├── .gitattributes
├── .gitignore
├── Directory.Build.props
├── SDL.SignalR.OracleMessageBus.sln
├── ServerRun.testsettings
├── Tests
└── SDL.SignalR.OracleMessageBus.Tests
│ ├── DbOperationTest.cs
│ ├── DbProviderFactoryAdapterTest.cs
│ ├── ObservableDbOperationTest.cs
│ ├── OracleDependencyManagerTest.cs
│ ├── OracleInstallerTest.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── ReceiverTest.cs
│ ├── SDL.SignalR.OracleMessageBus.Tests.csproj
│ └── SenderTest.cs
├── appveyor.yml
├── readme.md
├── samples
├── SDL.SignalR.OracleMessageBus.Client
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── SDL.SignalR.OracleMessageBus.Client.csproj
└── SDL.SignalR.OracleMessageBus.Server
│ ├── Program.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ └── SDL.SignalR.OracleMessageBus.Server.csproj
├── shared
└── Sdl.SignalR.OracleMessageBus.snk
├── src
└── SDL.SignalR.OracleMessageBus
│ ├── DbOperation
│ ├── DataRecordExtensions.cs
│ ├── DbCommandExtensions.cs
│ ├── DbConnectionExtension.cs
│ ├── DbOperation.cs
│ ├── DbOperationFactory.cs
│ ├── DbProviderFactoryAdapter.cs
│ ├── DbProviderFactoryExtensions.cs
│ ├── NotificationState.cs
│ ├── ObservableDbOperation.cs
│ ├── ObservableDbOperationFactory.cs
│ ├── OracleDependencyManager.cs
│ ├── OracleMessageBusException.cs
│ ├── SignalRDbNotificationEventArgs.cs
│ ├── SignalrDbDependency.cs
│ └── SignalrDbDependencyFactory.cs
│ ├── DependencyResolverExtensions.cs
│ ├── Helpers
│ └── TaskAsyncHelper.cs
│ ├── Interfaces
│ ├── IDataParameterExtensions.cs
│ ├── IDbBehavior.cs
│ ├── IDbOperation.cs
│ ├── IDbOperationFactory.cs
│ ├── IDbProviderFactory.cs
│ ├── IObservableDbOperation.cs
│ ├── IObservableDbOperationFactory.cs
│ ├── IOracleDependencyManager.cs
│ ├── IOracleReceiver.cs
│ ├── IOracleSender.cs
│ ├── ISignalRDbDependency.cs
│ ├── ISignalRDbNotificationEventArgs.cs
│ └── ISignalrDbDependencyFactory.cs
│ ├── MessageWrapper.cs
│ ├── OracleInstaller.cs
│ ├── OracleMessageBus.cs
│ ├── OraclePayload.cs
│ ├── OracleReceiver.cs
│ ├── OracleScaleoutConfiguration.cs
│ ├── OracleSender.cs
│ ├── OracleStream.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── SDL.SignalR.OracleMessageBus.csproj
│ └── install.sql
└── test.runsettings
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 |
24 | # Visual Studio 2015 cache/options directory
25 | .vs/
26 |
27 | # MSTest test Results
28 | [Tt]est[Rr]esult*/
29 | [Bb]uild[Ll]og.*
30 |
31 | # NUNIT
32 | *.VisualState.xml
33 | TestResult.xml
34 |
35 | # Build Results of an ATL Project
36 | [Dd]ebugPS/
37 | [Rr]eleasePS/
38 | dlldata.c
39 |
40 | # DNX
41 | project.lock.json
42 | artifacts/
43 |
44 | *_i.c
45 | *_p.c
46 | *_i.h
47 | *.ilk
48 | *.meta
49 | *.obj
50 | *.pch
51 | *.pdb
52 | *.pgc
53 | *.pgd
54 | *.rsp
55 | *.sbr
56 | *.tlb
57 | *.tli
58 | *.tlh
59 | *.tmp
60 | *.tmp_proj
61 | *.log
62 | *.vspscc
63 | *.vssscc
64 | .builds
65 | *.pidb
66 | *.svclog
67 | *.scc
68 |
69 | # Chutzpah Test files
70 | _Chutzpah*
71 |
72 | # Visual C++ cache files
73 | ipch/
74 | *.aps
75 | *.ncb
76 | *.opensdf
77 | *.sdf
78 | *.cachefile
79 |
80 | # Visual Studio profiler
81 | *.psess
82 | *.vsp
83 | *.vspx
84 |
85 | # TFS 2012 Local Workspace
86 | $tf/
87 |
88 | # Guidance Automation Toolkit
89 | *.gpState
90 |
91 | # ReSharper is a .NET coding add-in
92 | _ReSharper*/
93 | *.[Rr]e[Ss]harper
94 | *.DotSettings.user
95 |
96 | # JustCode is a .NET coding add-in
97 | .JustCode
98 |
99 | # TeamCity is a build add-in
100 | _TeamCity*
101 |
102 | # DotCover is a Code Coverage Tool
103 | *.dotCover
104 |
105 | # NCrunch
106 | _NCrunch_*
107 | .*crunch*.local.xml
108 |
109 | # MightyMoose
110 | *.mm.*
111 | AutoTest.Net/
112 |
113 | # Web workbench (sass)
114 | .sass-cache/
115 |
116 | # Installshield output folder
117 | [Ee]xpress/
118 |
119 | # DocProject is a documentation generator add-in
120 | DocProject/buildhelp/
121 | DocProject/Help/*.HxT
122 | DocProject/Help/*.HxC
123 | DocProject/Help/*.hhc
124 | DocProject/Help/*.hhk
125 | DocProject/Help/*.hhp
126 | DocProject/Help/Html2
127 | DocProject/Help/html
128 |
129 | # Click-Once directory
130 | publish/
131 |
132 | # Publish Web Output
133 | *.[Pp]ublish.xml
134 | *.azurePubxml
135 | ## TODO: Comment the next line if you want to checkin your
136 | ## web deploy settings but do note that will include unencrypted
137 | ## passwords
138 | #*.pubxml
139 |
140 | *.publishproj
141 |
142 | # NuGet Packages
143 | *.nupkg
144 | # The packages folder can be ignored because of Package Restore
145 | **/packages/*
146 | # except build/, which is used as an MSBuild target.
147 | !**/packages/build/
148 | # Uncomment if necessary however generally it will be regenerated when needed
149 | !**/packages/repositories.config
150 |
151 | # Windows Azure Build Output
152 | csx/
153 | *.build.csdef
154 |
155 | # Windows Store app package directory
156 | AppPackages/
157 |
158 | # Visual Studio cache files
159 | # files ending in .cache can be ignored
160 | *.[Cc]ache
161 | # but keep track of directories ending in .cache
162 | !*.[Cc]ache/
163 |
164 | # Others
165 | ClientBin/
166 | [Ss]tyle[Cc]op.*
167 | ~$*
168 | *~
169 | *.dbmdl
170 | *.dbproj.schemaview
171 | *.pfx
172 | *.publishsettings
173 | node_modules/
174 | orleans.codegen.cs
175 |
176 | # RIA/Silverlight projects
177 | Generated_Code/
178 |
179 | # Backup & report files from converting an old project file
180 | # to a newer Visual Studio version. Backup files are not needed,
181 | # because we have git ;-)
182 | _UpgradeReport_Files/
183 | Backup*/
184 | UpgradeLog*.XML
185 | UpgradeLog*.htm
186 |
187 | # SQL Server files
188 | *.mdf
189 | *.ldf
190 |
191 | # Business Intelligence projects
192 | *.rdl.data
193 | *.bim.layout
194 | *.bim_*.settings
195 |
196 | # Microsoft Fakes
197 | FakesAssemblies/
198 |
199 | # Node.js Tools for Visual Studio
200 | .ntvs_analysis.dat
201 |
202 | # Visual Studio 6 build log
203 | *.plg
204 |
205 | # Visual Studio 6 workspace options file
206 | *.opt
207 |
208 | # LightSwitch generated files
209 | GeneratedArtifacts/
210 | _Pvt_Extensions/
211 | ModelManifest.xml
212 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 2.0.4.0
4 | 2.0.4.0
5 | 2.0.4.0
6 | RWS Group for and on behalf of its affiliates and subsidiaries
7 | RWS Group for and on behalf of its affiliates and subsidiaries
8 | Copyright © 2015-2023 All Rights Reserved by the RWS Group for and on behalf of its affiliates and subsidiaries.
9 | http://dr0muzwhcp26z.cloudfront.net/static/corporate/SDL-logo-2014.png
10 | https://community.sdl.com/developers/tridion_developer/w/wiki/864.sdl-web-developer-software-and-distribution-agreement
11 | https://github.com/sdl/SignalR-OracleMessageBus
12 | Initial release of Oracle backplane which supports only single stream.
13 | SDL,SignalR,Backplane,MessageBus,Oracle
14 | true
15 |
16 |
--------------------------------------------------------------------------------
/SDL.SignalR.OracleMessageBus.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.26228.4
5 | MinimumVisualStudioVersion = 15.0.26228.4
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sdl.SignalR.OracleMessageBus", "src\Sdl.SignalR.OracleMessageBus\Sdl.SignalR.OracleMessageBus.csproj", "{286E7DED-376D-45A2-A1A6-E2DFC1431360}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DB8B4AA0-DB1F-4DFA-817F-582B2B88ED5A}"
9 | ProjectSection(SolutionItems) = preProject
10 | ServerRun.testsettings = ServerRun.testsettings
11 | test.runsettings = test.runsettings
12 | EndProjectSection
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sdl.SignalR.OracleMessageBus.Tests", "Tests\Sdl.SignalR.OracleMessageBus.Tests\Sdl.SignalR.OracleMessageBus.Tests.csproj", "{99F760DE-2496-4A81-9C13-8D9A27623671}"
15 | EndProject
16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{3112B7DE-0654-4030-B273-FB1026C49169}"
17 | EndProject
18 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{19276FA5-ECFE-4258-87C1-0D36C22EEFDF}"
19 | EndProject
20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sdl.SignalR.OracleMessageBus.Client", "samples\Sdl.SignalR.OracleMessageBus.Client\Sdl.SignalR.OracleMessageBus.Client.csproj", "{3F3C2EBB-E0D8-4CAF-9C1B-CAC5B0241C4C}"
21 | EndProject
22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sdl.SignalR.OracleMessageBus.Server", "samples\Sdl.SignalR.OracleMessageBus.Server\Sdl.SignalR.OracleMessageBus.Server.csproj", "{E4ADC697-E387-4FBB-919C-6C4B2BF0FC19}"
23 | EndProject
24 | Global
25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
26 | Debug|Any CPU = Debug|Any CPU
27 | Release|Any CPU = Release|Any CPU
28 | EndGlobalSection
29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
30 | {286E7DED-376D-45A2-A1A6-E2DFC1431360}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {286E7DED-376D-45A2-A1A6-E2DFC1431360}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {286E7DED-376D-45A2-A1A6-E2DFC1431360}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {286E7DED-376D-45A2-A1A6-E2DFC1431360}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {99F760DE-2496-4A81-9C13-8D9A27623671}.Debug|Any CPU.ActiveCfg = Release|Any CPU
35 | {99F760DE-2496-4A81-9C13-8D9A27623671}.Debug|Any CPU.Build.0 = Release|Any CPU
36 | {99F760DE-2496-4A81-9C13-8D9A27623671}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {99F760DE-2496-4A81-9C13-8D9A27623671}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {3F3C2EBB-E0D8-4CAF-9C1B-CAC5B0241C4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {3F3C2EBB-E0D8-4CAF-9C1B-CAC5B0241C4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {3F3C2EBB-E0D8-4CAF-9C1B-CAC5B0241C4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {3F3C2EBB-E0D8-4CAF-9C1B-CAC5B0241C4C}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {E4ADC697-E387-4FBB-919C-6C4B2BF0FC19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {E4ADC697-E387-4FBB-919C-6C4B2BF0FC19}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {E4ADC697-E387-4FBB-919C-6C4B2BF0FC19}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {E4ADC697-E387-4FBB-919C-6C4B2BF0FC19}.Release|Any CPU.Build.0 = Release|Any CPU
46 | EndGlobalSection
47 | GlobalSection(SolutionProperties) = preSolution
48 | HideSolutionNode = FALSE
49 | EndGlobalSection
50 | GlobalSection(NestedProjects) = preSolution
51 | {99F760DE-2496-4A81-9C13-8D9A27623671} = {3112B7DE-0654-4030-B273-FB1026C49169}
52 | {3F3C2EBB-E0D8-4CAF-9C1B-CAC5B0241C4C} = {19276FA5-ECFE-4258-87C1-0D36C22EEFDF}
53 | {E4ADC697-E387-4FBB-919C-6C4B2BF0FC19} = {19276FA5-ECFE-4258-87C1-0D36C22EEFDF}
54 | EndGlobalSection
55 | GlobalSection(ExtensibilityGlobals) = postSolution
56 | SolutionGuid = {CB7DDD79-421A-4002-8B50-9AF4C2200576}
57 | EndGlobalSection
58 | EndGlobal
59 |
--------------------------------------------------------------------------------
/ServerRun.testsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 | These are default test settings for a local test run.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Tests/SDL.SignalR.OracleMessageBus.Tests/DbOperationTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.Diagnostics;
4 | using FakeItEasy;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 |
7 | namespace Sdl.SignalR.OracleMessageBus.Tests
8 | {
9 | [TestClass]
10 | public class DbOperationTest
11 | {
12 | [TestMethod]
13 | public void OpenDispose_Basic_Success()
14 | {
15 | bool[] dbReaderReads = { true, true, false };
16 |
17 | var fakeDbReader = A.Fake();
18 | var fakeDbReaderReadCall = A.CallTo(() => fakeDbReader.Read());
19 | fakeDbReaderReadCall.ReturnsNextFromSequence(dbReaderReads);
20 |
21 | var fakeDbCommand = A.Fake();
22 | A.CallTo(() => fakeDbCommand.ExecuteNonQuery()).Returns(2);
23 | A.CallTo(() => fakeDbCommand.ExecuteScalar()).Returns(3);
24 | A.CallTo(() => fakeDbCommand.ExecuteReader()).Returns(fakeDbReader);
25 |
26 | var fakeConnection = A.Fake();
27 | var fakeConnectionDisposeCall = A.CallTo(() => fakeConnection.Dispose());
28 | var fakeConnectionOpenCall = A.CallTo(() => fakeConnection.Open());
29 | A.CallTo(() => fakeConnection.CreateCommand())
30 | .Returns(fakeDbCommand);
31 |
32 | IDbProviderFactory fakeDbProviderFactory = A.Fake();
33 | var createConnectionCall = A.CallTo(() => fakeDbProviderFactory.CreateConnection());
34 | createConnectionCall.Returns(fakeConnection);
35 |
36 | DbOperation dbOperation = new DbOperation(string.Empty, string.Empty, new TraceSource("ss"), fakeDbProviderFactory);
37 | dbOperation.ExecuteNonQuery();
38 | int readCount = dbOperation.ExecuteReader(A.Fake>());
39 |
40 | Assert.AreEqual(dbReaderReads.Length - 1, readCount);
41 |
42 | createConnectionCall.MustHaveHappened(Repeated.Exactly.Twice);
43 | fakeConnectionOpenCall.MustHaveHappened(Repeated.Exactly.Twice);
44 | fakeConnectionDisposeCall.MustHaveHappened(Repeated.Exactly.Twice);
45 | }
46 |
47 | [TestMethod]
48 | public void DbExceptionThrown()
49 | {
50 | string msg = Guid.NewGuid().ToString("N");
51 |
52 | var fakeDbCommand = A.Fake();
53 | A.CallTo(() => fakeDbCommand.ExecuteNonQuery()).Throws(new Exception(msg));
54 | A.CallTo(() => fakeDbCommand.ExecuteScalar()).Throws(new Exception(msg));
55 | A.CallTo(() => fakeDbCommand.ExecuteReader()).Throws(new Exception(msg));
56 |
57 | var fakeConnection = A.Fake();
58 | A.CallTo(() => fakeConnection.CreateCommand())
59 | .Returns(fakeDbCommand);
60 |
61 | IDbProviderFactory fakeDbProviderFactory = A.Fake();
62 | var createConnectionCall = A.CallTo(() => fakeDbProviderFactory.CreateConnection());
63 | createConnectionCall.Returns(fakeConnection);
64 |
65 | DbOperation dbOperation = new DbOperation(string.Empty, string.Empty, new TraceSource("ss"), fakeDbProviderFactory);
66 |
67 | try
68 | {
69 | dbOperation.ExecuteNonQuery();
70 | Assert.Fail("Expected exception was not thrown.");
71 | }
72 | catch (Exception e)
73 | {
74 | Assert.AreEqual(msg, e.Message);
75 | }
76 |
77 | try
78 | {
79 | dbOperation.ExecuteScalar();
80 | Assert.Fail("Expected exception was not thrown.");
81 | }
82 | catch (Exception e)
83 | {
84 | Assert.AreEqual(msg, e.Message);
85 | }
86 |
87 | try
88 | {
89 | dbOperation.ExecuteReader(A.Fake>());
90 | Assert.Fail("Expected exception was not thrown.");
91 | }
92 | catch (Exception e)
93 | {
94 | Assert.AreEqual(msg, e.Message);
95 | }
96 |
97 | try
98 | {
99 | dbOperation.ExecuteNonQueryAsync().Wait();
100 | Assert.Fail("Expected exception was not thrown.");
101 | }
102 | catch (Exception e)
103 | {
104 | Assert.AreEqual(msg, e.Message);
105 | }
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/Tests/SDL.SignalR.OracleMessageBus.Tests/DbProviderFactoryAdapterTest.cs:
--------------------------------------------------------------------------------
1 | using System.Data.Common;
2 | using FakeItEasy;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace Sdl.SignalR.OracleMessageBus.Tests
6 | {
7 | [TestClass]
8 | public class DbProviderFactoryAdapterTest
9 | {
10 | [TestMethod]
11 | public void DbProviderFactoryAdapterCreateConnection()
12 | {
13 | DbProviderFactory dbProviderFactory = A.Fake(c => c.Strict());
14 | DbConnection iDbConnection = A.Fake();
15 |
16 | DbProviderFactoryAdapter dbProviderFactoryAdapter = new DbProviderFactoryAdapter(dbProviderFactory);
17 | var fakeDbProviderFactoryAdapter = A.CallTo(() => dbProviderFactory.CreateConnection());
18 |
19 | fakeDbProviderFactoryAdapter.Returns(iDbConnection);
20 | dbProviderFactoryAdapter.CreateConnection();
21 |
22 | fakeDbProviderFactoryAdapter.MustHaveHappened(Repeated.Exactly.Once);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Tests/SDL.SignalR.OracleMessageBus.Tests/ObservableDbOperationTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Data;
4 | using System.Diagnostics;
5 | using System.Threading;
6 | using System.Threading.Tasks;
7 | using FakeItEasy;
8 | using Microsoft.VisualStudio.TestTools.UnitTesting;
9 | using Oracle.ManagedDataAccess.Client;
10 |
11 | namespace Sdl.SignalR.OracleMessageBus.Tests
12 | {
13 | [TestClass]
14 | public class ObservableDbOperationTest
15 | {
16 | private Tuple[] _updateLoopRetryDelays =
17 | {
18 | Tuple.Create(0, 3), // 0ms x 3
19 | Tuple.Create(10, 3), // 10ms x 3
20 | };
21 |
22 | [TestMethod]
23 | public void Basic_Success()
24 | {
25 | var fakeDbBehavior = A.Fake();
26 | A.CallTo(() => fakeDbBehavior.UpdateLoopRetryDelays).Returns(_updateLoopRetryDelays);
27 |
28 | ObservableDbOperation dbOperation = new ObservableDbOperation(string.Empty, string.Empty, new TraceSource("ss"),
29 | fakeDbBehavior,
30 | A.Fake(),
31 | A.Fake(),
32 | A.Fake(),
33 | true);
34 |
35 | dbOperation.ExecuteReaderWithUpdates(A.Fake>());
36 | }
37 |
38 | [TestMethod]
39 | public void CreateDependency_Success()
40 | {
41 | ObservableDbOperation dbOperation = new ObservableDbOperation(string.Empty, string.Empty, new TraceSource("ss"),
42 | null,
43 | A.Fake(),
44 | A.Fake(),
45 | A.Fake(),
46 | true);
47 |
48 | dbOperation.ExecuteReaderWithUpdates(A.Fake>());
49 | }
50 |
51 | [TestMethod]
52 | public void Pooling_Success()
53 | {
54 | var fakeDbReader = A.Fake();
55 | var fakeDbReaderReadCall = A.CallTo(() => fakeDbReader.Read());
56 | fakeDbReaderReadCall.ReturnsNextFromSequence(true, true, false);
57 |
58 | var fakeEmptyDbReader = A.Fake();
59 | A.CallTo(() => fakeEmptyDbReader.Read()).Returns(false);
60 |
61 | var fakeDbCommand = A.Fake();
62 | A.CallTo(() => fakeDbCommand.ExecuteReader()).ReturnsNextFromSequence(fakeDbReader, fakeEmptyDbReader);
63 |
64 | var fakeDbConnection = A.Fake();
65 | A.CallTo(() => fakeDbConnection.CreateCommand()).Returns(fakeDbCommand);
66 | var fakeDbConnectionDisposeCall = A.CallTo(() => fakeDbConnection.Dispose());
67 |
68 | var fakeDbProviderFactory = A.Fake();
69 | A.CallTo(() => fakeDbProviderFactory.CreateConnection()).Returns(fakeDbConnection);
70 |
71 | var fakeProcessRecordAction = A.Fake>();
72 | var fakeProcessRecordActionInvokeCall = A.CallTo(() => fakeProcessRecordAction.Invoke(null, null)).WithAnyArguments();
73 |
74 | var fakeDbBehavior = A.Fake();
75 | A.CallTo(() => fakeDbBehavior.UpdateLoopRetryDelays).Returns(_updateLoopRetryDelays);
76 |
77 | var fakeOracleDependencyManager = A.Fake();
78 | var fakeOracleDependencyManagerRegistryDepCall = A.CallTo(() => fakeOracleDependencyManager.RegisterDependency(null)).WithAnyArguments();
79 |
80 | var fakeOracleDependencyManagerRemoveRegistrationCall =
81 | A.CallTo(() => fakeOracleDependencyManager.RemoveRegistration(string.Empty)).WithAnyArguments();
82 |
83 | var fakeSignalrDbDependencyFactory = A.Fake();
84 | var fakeSignalrDbDependencyFactoryCreateDepCall = A.CallTo(() => fakeSignalrDbDependencyFactory.CreateDbDependency(null, false, 0, false)).WithAnyArguments();
85 |
86 | ObservableDbOperation dbOperation = new ObservableDbOperation(string.Empty, string.Empty, new TraceSource("ss"),
87 | fakeDbBehavior,
88 | fakeDbProviderFactory,
89 | fakeOracleDependencyManager,
90 | fakeSignalrDbDependencyFactory,
91 | false);
92 |
93 | using (var cts = new CancellationTokenSource())
94 | {
95 | Task.Run(() => dbOperation.ExecuteReaderWithUpdates(fakeProcessRecordAction),
96 | cts.Token);
97 | Thread.Sleep(1000);
98 | cts.Cancel();
99 | }
100 |
101 | Thread.Sleep(1000);
102 | fakeOracleDependencyManagerRegistryDepCall.MustNotHaveHappened();
103 | fakeSignalrDbDependencyFactoryCreateDepCall.MustNotHaveHappened();
104 | fakeProcessRecordActionInvokeCall.MustHaveHappened();
105 | fakeDbReaderReadCall.MustHaveHappened(Repeated.Exactly.Times(3));
106 | fakeDbConnectionDisposeCall.MustHaveHappened();
107 |
108 | dbOperation.Dispose();
109 |
110 | fakeOracleDependencyManagerRemoveRegistrationCall.MustHaveHappened(Repeated.Exactly.Once);
111 | }
112 |
113 | private class FakeSignalrDependency : ISignalRDbDependency
114 | {
115 | public void FireEvent()
116 | {
117 | if (OnChanged != null)
118 | {
119 | OnChanged(this, A.Fake());
120 | }
121 | }
122 |
123 | public void FireEvent(OracleNotificationType notificationType, OracleNotificationInfo notificationInfo)
124 | {
125 | var notificationArgsFake = A.Fake();
126 | A.CallTo(() => notificationArgsFake.NotificationType).Returns((int)notificationType);
127 | A.CallTo(() => notificationArgsFake.NotificationInfo).Returns((int)notificationInfo);
128 |
129 | if (OnChanged != null)
130 | {
131 | OnChanged(this, notificationArgsFake);
132 | }
133 | }
134 |
135 | public event EventHandler OnChanged;
136 | public void RemoveRegistration(OracleConnection conn)
137 | {
138 | }
139 | }
140 |
141 | [TestMethod]
142 | public void DependencyOnChange()
143 | {
144 | var fakeOracleDependencyManager = A.Fake();
145 | var fakeOracleDependencyManagerRegistryDepCall = A.CallTo(() => fakeOracleDependencyManager.RegisterDependency(null)).WithAnyArguments();
146 |
147 | var fakeSignalrDbDependencyFactory = A.Fake();
148 | var fakeSignalrDbDependencyFactoryCreateDepCall = A.CallTo(() => fakeSignalrDbDependencyFactory.CreateDbDependency(null, false, 0, false)).WithAnyArguments();
149 |
150 | var fakeSignalrDependency = new FakeSignalrDependency();
151 | fakeSignalrDbDependencyFactoryCreateDepCall.Returns(fakeSignalrDependency);
152 |
153 | ObservableDbOperation dbOperation = new ObservableDbOperation(string.Empty, string.Empty, new TraceSource("ss"),
154 | null,
155 | A.Fake(),
156 | fakeOracleDependencyManager,
157 | fakeSignalrDbDependencyFactory,
158 | true);
159 |
160 | dbOperation.ExecuteReaderWithUpdates(A.Fake>());
161 |
162 | int changedCounter = 0;
163 | dbOperation.Changed += () => { changedCounter++; };
164 | int faultCounter = 0;
165 | dbOperation.Faulted += ex => { faultCounter++; };
166 |
167 | fakeSignalrDependency.FireEvent();
168 |
169 | Assert.AreEqual(1, changedCounter);
170 | Assert.AreEqual(0, faultCounter);
171 | fakeOracleDependencyManagerRegistryDepCall.MustHaveHappened(Repeated.Exactly.Once);
172 | fakeSignalrDbDependencyFactoryCreateDepCall.MustHaveHappened(Repeated.Exactly.Once);
173 | }
174 |
175 | [TestMethod]
176 | public void DependencyFault()
177 | {
178 | var fakeOracleDependencyManager = A.Fake();
179 | var fakeOracleDependencyManagerRegistryDepCall = A.CallTo(() => fakeOracleDependencyManager.RegisterDependency(null)).WithAnyArguments();
180 |
181 | var fakeSignalrDbDependencyFactory = A.Fake();
182 | var fakeSignalrDbDependencyFactoryCreateDepCall = A.CallTo(() => fakeSignalrDbDependencyFactory.CreateDbDependency(null, false, 0, false)).WithAnyArguments();
183 |
184 | var fakeSignalrDependency = new FakeSignalrDependency();
185 | fakeSignalrDbDependencyFactoryCreateDepCall.Returns(fakeSignalrDependency);
186 |
187 | ObservableDbOperation dbOperation = new ObservableDbOperation(string.Empty, string.Empty, new TraceSource("ss"),
188 | null,
189 | A.Fake(),
190 | fakeOracleDependencyManager,
191 | fakeSignalrDbDependencyFactory,
192 | true);
193 |
194 | dbOperation.ExecuteReaderWithUpdates(A.Fake>());
195 |
196 | int faultCounter = 0;
197 | dbOperation.Faulted += ex => { if (ex != null) faultCounter++; };
198 |
199 | fakeSignalrDependency.FireEvent(OracleNotificationType.Change, OracleNotificationInfo.Error);
200 |
201 | Assert.AreEqual(1, faultCounter);
202 | fakeOracleDependencyManagerRegistryDepCall.MustHaveHappened(Repeated.Exactly.Once);
203 | fakeSignalrDbDependencyFactoryCreateDepCall.MustHaveHappened(Repeated.Exactly.Once);
204 | }
205 |
206 | [TestMethod]
207 | public void RemoveRegistrationDependency()
208 | {
209 | var fakeOracleDependencyManager = A.Fake();
210 | var fakeOracleDependencyManagerRegistryDepCall = A.CallTo(() => fakeOracleDependencyManager.RegisterDependency(null)).WithAnyArguments();
211 |
212 | var fakeOracleDependencyManagerRemoveRegistrationCall =
213 | A.CallTo(() => fakeOracleDependencyManager.RemoveRegistration(string.Empty)).WithAnyArguments();
214 |
215 | var fakeSignalrDbDependencyFactory = A.Fake();
216 | var fakeSignalrDbDependencyFactoryCreateDepCall = A.CallTo(() => fakeSignalrDbDependencyFactory.CreateDbDependency(null, false, 0, false)).WithAnyArguments();
217 |
218 | var fakeSignalrDependency = new FakeSignalrDependency();
219 | fakeSignalrDbDependencyFactoryCreateDepCall.Returns(fakeSignalrDependency);
220 |
221 | ObservableDbOperation dbOperation = new ObservableDbOperation(string.Empty, string.Empty, new TraceSource("ss"),
222 | null,
223 | A.Fake(),
224 | fakeOracleDependencyManager,
225 | fakeSignalrDbDependencyFactory,
226 | true);
227 |
228 | dbOperation.ExecuteReaderWithUpdates(A.Fake>());
229 |
230 | fakeSignalrDependency.FireEvent(OracleNotificationType.Subscribe, OracleNotificationInfo.Error);
231 |
232 | fakeOracleDependencyManagerRegistryDepCall.MustHaveHappened(Repeated.Exactly.Once);
233 | fakeSignalrDbDependencyFactoryCreateDepCall.MustHaveHappened(Repeated.Exactly.Once);
234 | fakeOracleDependencyManagerRemoveRegistrationCall.MustHaveHappened(Repeated.Exactly.Once);
235 | }
236 |
237 | [TestMethod]
238 | public void ExecuteReaderWithUpdates_Fail()
239 | {
240 | var fakeOracleDependencyManager = A.Fake();
241 | var fakeSignalrDbDependencyFactory = A.Fake();
242 |
243 | ObservableDbOperation dbOperation = new ObservableDbOperation(string.Empty, string.Empty,
244 | new TraceSource("ss"),
245 | null,
246 | A.Fake(),
247 | fakeOracleDependencyManager,
248 | fakeSignalrDbDependencyFactory,
249 | true);
250 |
251 | dbOperation.Queried += () => { throw new Exception(); };
252 | int counter = 0;
253 | dbOperation.Faulted += (ex) => { counter++; };
254 |
255 | using (var cts = new CancellationTokenSource())
256 | {
257 | Task.Run(() => dbOperation.ExecuteReaderWithUpdates(A.Fake>()),
258 | cts.Token);
259 | Thread.Sleep(1000);
260 | dbOperation.Dispose();
261 | cts.Cancel();
262 | }
263 |
264 | Assert.IsTrue(counter > 0);
265 | }
266 |
267 | [TestMethod]
268 | public void UpdateDependency()
269 | {
270 | var fakeOracleDependencyManager = A.Fake();
271 | var fakeOracleDependencyManagerRegistryDepCall =
272 | A.CallTo(() => fakeOracleDependencyManager.RegisterDependency(null)).WithAnyArguments();
273 |
274 | var fakeSignalrDbDependencyFactory = A.Fake();
275 | var fakeSignalrDbDependencyFactoryCreateDepCall =
276 | A.CallTo(() => fakeSignalrDbDependencyFactory.CreateDbDependency(null, false, 0, false))
277 | .WithAnyArguments();
278 |
279 | var fakeSignalrDependency = new FakeSignalrDependency();
280 | fakeSignalrDbDependencyFactoryCreateDepCall.Returns(fakeSignalrDependency);
281 |
282 | TraceSource trace = new TraceSource("Fault");
283 | FakeTraceListener fakeListener = new FakeTraceListener();
284 | trace.Listeners.Add(fakeListener);
285 | trace.Switch.Level = SourceLevels.All;
286 |
287 | ObservableDbOperation dbOperation = new ObservableDbOperation(string.Empty, string.Empty, trace,
288 | null,
289 | A.Fake(),
290 | fakeOracleDependencyManager,
291 | fakeSignalrDbDependencyFactory,
292 | true);
293 |
294 | dbOperation.ExecuteReaderWithUpdates(A.Fake>());
295 | fakeSignalrDependency.FireEvent(OracleNotificationType.Change, OracleNotificationInfo.Update);
296 | int counter = 0;
297 | dbOperation.Faulted += (ex) => { counter++; };
298 | Assert.AreEqual(0, counter);
299 | Assert.IsTrue(fakeListener.Traces.Exists(item => item.StartsWith("Oracle notification details:")));
300 |
301 | fakeSignalrDependency.FireEvent(OracleNotificationType.Change, OracleNotificationInfo.End);
302 | Assert.AreEqual(0, counter);
303 | Assert.IsTrue(fakeListener.Traces.Exists(item => item.StartsWith("Oracle notification timed out")));
304 |
305 | fakeSignalrDependency.FireEvent(OracleNotificationType.Change, OracleNotificationInfo.Drop);
306 | Assert.AreEqual(1, counter);
307 | Assert.IsTrue(fakeListener.Traces.Exists(item => item.StartsWith("Unexpected Oracle notification details:")));
308 |
309 | fakeOracleDependencyManagerRegistryDepCall.MustHaveHappened(Repeated.AtLeast.Once);
310 | fakeSignalrDbDependencyFactoryCreateDepCall.MustHaveHappened(Repeated.AtLeast.Once);
311 |
312 | }
313 |
314 | [TestMethod]
315 | public void CatchQLreceiveloop()
316 | {
317 |
318 | // Configure IDbBehaviour to issue OracleException during AddOracleDependency
319 | var fakeDbBehavior = A.Fake();
320 | A.CallTo(() => fakeDbBehavior.AddOracleDependency(null, null))
321 | .WithAnyArguments()
322 | .Throws(new Exception("Hello, World!") );
323 | A.CallTo(() => fakeDbBehavior.UpdateLoopRetryDelays).Returns(_updateLoopRetryDelays);
324 |
325 | // Define trace source with our listener to collect trace messages
326 | var traceSource = new TraceSource("ss");
327 | FakeTraceListener fakeListener = new FakeTraceListener();
328 | traceSource.Listeners.Add(fakeListener);
329 | traceSource.Switch.Level = SourceLevels.All;
330 |
331 | var fakeOracleDependencyManager = A.Fake();
332 | var fakeSignalrDbDependencyFactory = A.Fake();
333 | var fakeDbProviderFactory = A.Fake();
334 |
335 | ObservableDbOperation dbOperation = new ObservableDbOperation(string.Empty, string.Empty, traceSource,
336 | fakeDbBehavior,
337 | fakeDbProviderFactory,
338 | fakeOracleDependencyManager,
339 | fakeSignalrDbDependencyFactory,
340 | useOracleDependency: true);
341 |
342 | Action