SEBWIN-301: Added unit tests for basic service functionality.
This commit is contained in:
		
							parent
							
								
									3589b92b9d
								
							
						
					
					
						commit
						ac28eec94a
					
				
					 10 changed files with 520 additions and 28 deletions
				
			
		|  | @ -0,0 +1,140 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using System; | ||||||
|  | using System.Threading; | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Moq; | ||||||
|  | using SafeExamBrowser.Contracts.Communication; | ||||||
|  | using SafeExamBrowser.Contracts.Communication.Data; | ||||||
|  | using SafeExamBrowser.Contracts.Communication.Events; | ||||||
|  | using SafeExamBrowser.Contracts.Communication.Hosts; | ||||||
|  | using SafeExamBrowser.Contracts.Configuration; | ||||||
|  | using SafeExamBrowser.Contracts.Logging; | ||||||
|  | using SafeExamBrowser.Service.Communication; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Service.UnitTests.Communication | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class ServiceHostTests | ||||||
|  | 	{ | ||||||
|  | 		private Mock<IHostObject> hostObject; | ||||||
|  | 		private Mock<IHostObjectFactory> hostObjectFactory; | ||||||
|  | 		private Mock<ILogger> logger; | ||||||
|  | 		private ServiceHost sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			hostObject = new Mock<IHostObject>(); | ||||||
|  | 			hostObjectFactory = new Mock<IHostObjectFactory>(); | ||||||
|  | 			logger = new Mock<ILogger>(); | ||||||
|  | 
 | ||||||
|  | 			hostObjectFactory.Setup(f => f.CreateObject(It.IsAny<string>(), It.IsAny<ICommunication>())).Returns(hostObject.Object); | ||||||
|  | 
 | ||||||
|  | 			sut = new ServiceHost("net:pipe://some/address", hostObjectFactory.Object, logger.Object, 0); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Connect_MustAllowFirstConnnectionAndDenyFurtherRequests() | ||||||
|  | 		{ | ||||||
|  | 			var response = sut.Connect(); | ||||||
|  | 			var response2 = sut.Connect(); | ||||||
|  | 			var response3 = sut.Connect(); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsTrue(response.ConnectionEstablished); | ||||||
|  | 			Assert.IsFalse(sut.AllowConnection); | ||||||
|  | 			Assert.IsFalse(response2.ConnectionEstablished); | ||||||
|  | 			Assert.IsFalse(response3.ConnectionEstablished); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Disconnect_MustDisconnectAndThenAllowNewConnection() | ||||||
|  | 		{ | ||||||
|  | 			var connect = sut.Connect(); | ||||||
|  | 			var disconnect = sut.Disconnect(new DisconnectionMessage { CommunicationToken = connect.CommunicationToken.Value, Interlocutor = Interlocutor.Runtime }); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsTrue(sut.AllowConnection); | ||||||
|  | 			Assert.IsTrue(disconnect.ConnectionTerminated); | ||||||
|  | 
 | ||||||
|  | 			var connect2 = sut.Connect(); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(sut.AllowConnection); | ||||||
|  | 			Assert.IsTrue(connect2.ConnectionEstablished); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Send_MustHandleSessionStartRequest() | ||||||
|  | 		{ | ||||||
|  | 			var args = default(SessionStartEventArgs); | ||||||
|  | 			var sync = new AutoResetEvent(false); | ||||||
|  | 			var configuration = new ServiceConfiguration { SessionId = Guid.NewGuid() }; | ||||||
|  | 			var sessionStartRequested = false; | ||||||
|  | 
 | ||||||
|  | 			sut.SessionStartRequested += (a) => { args = a; sessionStartRequested = true; sync.Set(); }; | ||||||
|  | 
 | ||||||
|  | 			var token = sut.Connect().CommunicationToken.Value; | ||||||
|  | 			var message = new SessionStartMessage(configuration) { CommunicationToken = token }; | ||||||
|  | 			var response = sut.Send(message); | ||||||
|  | 
 | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsTrue(sessionStartRequested); | ||||||
|  | 			Assert.IsNotNull(args); | ||||||
|  | 			Assert.IsNotNull(response); | ||||||
|  | 			Assert.IsInstanceOfType(response, typeof(SimpleResponse)); | ||||||
|  | 			Assert.AreEqual(configuration.SessionId, args.Configuration.SessionId); | ||||||
|  | 			Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Send_MustHandleSessionStopRequest() | ||||||
|  | 		{ | ||||||
|  | 			var args = default(SessionStopEventArgs); | ||||||
|  | 			var sync = new AutoResetEvent(false); | ||||||
|  | 			var sessionId = Guid.NewGuid(); | ||||||
|  | 			var sessionStopRequested = false; | ||||||
|  | 
 | ||||||
|  | 			sut.SessionStopRequested += (a) => { args = a; sessionStopRequested = true; sync.Set(); }; | ||||||
|  | 
 | ||||||
|  | 			var token = sut.Connect().CommunicationToken.Value; | ||||||
|  | 			var message = new SessionStopMessage(sessionId) { CommunicationToken = token }; | ||||||
|  | 			var response = sut.Send(message); | ||||||
|  | 
 | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsTrue(sessionStopRequested); | ||||||
|  | 			Assert.IsNotNull(args); | ||||||
|  | 			Assert.IsNotNull(response); | ||||||
|  | 			Assert.IsInstanceOfType(response, typeof(SimpleResponse)); | ||||||
|  | 			Assert.AreEqual(sessionId, args.SessionId); | ||||||
|  | 			Assert.AreEqual(SimpleResponsePurport.Acknowledged, (response as SimpleResponse)?.Purport); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Send_MustReturnUnknownMessageAsDefault() | ||||||
|  | 		{ | ||||||
|  | 			var token = sut.Connect().CommunicationToken.Value; | ||||||
|  | 			var message = new TestMessage { CommunicationToken = token } as Message; | ||||||
|  | 			var response = sut.Send(message); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsNotNull(response); | ||||||
|  | 			Assert.IsInstanceOfType(response, typeof(SimpleResponse)); | ||||||
|  | 			Assert.AreEqual(SimpleResponsePurport.UnknownMessage, (response as SimpleResponse)?.Purport); | ||||||
|  | 
 | ||||||
|  | 			message = new SimpleMessage(default(SimpleMessagePurport)) { CommunicationToken = token }; | ||||||
|  | 			response = sut.Send(message); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsNotNull(response); | ||||||
|  | 			Assert.IsInstanceOfType(response, typeof(SimpleResponse)); | ||||||
|  | 			Assert.AreEqual(SimpleResponsePurport.UnknownMessage, (response as SimpleResponse)?.Purport); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		private class TestMessage : Message { }; | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								SafeExamBrowser.Service.UnitTests/Operations/EventStub.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								SafeExamBrowser.Service.UnitTests/Operations/EventStub.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using System.Threading; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Service.UnitTests.Operations | ||||||
|  | { | ||||||
|  | 	internal class EventStub : EventWaitHandle | ||||||
|  | 	{ | ||||||
|  | 		public bool IsClosed { get; set; } | ||||||
|  | 
 | ||||||
|  | 		public EventStub() : base(false, EventResetMode.AutoReset) | ||||||
|  | 		{ | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		public override void Close() | ||||||
|  | 		{ | ||||||
|  | 			IsClosed = true; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,68 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using System.Threading; | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Moq; | ||||||
|  | using SafeExamBrowser.Contracts.Core.OperationModel; | ||||||
|  | using SafeExamBrowser.Contracts.Logging; | ||||||
|  | using SafeExamBrowser.Service.Operations; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Service.UnitTests.Operations | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class ServiceEventCleanupOperationTests | ||||||
|  | 	{ | ||||||
|  | 		private Mock<ILogger> logger; | ||||||
|  | 		private SessionContext sessionContext; | ||||||
|  | 		private ServiceEventCleanupOperation sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			logger = new Mock<ILogger>(); | ||||||
|  | 			sessionContext = new SessionContext(); | ||||||
|  | 
 | ||||||
|  | 			sut = new ServiceEventCleanupOperation(logger.Object, sessionContext); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Perform_MustDoNothing() | ||||||
|  | 		{ | ||||||
|  | 			var serviceEvent = new EventWaitHandle(false, EventResetMode.AutoReset); | ||||||
|  | 
 | ||||||
|  | 			sessionContext.ServiceEvent = serviceEvent; | ||||||
|  | 
 | ||||||
|  | 			var result = sut.Perform(); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 			Assert.AreSame(serviceEvent, sessionContext.ServiceEvent); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Revert_MustCloseEvent() | ||||||
|  | 		{ | ||||||
|  | 			var serviceEvent = new EventStub(); | ||||||
|  | 
 | ||||||
|  | 			sessionContext.ServiceEvent = serviceEvent; | ||||||
|  | 
 | ||||||
|  | 			var result = sut.Revert(); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 			Assert.IsTrue(serviceEvent.IsClosed); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Revert_MustNotFailIfEventNull() | ||||||
|  | 		{ | ||||||
|  | 			var result = sut.Revert(); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,58 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using System.Threading; | ||||||
|  | using System.Threading.Tasks; | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Moq; | ||||||
|  | using SafeExamBrowser.Contracts.Core.OperationModel; | ||||||
|  | using SafeExamBrowser.Contracts.Logging; | ||||||
|  | using SafeExamBrowser.Service.Operations; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Service.UnitTests.Operations | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class SessionActivationOperationTests | ||||||
|  | 	{ | ||||||
|  | 		private Mock<ILogger> logger; | ||||||
|  | 		private SessionContext sessionContext; | ||||||
|  | 		private SessionActivationOperation sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			logger = new Mock<ILogger>(); | ||||||
|  | 			sessionContext = new SessionContext(); | ||||||
|  | 
 | ||||||
|  | 			sut = new SessionActivationOperation(logger.Object, sessionContext); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Perform_MustSetServiceEvent() | ||||||
|  | 		{ | ||||||
|  | 			sessionContext.ServiceEvent = new EventWaitHandle(false, EventResetMode.AutoReset); | ||||||
|  | 
 | ||||||
|  | 			var wasSet = false; | ||||||
|  | 			var task = Task.Run(() => wasSet = sessionContext.ServiceEvent.WaitOne(1000)); | ||||||
|  | 			var result = sut.Perform(); | ||||||
|  | 
 | ||||||
|  | 			task.Wait(); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 			Assert.IsTrue(wasSet); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Revert_MustDoNothing() | ||||||
|  | 		{ | ||||||
|  | 			var result = sut.Revert(); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,108 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using System; | ||||||
|  | using System.Threading; | ||||||
|  | using System.Threading.Tasks; | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Moq; | ||||||
|  | using SafeExamBrowser.Contracts.Communication.Hosts; | ||||||
|  | using SafeExamBrowser.Contracts.Configuration; | ||||||
|  | using SafeExamBrowser.Contracts.Core.OperationModel; | ||||||
|  | using SafeExamBrowser.Contracts.Logging; | ||||||
|  | using SafeExamBrowser.Service.Operations; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Service.UnitTests.Operations | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class SessionInitializationOperationTests | ||||||
|  | 	{ | ||||||
|  | 		private Mock<ILogger> logger; | ||||||
|  | 		private Mock<Func<string, ILogObserver>> logWriterFactory; | ||||||
|  | 		private Mock<IServiceHost> serviceHost; | ||||||
|  | 		private Mock<Func<string, EventWaitHandle>> serviceEventFactory; | ||||||
|  | 		private SessionContext sessionContext; | ||||||
|  | 		private SessionInitializationOperation sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			logger = new Mock<ILogger>(); | ||||||
|  | 			logWriterFactory = new Mock<Func<string, ILogObserver>>(); | ||||||
|  | 			serviceHost = new Mock<IServiceHost>(); | ||||||
|  | 			serviceEventFactory = new Mock<Func<string, EventWaitHandle>>(); | ||||||
|  | 			sessionContext = new SessionContext(); | ||||||
|  | 
 | ||||||
|  | 			logWriterFactory.Setup(f => f.Invoke(It.IsAny<string>())).Returns(new Mock<ILogObserver>().Object); | ||||||
|  | 			serviceEventFactory.Setup(f => f.Invoke(It.IsAny<string>())).Returns(new EventStub()); | ||||||
|  | 			sessionContext.Configuration = new ServiceConfiguration | ||||||
|  | 			{ | ||||||
|  | 				AppConfig = new AppConfig { ServiceEventName = $"{nameof(SafeExamBrowser)}-{nameof(SessionInitializationOperationTests)}" } | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			sut = new SessionInitializationOperation(logger.Object, logWriterFactory.Object, serviceEventFactory.Object, serviceHost.Object, sessionContext); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Perform_MustDisableNewConnections() | ||||||
|  | 		{ | ||||||
|  | 			var result = sut.Perform(); | ||||||
|  | 
 | ||||||
|  | 			serviceHost.VerifySet(h => h.AllowConnection = false, Times.Once); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Perform_MustInitializeServiceEvent() | ||||||
|  | 		{ | ||||||
|  | 			var result = sut.Perform(); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 			Assert.IsInstanceOfType(sessionContext.ServiceEvent, typeof(EventWaitHandle)); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Revert_MustSetServiceEvent() | ||||||
|  | 		{ | ||||||
|  | 			sessionContext.ServiceEvent = new EventWaitHandle(false, EventResetMode.AutoReset); | ||||||
|  | 
 | ||||||
|  | 			var wasSet = false; | ||||||
|  | 			var task = Task.Run(() => wasSet = sessionContext.ServiceEvent.WaitOne(1000)); | ||||||
|  | 			var result = sut.Revert(); | ||||||
|  | 
 | ||||||
|  | 			task.Wait(); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 			Assert.IsTrue(wasSet); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Revert_MustDeleteConfiguration() | ||||||
|  | 		{ | ||||||
|  | 			sessionContext.Configuration = new ServiceConfiguration(); | ||||||
|  | 			sessionContext.ServiceEvent = new EventStub(); | ||||||
|  | 
 | ||||||
|  | 			var result = sut.Revert(); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 			Assert.IsNull(sessionContext.Configuration); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Revert_MustEnableNewConnections() | ||||||
|  | 		{ | ||||||
|  | 			sessionContext.ServiceEvent = new EventStub(); | ||||||
|  | 
 | ||||||
|  | 			var result = sut.Revert(); | ||||||
|  | 
 | ||||||
|  | 			serviceHost.VerifySet(h => h.AllowConnection = true, Times.Once); | ||||||
|  | 			Assert.AreEqual(OperationResult.Success, result); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -80,6 +80,11 @@ | ||||||
|     </Reference> |     </Reference> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |     <Compile Include="Communication\ServiceHostTests.cs" /> | ||||||
|  |     <Compile Include="Operations\EventStub.cs" /> | ||||||
|  |     <Compile Include="Operations\ServiceEventCleanupOperationTests.cs" /> | ||||||
|  |     <Compile Include="Operations\SessionActivationOperationTests.cs" /> | ||||||
|  |     <Compile Include="Operations\SessionInitializationOperationTests.cs" /> | ||||||
|     <Compile Include="Properties\AssemblyInfo.cs" /> |     <Compile Include="Properties\AssemblyInfo.cs" /> | ||||||
|     <Compile Include="ServiceControllerTests.cs" /> |     <Compile Include="ServiceControllerTests.cs" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|  | @ -87,6 +92,10 @@ | ||||||
|     <None Include="packages.config" /> |     <None Include="packages.config" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  |     <ProjectReference Include="..\SafeExamBrowser.Communication\SafeExamBrowser.Communication.csproj"> | ||||||
|  |       <Project>{c9416a62-0623-4d38-96aa-92516b32f02f}</Project> | ||||||
|  |       <Name>SafeExamBrowser.Communication</Name> | ||||||
|  |     </ProjectReference> | ||||||
|     <ProjectReference Include="..\SafeExamBrowser.Contracts\SafeExamBrowser.Contracts.csproj"> |     <ProjectReference Include="..\SafeExamBrowser.Contracts\SafeExamBrowser.Contracts.csproj"> | ||||||
|       <Project>{47da5933-bef8-4729-94e6-abde2db12262}</Project> |       <Project>{47da5933-bef8-4729-94e6-abde2db12262}</Project> | ||||||
|       <Name>SafeExamBrowser.Contracts</Name> |       <Name>SafeExamBrowser.Contracts</Name> | ||||||
|  | @ -96,10 +105,7 @@ | ||||||
|       <Name>SafeExamBrowser.Service</Name> |       <Name>SafeExamBrowser.Service</Name> | ||||||
|     </ProjectReference> |     </ProjectReference> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup /> | ||||||
|     <Folder Include="Communication\" /> |  | ||||||
|     <Folder Include="Operations\" /> |  | ||||||
|   </ItemGroup> |  | ||||||
|   <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> |   <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> | ||||||
|   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||||||
|   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> |   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> | ||||||
|  |  | ||||||
|  | @ -6,8 +6,10 @@ | ||||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | using System; | ||||||
| using Microsoft.VisualStudio.TestTools.UnitTesting; | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
| using Moq; | using Moq; | ||||||
|  | using SafeExamBrowser.Contracts.Communication.Events; | ||||||
| using SafeExamBrowser.Contracts.Communication.Hosts; | using SafeExamBrowser.Contracts.Communication.Hosts; | ||||||
| using SafeExamBrowser.Contracts.Configuration; | using SafeExamBrowser.Contracts.Configuration; | ||||||
| using SafeExamBrowser.Contracts.Core.OperationModel; | using SafeExamBrowser.Contracts.Core.OperationModel; | ||||||
|  | @ -21,7 +23,7 @@ namespace SafeExamBrowser.Service.UnitTests | ||||||
| 		private Mock<ILogger> logger; | 		private Mock<ILogger> logger; | ||||||
| 		private Mock<IOperationSequence> bootstrapSequence; | 		private Mock<IOperationSequence> bootstrapSequence; | ||||||
| 		private SessionContext sessionContext; | 		private SessionContext sessionContext; | ||||||
| 		private Mock<IRepeatableOperationSequence> sessionSequence; | 		private Mock<IOperationSequence> sessionSequence; | ||||||
| 		private Mock<IServiceHost> serviceHost; | 		private Mock<IServiceHost> serviceHost; | ||||||
| 		private ServiceController sut; | 		private ServiceController sut; | ||||||
| 
 | 
 | ||||||
|  | @ -31,12 +33,86 @@ namespace SafeExamBrowser.Service.UnitTests | ||||||
| 			logger = new Mock<ILogger>(); | 			logger = new Mock<ILogger>(); | ||||||
| 			bootstrapSequence = new Mock<IOperationSequence>(); | 			bootstrapSequence = new Mock<IOperationSequence>(); | ||||||
| 			sessionContext = new SessionContext(); | 			sessionContext = new SessionContext(); | ||||||
| 			sessionSequence = new Mock<IRepeatableOperationSequence>(); | 			sessionSequence = new Mock<IOperationSequence>(); | ||||||
| 			serviceHost = new Mock<IServiceHost>(); | 			serviceHost = new Mock<IServiceHost>(); | ||||||
| 
 | 
 | ||||||
| 			sut = new ServiceController(logger.Object, bootstrapSequence.Object, sessionSequence.Object, serviceHost.Object, sessionContext); | 			sut = new ServiceController(logger.Object, bootstrapSequence.Object, sessionSequence.Object, serviceHost.Object, sessionContext); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Communication_MustStartNewSessionUponRequest() | ||||||
|  | 		{ | ||||||
|  | 			var args = new SessionStartEventArgs { Configuration = new ServiceConfiguration { SessionId = Guid.NewGuid() } }; | ||||||
|  | 
 | ||||||
|  | 			bootstrapSequence.Setup(b => b.TryPerform()).Returns(OperationResult.Success); | ||||||
|  | 			sessionSequence.Setup(b => b.TryPerform()).Returns(OperationResult.Success); | ||||||
|  | 
 | ||||||
|  | 			sut.TryStart(); | ||||||
|  | 			serviceHost.Raise(h => h.SessionStartRequested += null, args); | ||||||
|  | 
 | ||||||
|  | 			sessionSequence.Verify(s => s.TryPerform(), Times.Once); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsNotNull(sessionContext.Configuration); | ||||||
|  | 			Assert.AreEqual(args.Configuration.SessionId, sessionContext.Configuration.SessionId); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Communication_MustNotAllowNewSessionDuringActiveSession() | ||||||
|  | 		{ | ||||||
|  | 			var args = new SessionStartEventArgs { Configuration = new ServiceConfiguration { SessionId = Guid.NewGuid() } }; | ||||||
|  | 
 | ||||||
|  | 			bootstrapSequence.Setup(b => b.TryPerform()).Returns(OperationResult.Success); | ||||||
|  | 			sessionContext.Configuration = new ServiceConfiguration { SessionId = Guid.NewGuid() }; | ||||||
|  | 
 | ||||||
|  | 			sut.TryStart(); | ||||||
|  | 			serviceHost.Raise(h => h.SessionStartRequested += null, args); | ||||||
|  | 
 | ||||||
|  | 			sessionSequence.Verify(s => s.TryPerform(), Times.Never); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreNotEqual(args.Configuration.SessionId, sessionContext.Configuration.SessionId); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Communication_MustStopActiveSessionUponRequest() | ||||||
|  | 		{ | ||||||
|  | 			var args = new SessionStopEventArgs { SessionId = Guid.NewGuid() }; | ||||||
|  | 
 | ||||||
|  | 			bootstrapSequence.Setup(b => b.TryPerform()).Returns(OperationResult.Success); | ||||||
|  | 			sessionContext.Configuration = new ServiceConfiguration { SessionId = args.SessionId }; | ||||||
|  | 
 | ||||||
|  | 			sut.TryStart(); | ||||||
|  | 			serviceHost.Raise(h => h.SessionStopRequested += null, args); | ||||||
|  | 
 | ||||||
|  | 			sessionSequence.Verify(s => s.TryRevert(), Times.Once); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Communication_MustNotStopSessionWithWrongId() | ||||||
|  | 		{ | ||||||
|  | 			var args = new SessionStopEventArgs { SessionId = Guid.NewGuid() }; | ||||||
|  | 
 | ||||||
|  | 			bootstrapSequence.Setup(b => b.TryPerform()).Returns(OperationResult.Success); | ||||||
|  | 			sessionContext.Configuration = new ServiceConfiguration { SessionId = Guid.NewGuid() }; | ||||||
|  | 
 | ||||||
|  | 			sut.TryStart(); | ||||||
|  | 			serviceHost.Raise(h => h.SessionStopRequested += null, args); | ||||||
|  | 
 | ||||||
|  | 			sessionSequence.Verify(s => s.TryRevert(), Times.Never); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void Communication_MustNotStopSessionWithoutActiveSession() | ||||||
|  | 		{ | ||||||
|  | 			var args = new SessionStopEventArgs { SessionId = Guid.NewGuid() }; | ||||||
|  | 
 | ||||||
|  | 			bootstrapSequence.Setup(b => b.TryPerform()).Returns(OperationResult.Success); | ||||||
|  | 
 | ||||||
|  | 			sut.TryStart(); | ||||||
|  | 			serviceHost.Raise(h => h.SessionStopRequested += null, args); | ||||||
|  | 
 | ||||||
|  | 			sessionSequence.Verify(s => s.TryRevert(), Times.Never); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		[TestMethod] | 		[TestMethod] | ||||||
| 		public void Start_MustOnlyPerformBootstrapSequence() | 		public void Start_MustOnlyPerformBootstrapSequence() | ||||||
| 		{ | 		{ | ||||||
|  | @ -49,7 +125,6 @@ namespace SafeExamBrowser.Service.UnitTests | ||||||
| 			bootstrapSequence.Verify(b => b.TryPerform(), Times.Once); | 			bootstrapSequence.Verify(b => b.TryPerform(), Times.Once); | ||||||
| 			bootstrapSequence.Verify(b => b.TryRevert(), Times.Never); | 			bootstrapSequence.Verify(b => b.TryRevert(), Times.Never); | ||||||
| 			sessionSequence.Verify(b => b.TryPerform(), Times.Never); | 			sessionSequence.Verify(b => b.TryPerform(), Times.Never); | ||||||
| 			sessionSequence.Verify(b => b.TryRepeat(), Times.Never); |  | ||||||
| 			sessionSequence.Verify(b => b.TryRevert(), Times.Never); | 			sessionSequence.Verify(b => b.TryRevert(), Times.Never); | ||||||
| 
 | 
 | ||||||
| 			Assert.IsTrue(success); | 			Assert.IsTrue(success); | ||||||
|  | @ -76,7 +151,6 @@ namespace SafeExamBrowser.Service.UnitTests | ||||||
| 			bootstrapSequence.Verify(b => b.TryPerform(), Times.Never); | 			bootstrapSequence.Verify(b => b.TryPerform(), Times.Never); | ||||||
| 			bootstrapSequence.Verify(b => b.TryRevert(), Times.Once); | 			bootstrapSequence.Verify(b => b.TryRevert(), Times.Once); | ||||||
| 			sessionSequence.Verify(b => b.TryPerform(), Times.Never); | 			sessionSequence.Verify(b => b.TryPerform(), Times.Never); | ||||||
| 			sessionSequence.Verify(b => b.TryRepeat(), Times.Never); |  | ||||||
| 			sessionSequence.Verify(b => b.TryRevert(), Times.Once); | 			sessionSequence.Verify(b => b.TryRevert(), Times.Once); | ||||||
| 
 | 
 | ||||||
| 			Assert.AreEqual(1, session); | 			Assert.AreEqual(1, session); | ||||||
|  | @ -104,7 +178,6 @@ namespace SafeExamBrowser.Service.UnitTests | ||||||
| 			bootstrapSequence.Verify(b => b.TryPerform(), Times.Never); | 			bootstrapSequence.Verify(b => b.TryPerform(), Times.Never); | ||||||
| 			bootstrapSequence.Verify(b => b.TryRevert(), Times.Once); | 			bootstrapSequence.Verify(b => b.TryRevert(), Times.Once); | ||||||
| 			sessionSequence.Verify(b => b.TryPerform(), Times.Never); | 			sessionSequence.Verify(b => b.TryPerform(), Times.Never); | ||||||
| 			sessionSequence.Verify(b => b.TryRepeat(), Times.Never); |  | ||||||
| 			sessionSequence.Verify(b => b.TryRevert(), Times.Never); | 			sessionSequence.Verify(b => b.TryRevert(), Times.Never); | ||||||
| 
 | 
 | ||||||
| 			Assert.AreEqual(0, session); | 			Assert.AreEqual(0, session); | ||||||
|  |  | ||||||
|  | @ -9,6 +9,9 @@ | ||||||
| using System; | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.IO; | using System.IO; | ||||||
|  | using System.Security.AccessControl; | ||||||
|  | using System.Security.Principal; | ||||||
|  | using System.Threading; | ||||||
| using SafeExamBrowser.Communication.Hosts; | using SafeExamBrowser.Communication.Hosts; | ||||||
| using SafeExamBrowser.Communication.Proxies; | using SafeExamBrowser.Communication.Proxies; | ||||||
| using SafeExamBrowser.Contracts.Core.OperationModel; | using SafeExamBrowser.Contracts.Core.OperationModel; | ||||||
|  | @ -42,13 +45,10 @@ namespace SafeExamBrowser.Service | ||||||
| 			var bootstrapOperations = new Queue<IOperation>(); | 			var bootstrapOperations = new Queue<IOperation>(); | ||||||
| 			var sessionOperations = new Queue<IOperation>(); | 			var sessionOperations = new Queue<IOperation>(); | ||||||
| 
 | 
 | ||||||
| 			// TODO: bootstrapOperations.Enqueue(new RestoreOperation()); |  | ||||||
| 			bootstrapOperations.Enqueue(new CommunicationHostOperation(serviceHost, logger)); | 			bootstrapOperations.Enqueue(new CommunicationHostOperation(serviceHost, logger)); | ||||||
| 			bootstrapOperations.Enqueue(new ServiceEventCleanupOperation(logger, sessionContext)); | 			bootstrapOperations.Enqueue(new ServiceEventCleanupOperation(logger, sessionContext)); | ||||||
| 
 | 
 | ||||||
| 			sessionOperations.Enqueue(new SessionInitializationOperation(logger, CreateLogWriter, serviceHost, sessionContext)); | 			sessionOperations.Enqueue(new SessionInitializationOperation(logger, LogWriterFactory, ServiceEventFactory, serviceHost, sessionContext)); | ||||||
| 			// TODO: sessionOperations.Enqueue(new RegistryOperation()); |  | ||||||
| 			//       sessionOperations.Enqueue(new WindowsUpdateOperation()); |  | ||||||
| 			sessionOperations.Enqueue(new SessionActivationOperation(logger, sessionContext)); | 			sessionOperations.Enqueue(new SessionActivationOperation(logger, sessionContext)); | ||||||
| 
 | 
 | ||||||
| 			var bootstrapSequence = new OperationSequence(logger, bootstrapOperations); | 			var bootstrapSequence = new OperationSequence(logger, bootstrapOperations); | ||||||
|  | @ -82,7 +82,7 @@ namespace SafeExamBrowser.Service | ||||||
| 			logFileWriter.Initialize(); | 			logFileWriter.Initialize(); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		private ILogObserver CreateLogWriter(string filePath) | 		private ILogObserver LogWriterFactory(string filePath) | ||||||
| 		{ | 		{ | ||||||
| 			var writer = new LogFileWriter(new DefaultLogFormatter(), filePath); | 			var writer = new LogFileWriter(new DefaultLogFormatter(), filePath); | ||||||
| 
 | 
 | ||||||
|  | @ -90,5 +90,16 @@ namespace SafeExamBrowser.Service | ||||||
| 
 | 
 | ||||||
| 			return writer; | 			return writer; | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
|  | 		private EventWaitHandle ServiceEventFactory(string eventName) | ||||||
|  | 		{ | ||||||
|  | 			var securityIdentifier = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null); | ||||||
|  | 			var accessRule = new EventWaitHandleAccessRule(securityIdentifier, EventWaitHandleRights.Synchronize, AccessControlType.Allow); | ||||||
|  | 			var security = new EventWaitHandleSecurity(); | ||||||
|  | 
 | ||||||
|  | 			security.AddAccessRule(accessRule); | ||||||
|  | 
 | ||||||
|  | 			return new EventWaitHandle(false, EventResetMode.AutoReset, eventName, out _, security); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -7,8 +7,6 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| using System; | using System; | ||||||
| using System.Security.AccessControl; |  | ||||||
| using System.Security.Principal; |  | ||||||
| using System.Threading; | using System.Threading; | ||||||
| using SafeExamBrowser.Contracts.Communication.Hosts; | using SafeExamBrowser.Contracts.Communication.Hosts; | ||||||
| using SafeExamBrowser.Contracts.Core.OperationModel; | using SafeExamBrowser.Contracts.Core.OperationModel; | ||||||
|  | @ -19,18 +17,21 @@ namespace SafeExamBrowser.Service.Operations | ||||||
| 	internal class SessionInitializationOperation : SessionOperation | 	internal class SessionInitializationOperation : SessionOperation | ||||||
| 	{ | 	{ | ||||||
| 		private ILogger logger; | 		private ILogger logger; | ||||||
| 		private Func<string, ILogObserver> createLogWriter; | 		private Func<string, ILogObserver> logWriterFactory; | ||||||
|  | 		private Func<string, EventWaitHandle> serviceEventFactory; | ||||||
| 		private IServiceHost serviceHost; | 		private IServiceHost serviceHost; | ||||||
| 		private ILogObserver sessionWriter; | 		private ILogObserver sessionWriter; | ||||||
| 
 | 
 | ||||||
| 		public SessionInitializationOperation( | 		public SessionInitializationOperation( | ||||||
| 			ILogger logger, | 			ILogger logger, | ||||||
| 			Func<string, ILogObserver> createLogWriter, | 			Func<string, ILogObserver> logWriterFactory, | ||||||
|  | 			Func<string, EventWaitHandle> serviceEventFactory, | ||||||
| 			IServiceHost serviceHost, | 			IServiceHost serviceHost, | ||||||
| 			SessionContext sessionContext) : base(sessionContext) | 			SessionContext sessionContext) : base(sessionContext) | ||||||
| 		{ | 		{ | ||||||
| 			this.logger = logger; | 			this.logger = logger; | ||||||
| 			this.createLogWriter = createLogWriter; | 			this.logWriterFactory = logWriterFactory; | ||||||
|  | 			this.serviceEventFactory = serviceEventFactory; | ||||||
| 			this.serviceHost = serviceHost; | 			this.serviceHost = serviceHost; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -80,12 +81,6 @@ namespace SafeExamBrowser.Service.Operations | ||||||
| 
 | 
 | ||||||
| 		private void InitializeServiceEvent() | 		private void InitializeServiceEvent() | ||||||
| 		{ | 		{ | ||||||
| 			var securityIdentifier = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null); |  | ||||||
| 			var accessRule = new EventWaitHandleAccessRule(securityIdentifier, EventWaitHandleRights.Synchronize, AccessControlType.Allow); |  | ||||||
| 			var security = new EventWaitHandleSecurity(); |  | ||||||
| 
 |  | ||||||
| 			security.AddAccessRule(accessRule); |  | ||||||
| 
 |  | ||||||
| 			if (Context.ServiceEvent != null) | 			if (Context.ServiceEvent != null) | ||||||
| 			{ | 			{ | ||||||
| 				logger.Info("Closing service event from previous session..."); | 				logger.Info("Closing service event from previous session..."); | ||||||
|  | @ -94,13 +89,13 @@ namespace SafeExamBrowser.Service.Operations | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			logger.Info("Attempting to create new service event..."); | 			logger.Info("Attempting to create new service event..."); | ||||||
| 			Context.ServiceEvent = new EventWaitHandle(false, EventResetMode.AutoReset, Context.Configuration.AppConfig.ServiceEventName, out _, security); | 			Context.ServiceEvent = serviceEventFactory.Invoke(Context.Configuration.AppConfig.ServiceEventName); | ||||||
| 			logger.Info("Service event successfully created."); | 			logger.Info("Service event successfully created."); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		private void InitializeSessionWriter() | 		private void InitializeSessionWriter() | ||||||
| 		{ | 		{ | ||||||
| 			sessionWriter = createLogWriter.Invoke(Context.Configuration.AppConfig.ServiceLogFilePath); | 			sessionWriter = logWriterFactory.Invoke(Context.Configuration.AppConfig.ServiceLogFilePath); | ||||||
| 			logger.Subscribe(sessionWriter); | 			logger.Subscribe(sessionWriter); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -159,10 +159,17 @@ namespace SafeExamBrowser.Service | ||||||
| 		private void ServiceHost_SessionStopRequested(SessionStopEventArgs args) | 		private void ServiceHost_SessionStopRequested(SessionStopEventArgs args) | ||||||
| 		{ | 		{ | ||||||
| 			if (SessionIsRunning) | 			if (SessionIsRunning) | ||||||
|  | 			{ | ||||||
|  | 				if (Session.SessionId == args.SessionId) | ||||||
| 				{ | 				{ | ||||||
| 					StopSession(); | 					StopSession(); | ||||||
| 				} | 				} | ||||||
| 				else | 				else | ||||||
|  | 				{ | ||||||
|  | 					logger.Warn("Received session stop request with wrong session ID!"); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
| 			{ | 			{ | ||||||
| 				logger.Warn("Received session stop request, even though no session is currently running!"); | 				logger.Warn("Received session stop request, even though no session is currently running!"); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 dbuechel
						dbuechel