/// <inheritdoc/> /// <exception cref="TimeoutException"> Throws if operation takes longer than <see cref="Service.MUnitConfiguration.SendTimeout"/>. </exception> /// <exception cref="SocketException"> Re-throws exception thrown by underlying TCP socket. </exception> public virtual uint Send(WireMessage data) { ThrowUtilities.NullArgument(data, nameof(data)); Debug.Assert(_handler != null, "_handler should not be null." + Environment.NewLine + Environment.StackTrace); data.ID = _messageID++; byte[] bytes = SerializeHelper.BinarySerialize(data, _eof); _handler.Send(bytes, 0, bytes.Length, SocketFlags.None, out SocketError socketError); if (socketError != SocketError.Success) { if (socketError == SocketError.TimedOut) { throw new TimeoutException(string.Format( CultureInfo.CurrentCulture, Errors.UTE_TimeoutFormattableString, "Send")); } else { throw new SocketException((int)socketError); } } return(data.ID); }
/// <inheritdoc/> public virtual bool IsAttributeDefined(MemberInfo memberInfo, Type attributeType, bool inherit) { ThrowUtilities.NullArgument(memberInfo, nameof(memberInfo)); ThrowUtilities.NullArgument(attributeType, nameof(attributeType)); return(GetAttributes(memberInfo, inherit).ContainsKey(attributeType)); }
/// <summary> /// Synchronize write. /// </summary> /// <param name="action"> Action to perform on underlying data structure. </param> protected void SyncWrite(Action action) { ThrowUtilities.NullArgument(action, nameof(action)); _lock.EnterWriteLock(); action(); _lock.ExitWriteLock(); }
/// <summary> /// Synchronize read. /// </summary> /// <param name="action"> Action to perform on underlying data structure. </param> protected void SyncRead(Action action) { ThrowUtilities.NullArgument(action, nameof(action)); _lock.EnterReadLock(); action(); _lock.ExitReadLock(); }
/// <summary> /// Initializes a new instance of the <see cref="TestCycleGraph"/> class. /// </summary> /// <param name="root">Where test cycle stats.</param> /// <param name="logger"> Logs information. </param> public TestCycleGraph(ITestCycle root, IMUnitLogger logger) { ThrowUtilities.NullArgument(root, nameof(root)); _root = root; _testCycles.Add(root.ID, root); this.Logger = logger; }
/// <summary> /// Initializes a new instance of the <see cref="MUnitWire"/> class. /// </summary> /// <param name="testEngine"> Test engine supported by this transporter. </param> /// <param name="transporter"> Transporter used for IPC. </param> public MUnitWire(ITestEngine testEngine, ITransporter transporter) { ThrowUtilities.NullArgument(testEngine, nameof(testEngine)); ThrowUtilities.NullArgument(transporter, nameof(transporter)); _logger = testEngine.Logger; _transporter = transporter; _testEngine = testEngine; }
/// <inheritdoc/> public virtual bool HasAttributeDerivedFrom(MemberInfo memberInfo, Type baseAttributeType, bool inherit) { ThrowUtilities.NullArgument(memberInfo, nameof(memberInfo)); ThrowUtilities.NullArgument(baseAttributeType, nameof(baseAttributeType)); return(GetAttributes(memberInfo, inherit) .Keys .Any(t => t.IsSubclassOf(baseAttributeType))); }
/// <inheritdoc/> protected override object ProcessActionCommand(WireMessage message) { ThrowUtilities.NullArgument(message, nameof(message)); switch (message.Type) { case WireMessageTypes.Telemetry: switch (message.Command) { case CommandType.RecordTestStart: this.RecordTestStartEvent?.Invoke(message.Entity as TestResult); break; case CommandType.RecordTestEnd: this.RecordTestEndEvent?.Invoke(message.Entity as TestResult); break; case CommandType.DiscoverTests: _discoverTestsLocks.HandlerLock.WaitOne(); this.DiscoverTestsEvent?.Invoke(message.SessionID, message.Entity as ICollection <ITestMethodContext>); break; default: _logger.RecordMessage(MessageLevel.Warning, string.Format( CultureInfo.CurrentCulture, Errors.UTE_UnsupportedCommandType, message.Command.ToString())); break; } break; default: switch (message.Command) { case CommandType.TakeResults: this.RecordTestResultEvent?.Invoke(message.Entity as TestResult); break; case CommandType.CheckAssemblyHash: this.CheckAssemblyHashEvent?.Invoke(message.SessionID, message.Entity as byte[]); break; default: _logger.RecordMessage(MessageLevel.Warning, string.Format( CultureInfo.CurrentCulture, Errors.UTE_UnsupportedCommandType, message.Command.ToString())); break; } break; } return(null); }
/// <summary> /// Synchronize read. /// </summary> /// <typeparam name="T"> Generic type. </typeparam> /// <param name="func"> Function used to read. </param> /// <returns> Result returned from <paramref name="func"/>. </returns> protected T SyncRead <T>(Func <T> func) { ThrowUtilities.NullArgument(func, nameof(func)); _lock.EnterReadLock(); T value = func(); _lock.ExitReadLock(); return(value); }
/// <summary> /// Synchronize write. /// </summary> /// <typeparam name="T"> Generic type. </typeparam> /// <param name="tryFunc"> Functions used for writing. </param> /// <param name="value"> An out parameter passed to <paramref name="tryFunc"/>. </param> /// <returns> Returns true if <paramref name="tryFunc"/> is a success. </returns> protected bool SyncWrite <T>(TryFunction <T> tryFunc, out T value) { ThrowUtilities.NullArgument(tryFunc, nameof(tryFunc)); _lock.EnterWriteLock(); var success = tryFunc(out value); _lock.ExitWriteLock(); return(success); }
/// <summary> /// Discovers tests available from the provided source. /// </summary> /// <param name="sources">Collection of test containers.</param> /// <returns> A collection of test cycles. </returns> public TestCycleCollection DiscoverTests(IEnumerable <string> sources) { ThrowUtilities.NullArgument(sources, nameof(sources)); IList <SourcePackage> packages = _services.TestSource.GetTypes(sources, this.Logger); _testCycles = _services.TestBuilder.BuildTestCycles(packages, this.Logger); this.Logger.RecordMessage(MessageLevel.Information, "Total tests found: " + _testCycles.TestContextLookup.Count); return(_testCycles); }
/// <inheritdoc/> public virtual void Add(ITestCycle testCycle) { ThrowUtilities.NullArgument(testCycle, nameof(testCycle)); _testCycles.Add(testCycle.ID, testCycle); if (_testCycles.TryGetValue(testCycle.ParentID, out ITestCycle parent)) { ThrowUtilities.NullMember(parent.Children, nameof(ITestCycle), nameof(parent.Children)); parent.Children.Add(testCycle); } }
/// <inheritdoc/> public void RunTests(IEnumerable <Guid> guids, int testRunID, IMUnitLogger logger) { ThrowUtilities.NullArgument(guids, nameof(guids)); ThrowUtilities.NullArgument(logger, nameof(logger)); foreach (Guid guid in guids) { _testCycles.TestContextLookup[guid].SetActive(_testCycles); } _testCycles.Run(testRunID); }
/// <summary> /// Discover tests from a type. /// </summary> /// <param name="source"> Full path to the assembly that contains <paramref name="type"/>.</param> /// <param name="type"> Discover tests in this type. </param> /// <param name="testCycles"> Test cycles for query. </param> /// <param name="logger"> Log information. </param> protected virtual void DiscoverTests(string source, Type type, TestCycleCollection testCycles, IMUnitLogger logger) { ThrowUtilities.NullArgument(type, nameof(type)); ThrowUtilities.NullArgument(testCycles, nameof(testCycles)); foreach (MethodInfo method in _reflectionWorker.GetDeclaredMethods(type)) { if (_reflectionHelper.IsValidTestMethod(method, logger)) { TestMethodAttribute methodAttribute = _reflectionWorker.GetAttributesHaveBase(method, typeof(TestMethodAttribute), false).First() as TestMethodAttribute; Guid testCycleID = HashUtilities.GuidForTestCycleID(source, _reflectionHelper.ResolveTestCycleFullName(type, methodAttribute.Scope)); if (!testCycles.TryGetValue(testCycleID, out ITestCycle testCycle)) { testCycle = new TestCycle(source, type, TestCycleScope.Method) { DeclaringClass = type, }; testCycles.Add(testCycle); } TestMethodContext context = new TestMethodContext(source, testCycle, method, type, logger); if (_reflectionWorker.TryGetAttributeAssignableTo(method, typeof(IDataSource), false, out Attribute dataAttribute)) { if (dataAttribute is IDataProvidingMethod dataProvidingMethod) { if (dataProvidingMethod.DeclaringType == null) { dataProvidingMethod.DeclaringType = type; } } // TODO Report data method that has wrong signature. context.DataSource = dataAttribute as IDataSource; } IExecutor executor = _reflectionWorker.GetAttributeAssignableTo(method, typeof(IExecutor), false) as IExecutor; context.Executor = executor; testCycle.TestMethodContexts.Add(context); testCycles.TestContextLookup.Add(context.TestID, context); logger?.RecordMessage(MessageLevel.Trace, string.Format( CultureInfo.CurrentCulture, Resources.Strings.FoundTestMethod, type.FullName, method.Name)); } } }
protected virtual void BuildCycleFromAssembly(string source, ITestCycle root, IEnumerable <Type> types, TestCycleCollection testCycles, IMUnitLogger logger) { ThrowUtilities.NullArgument(root, nameof(root)); ThrowUtilities.NullArgument(testCycles, nameof(testCycles)); ThrowUtilities.NullArgument(types, nameof(types)); TestCycle assemblyCycle = new TestCycle(source, types.First(), root.ID, TestCycleScope.Assembly); testCycles.Add(assemblyCycle); foreach (Type type in types) { BuildCycleFromType(source, type, testCycles, logger); } }
public virtual void SendTestResult(IEnumerable <TestResult> testResults) { ThrowUtilities.NullArgument(testResults, nameof(testResults)); try { this.Send( new WireMessage( WireMessageTypes.Reply, CommandType.TakeResults, testResults), testResults.First().TestRunID); } catch (Exception e) { _logger.RecordMessage(MessageLevel.Error, e.ToString()); } }
/// <inheritdoc/> public virtual ICollection <ITestMethodContext> RunTests(IEnumerable <string> sources, out int testRunID) { ThrowUtilities.NullArgument(sources, nameof(sources)); try { testRunID = this.Send(new WireMessage( WireMessageTypes.Request, CommandType.RunTests, sources)); return(this.DiscoverTests(sources)); } catch (Exception e) { _logger.RecordMessage(MessageLevel.Error, e.ToString()); throw; } }
public virtual void SendTestStats(TestResult result, CommandType commandType) { ThrowUtilities.NullArgument(result, nameof(result)); Trace.Assert(commandType == CommandType.RecordTestStart || commandType == CommandType.RecordTestEnd, "Input command type is not supported."); try { this.Send( new WireMessage( WireMessageTypes.Telemetry, commandType, result), result.TestRunID); } catch (Exception e) { _logger.RecordMessage(MessageLevel.Error, e.ToString()); } }
/// <summary> /// Discover preparation methods in type. /// </summary> /// <param name="source"> Full path to the assembly that contains <paramref name="type"/>.</param> /// <param name="reference"> The type used for reference when retrieve test cycles. </param> /// <param name="type"> In which preparation methods are discovered. </param> /// <param name="testCycles"> Test cycles for query. </param> /// <param name="logger"> Log information. </param> protected virtual void DiscoverPreparationMethod(string source, Type reference, Type type, TestCycleCollection testCycles, IMUnitLogger logger) { if (type == null) { return; } ThrowUtilities.NullArgument(testCycles, nameof(testCycles)); DiscoverPreparationMethod(source, reference, type.BaseType, testCycles, logger); foreach (MethodInfo method in _reflectionWorker.GetDeclaredMethods(type)) { if (_reflectionHelper.IsValidPrepMethod(method, logger)) { IEnumerable <SupportingAttribute> preparations = _reflectionWorker.GetDerivedAttributes(method, typeof(SupportingAttribute), false) .OfType <SupportingAttribute>(); foreach (SupportingAttribute prep in preparations) { Guid testCycleID = HashUtilities.GuidForTestCycleID(source, _reflectionHelper.ResolveTestCycleFullName(reference, prep.Scope)); if (testCycles.TryGetValue(testCycleID, out ITestCycle cycle)) { prep.Register(cycle, method); logger?.RecordMessage(MessageLevel.Trace, string.Format( CultureInfo.InvariantCulture, "{0} prep method is registered to test cycle {1}", prep.PreparationType, cycle.FullName)); } else { logger?.RecordMessage(MessageLevel.Error, string.Format( CultureInfo.CurrentCulture, Errors.UTE_TestCycleNotFoundForPrep, method.Name)); } } } } }
/// <inheritdoc/> /// <exception cref="TimeoutException"> Throws if operation takes longer than <see cref="Service.MUnitConfiguration.SendTimeout"/>. </exception> /// <exception cref="SocketException"> Re-throws exception thrown by underlying TCP socket. </exception> public void SendAsync(WireMessage data) { ThrowUtilities.NullArgument(data, nameof(data)); Debug.Assert(_handler != null, "_handler should not be null." + Environment.NewLine + Environment.StackTrace); if (!_handler.Connected) { _handler.Connect(_remoteEndPoint ?? _handler.RemoteEndPoint); } if (data.Type == WireMessageTypes.Request) { data.ID = _messageID++; } byte[] bytes = SerializeHelper.BinarySerialize(data, _eof); _handler.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, SendAsyncCallback, _handler); }
/// <inheritdoc/> public virtual TestCycleCollection BuildTestCycles(IList <SourcePackage> packages, IMUnitLogger logger) { ThrowUtilities.NullArgument(packages, nameof(packages)); TestCycle root = new TestCycle(null, GetType(), TestCycleScope.AppDomain); TestCycleCollection testCycles = new TestCycleCollection(root, logger); logger?.RecordMessage(MessageLevel.Trace, string.Format( CultureInfo.InvariantCulture, "Create root test cycle with full name: {0} and parent ID: {1}", root.FullName, root.ParentID)); foreach (SourcePackage package in packages) { BuildCycleFromAssembly(package.Source, root, package.Types, testCycles, logger); } return(testCycles); }
public void Initialize(IMUnitLogger logger, string path) { ThrowUtilities.NullArgument(logger, nameof(logger)); try { if (path == null) { path = Path.Combine(Path.GetDirectoryName(MUnitConfiguration.ConfigPath), "TestLog.txt"); } logger.WriteToFile(path); _fileStream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.None); logger.MessageEvent += Logger_MessageEvent; } catch (Exception e) { logger.RecordMessage(MessageLevel.Error, e.ToString()); } }
protected virtual void BuildCycleFromType(string source, Type type, TestCycleCollection testCycles, IMUnitLogger logger) { ThrowUtilities.NullArgument(type, nameof(type)); ThrowUtilities.NullArgument(testCycles, nameof(testCycles)); if (_reflectionHelper.IsValidTestClass(type, logger)) { if (!testCycles.TryGetValue(HashUtilities.GuidForTestCycleID(source, type.Namespace), out _)) { TestCycle namespaceCycle = new TestCycle(source, type, TestCycleScope.Namespace); testCycles.Add(namespaceCycle); } TestCycle classCycle = new TestCycle(source, type, TestCycleScope.Class); testCycles.Add(classCycle); DiscoverTests(source, type, testCycles, logger); DiscoverPreparationMethod(source, type, type, testCycles, logger); } }
/// <inheritdoc/> public virtual ICollection <ITestMethodContext> DiscoverTests(IEnumerable <string> sources) { ThrowUtilities.NullArgument(sources, nameof(sources)); int sessionID = this.Send(new WireMessage(WireMessageTypes.Request, CommandType.DiscoverTests, sources)); void DiscoverTestsEventHandler(int id, ICollection <ITestMethodContext> tests) { if (id == sessionID) { _discoverTestsLocks.HandlerLock.State = tests; _discoverTestsLocks.EventLock.Set(); } } this.DiscoverTestsEvent += DiscoverTestsEventHandler; _discoverTestsLocks.HandlerLock.Set(); _discoverTestsLocks.EventLock.WaitOne(); this.DiscoverTestsEvent -= DiscoverTestsEventHandler; return((ICollection <ITestMethodContext>)_discoverTestsLocks.HandlerLock.State); }
/// <inheritdoc/> public IList <SourcePackage> GetTypes(IEnumerable <string> sources, IMUnitLogger logger) { ThrowUtilities.NullArgument(sources, nameof(sources)); ThrowUtilities.NullArgument(logger, nameof(logger)); List <SourcePackage> packages = new List <SourcePackage>(); foreach (string source in sources) { logger.RecordMessage(MessageLevel.Trace, "Loading tests from: " + Path.GetFullPath(source)); if (File.Exists(source)) { string fileName = Path.GetFileName(source); if (!ValidateExtension(fileName)) { logger.RecordMessage(MessageLevel.Error, Errors.InvalidExtension); continue; } else if (!TryLoaded(source, out Assembly assembly, logger)) { logger.RecordMessage(MessageLevel.Error, Errors.FileNotLoaded); continue; } else { if (packages.Find(package => package.FullName != assembly.FullName) == null) { packages.Add(new SourcePackage(Path.GetFullPath(source), assembly.FullName, assembly.GetTypes())); } else { logger.RecordMessage(MessageLevel.Warning, Errors.UTE_DuplicateAssembly); } } }
/// <summary> /// Register the method adorned with this attribute to test cycle. /// </summary> /// <param name="testCycle">In which the underlying method belongs.</param> /// <param name="pType">Preparation type of a method.</param> /// <param name="method">Method to register.</param> protected static void Register(ITestCycle testCycle, TestCycleMethodType pType, MethodInfo method) { ThrowUtilities.NullArgument(testCycle, nameof(testCycle)); ThrowUtilities.NullArgument(method, nameof(method)); SupportMethodsGroup group = testCycle.SupportMethodsGroups .FirstOrDefault(g => g.DeclaringType == method.DeclaringType); if (group == default) { group = new SupportMethodsGroup(method.DeclaringType); testCycle.SupportMethodsGroups.Add(group); } if (pType == TestCycleMethodType.Initialize) { // It will overwrite previously found methods in the same type, if there is any. group.InitializeMethod = method; } else if (pType == TestCycleMethodType.Cleanup) { group.CleanupMethod = method; } }
protected override object ProcessActionCommand(WireMessage message) { ThrowUtilities.NullArgument(message, nameof(message)); try { switch (message.Command) { case CommandType.CallFunction: if (message.CallingType != null) { object instance = message.CtorParams == null ? Activator.CreateInstance(message.CallingType) : Activator.CreateInstance(message.CallingType, message.CtorParams); ((MethodInfo)message.Entity).Invoke(instance, message.Parameters); } else { ((MethodInfo)message.Entity).Invoke(null, message.Parameters); } break; case CommandType.DiscoverTests: this.DiscoverTests(message); break; case CommandType.RunTests: switch (message.Entity) { case IEnumerable <string> sources: _testEngine.RunTests(sources, message.SessionID, _logger); break; case IEnumerable <Guid> guids: _testEngine.RunTests(guids, message.SessionID, _logger); break; default: throw new ArgumentException( string.Format( CultureInfo.CurrentCulture, Errors.UTE_UnSupportedTestSources, message.Entity.GetType())); } break; case CommandType.Cancel: _testEngine.Cancel(); break; case CommandType.CheckAssemblyHash: this.Send( new WireMessage( WireMessageTypes.Reply, CommandType.CheckAssemblyHash, new Hash(Assembly.Load((string)message.Entity)).SHA1), message.SessionID); break; default: _logger.RecordMessage(MessageLevel.Warning, string.Format( CultureInfo.CurrentCulture, Errors.UTE_UnsupportedCommandType, message.Command.ToString())); break; } return(null); } catch (SocketException) { throw; } catch (Exception e) { _logger.RecordMessage(MessageLevel.Error, e.ToString()); return(null); } }
/// <summary> /// Executes a test method. /// </summary> /// <param name="testMethodContext">The test method to execute.</param> /// <returns>An array of TestResult objects that represent the outcome(s) of the test.</returns> /// <remarks>Extensions can override this method to customize running a TestMethod.</remarks> public virtual IEnumerable <TestResult> Execute(ITestMethodContext testMethodContext) { ThrowUtilities.NullArgument(testMethodContext, nameof(testMethodContext)); return(testMethodContext.Invoke()); }