/// <summary>
        /// Updates the agent.
        /// </summary>
        /// <param name="agent">The agent.</param>
        public void UpdateAgent(AgentMetadata agent)
        {
            try
            {
                var agentVersion = agent.Version;
                var currentVersion = versionProvider.GetVersion();

                if (agentVersion < currentVersion)
                {
                    var zippedVersionFolder = updateSource.GetZippedVersionFolder();
                    if (zippedVersionFolder != null)
                    {
                        agents.MarkAsUpdating(agent);
                        new Action(() =>
                                       {
                                           try
                                           {
                                               var testRunnerAgent =
                                                   connectionProvider.GetConnection<IRemoteAppPart>(agent.RemotePartAddress);

                                               testRunnerAgent.ReceiveUpdatePackage(new UpdatePackage
                                                                                        {
                                                                                            IsAvailable = true,
                                                                                            Version = currentVersion,
                                                                                            UpdateZipStream =
                                                                                                zippedVersionFolder
                                                                                        });
                                               agents.MarkAsUpdated(agent);
                                           }
                                           catch(CommunicationException ex)
                                           {
                                               agents.MarkAsDisconnected(agent);
                                               log.Error("Error while updating agent", ex);
                                               throw;
                                           }
                                           catch(Exception ex)
                                           {
                                               agents.MarkAsFailure(agent);
                                               log.Error("Error while updating agent", ex);
                                               throw;
                                           }
                                       }).BeginInvoke(null, null);
                    }
                }
            }
            catch (CommunicationException ex)
            {
                log.Error("Error while trying to check version or apply updates", ex);
                agents.MarkAsFailure(agent);
            }
        }
        private void AddToCollection(AgentMetadata agent)
        {
            using (agents.Lock())
            {
                // ReSharper disable AccessToModifiedClosure
                var agentWithSameNameSameAddress = agents.GetAgent(a => string.Equals(a.Name, agent.Name)
                                                                    && a.Address.Equals(agent.Address));
                var agentWithSameName = agents.GetAgentByName(agent.Name);
                var agentWithSameAddress = agents.GetAgentByAddress(agent.Address);
                // ReSharper restore AccessToModifiedClosure

                if (agentWithSameNameSameAddress != null && agentWithSameNameSameAddress.Status == AgentState.Updated)
                {
                    if (agentWithSameNameSameAddress.Version < agent.Version) // agent was updated and restarted

                        StopAgentPinging(agentWithSameNameSameAddress);
                    else
                        return; // State was set to updated, but the agent has not been restarted yet
                }
                else if (agentWithSameNameSameAddress != null && agentWithSameNameSameAddress.Status != AgentState.Disconnected)
                    return;

                if (agentWithSameNameSameAddress != null) //agent is disconnected here
                {
                    agentWithSameNameSameAddress.Version = agent.Version;
                    agent = agentWithSameNameSameAddress; // replace, so it can be later connected
                }
                else
                {
                    if (agentWithSameName != null)
                    {
                        StopAgentPinging(agentWithSameName);
                        agents.MarkAsDisconnected(agentWithSameName);
                    }

                    if (agentWithSameAddress != null)
                    {
                        StopAgentPinging(agentWithSameAddress);
                        agents.MarkAsDisconnected(agentWithSameAddress);
                    }
                }

                agents.Connect(agent);
                StartAgentPinging(agent);
            }
        }
        public void ChildrenAreAddedAsSeparateUnits()
        {
            unitsFixture.Add("As.Nam1.Nam2.Nam3.Nam4.S1",
                             new[]
                                 {
                                     "tc1",
                                     "tc2",
                                     "tc3"
                                 });

            var units = unitsFixture.Build();
            resultsfactory.Initialize(units);

            resultsfactory.Execute(units[0].Children[0], r => r.Failure("Unit 1 failed", "Error stack trace 1"));
            resultsfactory.Execute(units[0].Children[2], r => r.Failure("Unit 3 failed", "Error stack trace 3"));

            var result = resultsfactory.Build();

            testRun.Parameters.SpecialHandlings.Add(
                new TestRunFailureSpecialHandling
                {
                    FailureMessage = "Unit 1",
                    FailureMessageType = MatchType.ContainsText,
                    RetryCount = 2
                });

            testRun.Parameters.SpecialHandlings.Add(
                new TestRunFailureSpecialHandling
                {
                    FailureMessage = "^U.+led$",
                    FailureMessageType = MatchType.Regex,
                    RetryCount = 2
                });

            var agent = new AgentMetadata(new EndpointAddress("net.tcp://test/"));
            reprocessor.AddForReprocessingIfRequired(units[0], result, agent);

            collectionMock.Received(1)
                .Add(Arg.Is<TestUnitWithMetadata>(v => v.FullName.Equals("As.Nam1.Nam2.Nam3.Nam4.S1.tc1")));
            collectionMock.Received(1)
                .Add(Arg.Is<TestUnitWithMetadata>(v => v.FullName.Equals("As.Nam1.Nam2.Nam3.Nam4.S1.tc3")));
        }
        public void FailedResultsIsProcessWhenMatchingInstructionsGiven()
        {
            unitsFixture.Add("As.Nam1.Nam2.Nam3.Nam4.S1",
                             new[]
                                 {
                                     "tc1",
                                     "tc2",
                                     "tc3"
                                 });
            unitsFixture.Add("As.Nam1.Nam2.Nam3.Nam4.S2",
                             new[]
                                 {
                                     "tc1",
                                     "tc2",
                                     "tc3"
                                 });
            var units = unitsFixture.Build();
            resultsfactory.Initialize(units);

            resultsfactory.Execute(units[0], r => r.Error(resultsfactory.GetInitilalizedException<NotImplementedException>()));
            resultsfactory.Execute(units[1], r => r.Failure("Unit 1 failed", "Error stack trace"));

            var result = resultsfactory.Build();

            testRun.Parameters.SpecialHandlings.Add(new TestRunFailureSpecialHandling
                                                        {
                                                            FailureMessage = "Unit 1",
                                                            FailureMessageType = MatchType.ContainsText,
                                                            RetryCount = 2
                                                        });

            testRun.Parameters.SpecialHandlings.Add(new TestRunFailureSpecialHandling
                                                        {
                                                            FailureStackTrace = resultsfactory.GetType().Namespace,
                                                            FailureStackTraceType = MatchType.ContainsText,
                                                            RetryCount = 2
                                                        });

            var agent = new AgentMetadata(new EndpointAddress("net.tcp://test/"));
            reprocessor.AddForReprocessingIfRequired(units[0], result, agent);
            reprocessor.AddForReprocessingIfRequired(units[1], result, agent);

            collectionMock
                .Received(1)
                .Add(Arg.Is<TestUnitWithMetadata>(v => v.FullName.Equals("As.Nam1.Nam2.Nam3.Nam4.S1")));
            collectionMock.Received(1)
                .Add(Arg.Is<TestUnitWithMetadata>(v => v.FullName.Equals("As.Nam1.Nam2.Nam3.Nam4.S2")));
        }
        public void FailedOrErroredResultIsNotReprocessedWhenNoHandlingInstructionsGiven()
        {
            unitsFixture.Add("As.Nam1.Nam2.Nam3.Nam4.S1",
                             new[]
                                 {
                                     "tc1",
                                     "tc2",
                                     "tc3"
                                 });
            unitsFixture.Add("As.Nam1.Nam2.Nam3.Nam4.S2",
                             new[]
                                 {
                                     "tc1",
                                     "tc2",
                                     "tc3"
                                 });
            var units = unitsFixture.Build();
            resultsfactory.Initialize(units);
            resultsfactory.Execute(units[0], r => r.Error(resultsfactory.GetInitilalizedException<NotImplementedException>()));
            resultsfactory.Execute(units[1], r => r.Failure("Error message", "Error stack trace"));

            var result = resultsfactory.Build();

            var agent = new AgentMetadata(new EndpointAddress("net.tcp://test/"));
            reprocessor.AddForReprocessingIfRequired(units[0], result, agent);
            reprocessor.AddForReprocessingIfRequired(units[1], result, agent);

            collectionMock.DidNotReceiveWithAnyArgs().Add(Arg.Any<TestUnitWithMetadata>());
        }
        // Should be started in a separate thread
        private void Run(TestUnitWithMetadata test, AgentMetadata agent, DistributedConfigurationSubstitutions configurationSubstitutions)
        {
            log.BeginActivity(string.Format("[{0}] Started test {1}", test.Test.Run, test.Test.Info.TestName.FullName));
            var request = requests.GetBy(test.Test.Run);
            if (request != null)
                request.Status = TestRunRequestStatus.Pending;
            try
            {
                log.BeginActivity(string.Format("Connecting to agent [{0}]...", agent));
                var testRunnerAgent = connectionProvider.GetConnection<IAgent>(agent.Address);
                log.BeginActivity(string.Format("Connected to agent [{0}]", agent));

                log.BeginActivity(string.Format("Checking project existence ('{0}') on agent {1}", test.Test.Run, agent));
                if (!testRunnerAgent.HasProject(test.Test.Run))
                {
                    log.EndActivity(string.Format("Project '{0}' doesn't exist on agent {1}", test.Test.Run, agent));

                    log.BeginActivity(string.Format("Sending project ('{0}') to agent {1}", test.Test.Run, agent));
                    using (Stream project = projects.GetStreamToPacked(test.Test.Run) ?? new MemoryStream(1))
                    {
                        testRunnerAgent.ReceiveProject(new ProjectMessage
                                                           {
                                                               TestRun = test.Test.Run,
                                                               Project = project
                                                           });
                    }
                    log.EndActivity(string.Format("Sent project ('{0}') to agent {1}", test.Test.Run, agent));
                }
                else
                    log.EndActivity(string.Format("Project '{0}' exist on agent {1}", test.Test.Run, agent));

                var reprocessedCount = request.Statistics.ReprocessedCount;
                log.BeginActivity(string.Format("[{3}/{4}]: Running {0} on {1} with variables ({2})...", test.Test.UniqueTestId, agent, configurationSubstitutions,
                    request.Statistics.GetCountAndIncrement(), reprocessedCount == 0
                    ? request.Statistics.Total.ToString(CultureInfo.InvariantCulture)
                    : string.Format("{2}({0}+{1})", request.Statistics.Total, reprocessedCount, request.Statistics.Total + reprocessedCount)));
                TestResult result = testRunnerAgent.RunTests(test.Test, configurationSubstitutions);
                log.EndActivity(string.Format("Finished running {0} on {1}...", test.Test.UniqueTestId, agent));

                if (result == null)
                    throw new FaultException("Result is not available");

                ProcessResult(test, agent, result);
            }
            catch (FaultException ex)
            {
                log.Error(string.Format("Exception while running test {0} on {1}", test.Test.UniqueTestId, agent), ex);
                agents.MarkAsFailure(agent);
                tests.Add(test);
            }
            catch (CommunicationException ex)
            {
                log.Error(string.Format("Exception in communication while running test {0} on {1}", test.Test.UniqueTestId, agent), ex);
                agents.MarkAsDisconnected(agent);
                tests.Add(test);
            }
            catch(Exception ex)
            {
                log.Error(string.Format("Something bad and unhandled happened while running test {0} on {1}", test.Test.UniqueTestId, agent), ex);
            }
        }
        private void ChangeStatus(AgentMetadata agent, AgentState agentState)
        {
            if (agent == null)
                return;

            var oldStatus = agent.Status;
            ((IAgentStateSetter)agent).Status = agentState;

            if (oldStatus != agentState)
            {
                log.Debug(string.Format("Agent '{0}' state was changed from {1} to {2}", agent.Address, oldStatus, agentState));
            }

            if (oldStatus != AgentState.Ready && agentState == AgentState.Ready)
                ReadyAgentAppeared.SafeInvoke(this, EventArgs.Empty);
            else if (!oldStatus.IsOneOf(new[]{AgentState.Disconnected, AgentState.Error})
                && agentState.IsOneOf(new[]{AgentState.Disconnected, AgentState.Error}))
            {
                ClientDisconnectedOrFailed.SafeInvoke(this, EventArgs.Empty);
            }
        }
 /// <summary>
 /// Marks as updated.
 /// </summary>
 /// <param name="agent">The agent.</param>
 public void MarkAsUpdated(AgentMetadata agent)
 {
     ChangeStatus(agent, AgentState.Updated);
 }
 /// <summary>
 /// Marks as failure.
 /// </summary>
 /// <param name="agent">The agent.</param>
 public void MarkAsFailure(AgentMetadata agent)
 {
     lock (syncObject)
     {
         ChangeStatus(agent, AgentState.Error);
     }
 }
 private void AddTestForReprocessing(TestUnitWithMetadata test, AgentMetadata agent)
 {
     test.AttachedData.MarkAgentAs(agent, SchedulingHint.NotRecommended);
     collection.Add(test);
 }
 private void StopAgentPinging(AgentMetadata agent)
 {
     Timer timer;
     if (timers.TryRemove(agent, out timer))
     {
         timer.Change(Timeout.Infinite, Timeout.Infinite);
         timer.Dispose();
     }
 }
 private void StartAgentPinging(AgentMetadata agent)
 {
     var timer = timers.GetOrAdd(agent, key => new Timer(OnPingTimerTick, key, Timeout.Infinite, Timeout.Infinite));
     lock (timer)
     {
         timer.Change(options.PingIntervalInMiliseconds, Timeout.Infinite);
     }
 }
        private void OnPingTimerTick(object state)
        {
            // This method is run in a separate thread.
            // There is no need to try to make it asynchronous.

            var agent = state as AgentMetadata;

            Timer timer;
            if (!timers.TryGetValue(agent, out timer))
                return;

            if (agent == null || (!agent.Status.IsOneOf(new[] { AgentState.Ready, AgentState.New, AgentState.Error })))
            {
                ReschedulePinging(timer);
                return;
            }

            try
            {
                var agentRemote = connectionProvider.GetConnection<IRemoteAppPart>(agent.RemotePartAddress);
                var result = agentRemote.Ping(TimeSpan.FromMilliseconds(options.PingIntervalInMiliseconds));

                agent.Version = result.Version;

                if (!string.Equals(agent.Name, result.Name))
                {
                    agents.MarkAsDisconnected(agent);
                    var newAgent = new AgentMetadata(agent.Address)
                                       {
                                           Name = result.Name,
                                           Version = result.Version
                                       };
                    agents.Connect(newAgent);
                    StartAgentPinging(newAgent);
                }

                agentUpdater.UpdateAgent(agent);

                ReschedulePinging(timer);
            }
            catch (CommunicationException)
            {
                // remove agent from tracking
                // mark as disconnected
                StopAgentPinging(agent);
                agents.MarkAsDisconnected(agent);
            }
            catch // in case of any other exception, we assume, that the agent errored out.
            {
                // remove agent from tracking
                // mark as errored out
                StopAgentPinging(agent);
                agents.MarkAsFailure(agent);
            }
        }
        private void OnAgentConnected(object sender, EventArgs<EndpointAddress> e)
        {
            var agent = new AgentMetadata(e.Data);

            using (agents.Lock())
            {
                var savedAgent = agents.GetAgentByAddress(agent.Address);
                if (savedAgent != null && !savedAgent.Status.IsOneOf(AgentState.Disconnected, AgentState.Updated))
                    return;
            }

            var action =
                new Action(
                    () =>
                        {
                            try
                            {
                                LockCallToAddress(agent.Address);

                                log.Debug(string.Format("Initially pinging {0}", agent.Address));
                                var remoteAppPart = connectionProvider.GetConnection<IRemoteAppPart>(agent.RemotePartAddress);

                                var result = remoteAppPart.Ping(TimeSpan.FromMilliseconds(options.PingIntervalInMiliseconds));

                                log.Debug(string.Format("Successfully initially pinged {0} at {1}", result.Name, agent.Address));

                                agent.Name = result.Name;
                                agent.Version = result.Version;

                                AddToCollection(agent);
                            }
                            finally
                            {
                                UnlockCallToAddress(agent.Address);
                            }
                        });

            action.BeginInvoke(ar =>
                                   {
                                       try
                                       {
                                           action.EndInvoke(ar);
                                       }
                                       catch(Exception ex)
                                       {
                                           // this should be traced as error
                                           log.Debug(string.Format("An error occurred, while initially pinging and adding to collection the endpoint ({0}): {1}", agent.Address, ex.Message));
                                       }
                                   }, null);
        }
        public void ParentReprocessingIsPerformedFixedAmountOfTimes2()
        {
            unitsFixture.Add("As.Nam1.Nam2.Nam3.Nam4.S1",
                             new[]
                                 {
                                     "tc1",
                                     "tc2",
                                     "tc3"
                                 });

            var units = unitsFixture.Build();
            resultsfactory.Initialize(units);

            resultsfactory.Execute(units[0], r => r.Failure("U failed", "Error for suite"));
            resultsfactory.Execute(units[0].Children[0], r => r.Ignore("Unit 1 failed", "Error stack trace 1"));
            resultsfactory.Execute(units[0].Children[1], r => r.Success());
            resultsfactory.Execute(units[0].Children[2], r => r.Failure("Unit 3 failed", "Error stack trace 3"));

            var result = resultsfactory.Build();

            testRun.Parameters.SpecialHandlings.Add(
                new TestRunFailureSpecialHandling
                {
                    FailureMessage = "^U.+led$",
                    FailureMessageType = MatchType.Regex,
                    RetryCount = 2
                });

            var agent = new AgentMetadata(new EndpointAddress("net.tcp://test/"));
            reprocessor.AddForReprocessingIfRequired(units[0], result, agent);

            for (int i = 0; i < 20; i++)
            {
                reprocessor.AddForReprocessingIfRequired(units[0], result, agent);
            }

            collectionMock.Received(2)
                .Add(Arg.Is<TestUnitWithMetadata>(v => v.FullName.Equals("As.Nam1.Nam2.Nam3.Nam4.S1")));
            collectionMock.DidNotReceive()
                .Add(Arg.Is<TestUnitWithMetadata>(v => !v.FullName.Equals("As.Nam1.Nam2.Nam3.Nam4.S1")));
        }
 /// <summary>
 /// Disconnects the specified agent.
 /// </summary>
 /// <param name="agent">The agent.</param>
 public void MarkAsDisconnected(AgentMetadata agent)
 {
     lock (syncObject)
     {
         ChangeStatus(agent, AgentState.Disconnected);
     }
 }
        /// <summary>
        /// Adds for reprocessing if required.
        /// </summary>
        /// <param name="test">The test.</param>
        /// <param name="result">The result.</param>
        /// <param name="agent"> </param>
        public void AddForReprocessingIfRequired(TestUnitWithMetadata test, TestResult result, AgentMetadata agent)
        {
            var request = requests != null ? requests.GetBy(test.Test.Run) : null;
            Action registerReprocessing = () => { if (request != null) request.Statistics.RegisterReprocessing(); };

            if (result == null)
            {
                test.AttachedData.NullReprocessingCount++;
                collection.Add(test);
                log.Info(string.Format("REPROCESSING (as null): '{0}' was added for reprocessing. [{1}]",
                   test.FullName, test.Test.Run));
                registerReprocessing();
                return;
            }

            if (!test.Test.Info.IsSuite)
            {
                var childResult = result.FindDescedant(d => d.FullName.Equals(test.FullName));
                if (childResult != null
                    && ProcessResult(childResult, test.Test.Run, test) == ReprocessingVerdict.PerformReprocessing)
                {
                    AddTestForReprocessing(test, agent);
                    registerReprocessing();
                }
                return;
            }

            foreach (var suiteResult in result.FindBottomLevelTestSuites())
            {
                if (test.FullName.Equals(suiteResult.FullName))
                {
                    var reprocessingVerdict = ProcessResult(suiteResult, test.Test.Run, test);
                    if (reprocessingVerdict == ReprocessingVerdict.MaximumCountWasReached)
                        return;

                    if (reprocessingVerdict == ReprocessingVerdict.PerformReprocessing)
                    {
                        AddTestForReprocessing(test, agent);
                        registerReprocessing();
                        continue;
                    }
                }

                var childrenForReprocessing = new List<Tuple<TestResult, TestUnitWithMetadata>>();
                foreach (TestResult childResult in suiteResult.Results)
                {
                    var childTest = test.Children.FirstOrDefault(ct => ct.FullName.Equals(childResult.FullName));
                    if (ProcessResult(childResult, test.Test.Run, childTest,
                        () =>
                            {
                                childTest = new TestUnitWithMetadata(test.Test.Run, childResult.Test, test.Test.AssemblyName);
                                test.Children.Add(childTest);
                                return childTest;
                            })==ReprocessingVerdict.PerformReprocessing)

                        childrenForReprocessing.Add(new Tuple<TestResult, TestUnitWithMetadata>(childResult, childTest));
                }

                if (childrenForReprocessing.Count > 0 && childrenForReprocessing.Count == suiteResult.Results.Count)
                {
                    AddTestForReprocessing(test, agent);
                    registerReprocessing();
                }
                else
                {
                    foreach (var childForReprocessing in childrenForReprocessing)
                    {
                        AddTestForReprocessing(childForReprocessing.Item2, agent);
                        registerReprocessing();
                    }
                }
            }
        }
 /// <summary>
 /// Marks as ready.
 /// </summary>
 /// <param name="agent">The agent.</param>
 public void MarkAsReady(AgentMetadata agent)
 {
     lock (syncObject)
     {
         ChangeStatus(agent, AgentState.Ready);
     }
 }
        private DistributedConfigurationSubstitutions GetConfigurationValues(DistributedConfigurationSetup configurationSetup,
                                                                      AgentMetadata agentToRun,
                                                                      TestUnitWithMetadata testToRun)
        {
            //BUG: add dependency on test run!
            return configurations.GetOrAdd(agentToRun.Name,
                                    key =>
                                        {
                                            var distributedConfigurationValues = new DistributedConfigurationSubstitutions();

                                            foreach (var variable in configurationSetup.Variables)
                                            {
                                                distributedConfigurationValues.Variables.Add(
                                                    new DistributedConfigurationVariablesValue(variable.Name, variable.GetNextValue()));
                                            }

                                            return distributedConfigurationValues;
                                        });
        }
 /// <summary>
 /// Marks the agent as updating.
 /// </summary>
 /// <param name="agent">The agent.</param>
 public void MarkAsUpdating(AgentMetadata agent)
 {
     lock (syncObject)
     {
         ChangeStatus(agent, AgentState.Updating);
     }
 }
 /// <summary>
 /// Marks the agent as.
 /// </summary>
 /// <param name="agent">The agent.</param>
 /// <param name="schedulingHint">The scheduling hint.</param>
 public void MarkAgentAs(AgentMetadata agent, SchedulingHint schedulingHint)
 {
 }
        /// <summary>
        /// Connects the specified agent metadata.
        /// </summary>
        /// <param name="agent">The agent metadata.</param>
        public void Connect(AgentMetadata agent)
        {
            lock (syncObject)
            {
                ChangeStatus(agent, AgentState.Ready);

                if (!allAgents.Contains(agent))
                    allAgents.Add(agent);
            }
        }
        private void ProcessResult(TestUnitWithMetadata test, AgentMetadata agent, TestResult result)
        {
            bool isRequestCompleted;
            using (agents.Lock())
            {
                lock (tests.SyncObject)
                {
                    AddResultsToTestUnitMetadata(test, result);
                    tests.MarkCompleted(test);
                    agents.MarkAsReady(agent);

                    reprocessor.AddForReprocessingIfRequired(test, result, agent);

                    isRequestCompleted = !tests.IsAnyAvailableFor(test.Test.Run);
                }
            }

            results.Add(result, test.Test.Run);
            var request = requests.GetBy(test.Test.Run);
            if (request != null)
                request.PipeToClient.Publish(result.DeepClone().SetFinal(false));

            if (isRequestCompleted)
                ProcessCompletedTestRun(test.Test.Run);
        }