Esempio n. 1
0
    public void canceled_transition_reverts_back_to_original_state()
    {
        var factory = new StateMachineTaskFactory <State>();
        var cancellationTokenSource = new CancellationTokenSource();

        factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
        factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.Delay(TimeSpan.FromSeconds(3), cancellationTokenSource.Token));
        factory.StateChanged += (s, e) =>
        {
            if (e.NewState == State.Stopping)
            {
                // cancel the stop
                cancellationTokenSource.Cancel();
            }
        };
        var startedTask = factory.TransitionTo(State.Started);
        var stoppedTask = factory.TransitionTo(State.Stopped, cancellationTokenSource.Token);

        startedTask.Wait(TimeSpan.FromSeconds(3));
        try
        {
            stoppedTask.Wait(TimeSpan.FromSeconds(3));
            Assert.True(false, "Failed to throw exception.");
        }
        catch (AggregateException ex)
        {
            Assert.Equal(1, ex.InnerExceptions.Count);
            Assert.IsType <OperationCanceledException>(ex.InnerExceptions[0]);
            Assert.Equal(State.Started, factory.State);
        }
    }
Esempio n. 2
0
    public void state_change_is_raised_as_state_changes()
    {
        var factory = new StateMachineTaskFactory <State>(State.Stopped);

        factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
        factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.FromResult(true));
        var stateChanges = new List <StateChangedEventArgs <State> >();

        factory.StateChanged += (s, e) => stateChanges.Add(e);
        factory.TransitionTo(State.Started).Wait(TimeSpan.FromSeconds(1));
        factory.TransitionTo(State.Stopped).Wait(TimeSpan.FromSeconds(1));
        factory.TransitionTo(State.Started).Wait(TimeSpan.FromSeconds(1));
        factory.TransitionTo(State.Stopped).Wait(TimeSpan.FromSeconds(1));
        Assert.Equal(8, stateChanges.Count);
        Assert.Equal(State.Stopped, stateChanges[0].OldState);
        Assert.Equal(State.Starting, stateChanges[0].NewState);
        Assert.Equal(State.Starting, stateChanges[1].OldState);
        Assert.Equal(State.Started, stateChanges[1].NewState);
        Assert.Equal(State.Started, stateChanges[2].OldState);
        Assert.Equal(State.Stopping, stateChanges[2].NewState);
        Assert.Equal(State.Stopping, stateChanges[3].OldState);
        Assert.Equal(State.Stopped, stateChanges[3].NewState);
        Assert.Equal(State.Stopped, stateChanges[4].OldState);
        Assert.Equal(State.Starting, stateChanges[4].NewState);
        Assert.Equal(State.Starting, stateChanges[5].OldState);
        Assert.Equal(State.Started, stateChanges[5].NewState);
        Assert.Equal(State.Started, stateChanges[6].OldState);
        Assert.Equal(State.Stopping, stateChanges[6].NewState);
        Assert.Equal(State.Stopping, stateChanges[7].OldState);
        Assert.Equal(State.Stopped, stateChanges[7].NewState);
    }
Esempio n. 3
0
    public void transition_to_returns_completed_task_if_already_in_desired_state()
    {
        var factory = new StateMachineTaskFactory <State>();

        factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
        factory.TransitionTo(State.Started).Wait();
        Assert.Equal(TaskStatus.RanToCompletion, factory.TransitionTo(State.Started).Status);
    }
Esempio n. 4
0
    public void register_transition_throws_if_transition_already_registered()
    {
        var factory = new StateMachineTaskFactory <State>();

        factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
        var ex = Assert.Throws <InvalidOperationException>(() => factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true)));

        Assert.Equal("A transition to state 'Started' has already been registered.", ex.Message);
    }
Esempio n. 5
0
        /// <summary>
        /// Writes the string to the response body.
        /// </summary>
        /// <param name="content">The content.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        public Task WriteAsync(string content, CancellationToken cancellationToken)
        {
            if (content == null)
            {
                return(TaskUtil.FromResult(0));
            }
            var buff = Encoding.UTF8.GetBytes(content);

            return(Body.WriteAsync(buff, 0, buff.Length, cancellationToken));
        }
Esempio n. 6
0
        /// <summary>
        /// Asynchronously closes the specified screen.
        /// </summary>
        /// <param name="screen">The <see cref="UIScreen"/> to close.</param>
        /// <param name="duration">The amount of time over which to transition the screen's state, or
        /// <see langword="null"/> to use the default transition time.</param>
        /// <returns>A task which represents the asynchronous operation.</returns>
        public Task CloseAsync(UIScreen screen, TimeSpan?duration = null)
        {
            Contract.Require(screen, nameof(screen));

            if (screens.Contains(screen))
            {
                return(screen.CloseAsync(duration));
            }
            return(TaskUtil.FromResult(false));
        }
Esempio n. 7
0
    public void transition_to_passes_any_state_to_task_creation_function()
    {
        var    factory       = new StateMachineTaskFactory <State>();
        string receivedState = null;

        factory.RegisterTransition(
            State.Starting,
            State.Started,
            (ct, o) =>
        {
            receivedState = o as string;
            return(TaskUtil.FromResult(true));
        });
        factory.TransitionTo(State.Started, CancellationToken.None, null, "here is the state").Wait();
        Assert.Equal("here is the state", receivedState);
    }
Esempio n. 8
0
        /// <summary>
        /// Asynchronously closes all open screens except for the specified screen.
        /// </summary>
        /// <param name="except">The screen which should remain open when all other screens are closed.</param>
        /// <param name="duration">The amount of time over which to transition the screens' states, or
        /// <see langword="null"/> to use the default transition time.</param>
        /// <returns>A collection of <see cref="Task"/> objects representing the asynchronous operations.</returns>
        public Task CloseAllExceptAsync(UIScreen except, TimeSpan?duration = null)
        {
            var tasks = default(List <Task>);

            for (var current = screens.First; current != null; current = current.Next)
            {
                var screen = current.Value;
                if (screen != except)
                {
                    tasks = tasks ?? new List <Task>();
                    tasks.Add(screen.CloseAsync(duration));
                }
            }

            return(tasks.Count == 0 ? TaskUtil.FromResult(true) :
                   new Task(() => Task.WaitAll(tasks.ToArray())));
        }
Esempio n. 9
0
        /// <summary>
        /// Asynchronously closes any screens which match the specified predicate.
        /// </summary>
        /// <param name="predicate">The predicate with which to determine which screens to close.</param>
        /// <param name="duration">The amount of time over which to transition the screens' states, or
        /// <see langword="null"/> to use the default transition time.</param>
        /// <returns>A collection of <see cref="Task"/> objects representing the asynchronous operations.</returns>
        public Task CloseMatchingAsync(Func <UIScreen, Boolean> predicate, TimeSpan?duration = null)
        {
            Contract.Require(predicate, nameof(predicate));

            var tasks = default(List <Task>);

            for (var current = screens.First; current != null; current = current.Next)
            {
                var screen = current.Value;
                if (predicate(screen))
                {
                    tasks = tasks ?? new List <Task>();
                    tasks.Add(screen.CloseAsync(duration));
                }
            }

            return(tasks.Count == 0 ? TaskUtil.FromResult(true) :
                   new Task(() => Task.WaitAll(tasks.ToArray())));
        }
Esempio n. 10
0
    public void transition_to_can_be_canceled_before_transition_takes_place()
    {
        var factory = new StateMachineTaskFactory <State>();
        var cancellationTokenSource = new CancellationTokenSource();

        factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
        cancellationTokenSource.Cancel();
        var startedTask = factory.TransitionTo(State.Started, cancellationTokenSource.Token);

        try
        {
            startedTask.Wait();
            Assert.True(false, "Failed to throw exception.");
        }
        catch (AggregateException ex)
        {
            Assert.Equal(1, ex.InnerExceptions.Count);
            Assert.IsType <OperationCanceledException>(ex.InnerExceptions[0]);
        }
    }
Esempio n. 11
0
    public void failed_transition_reverts_back_to_original_state()
    {
        var factory = new StateMachineTaskFactory <State>();

        factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
        factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => { throw new InvalidOperationException("Something went wrong"); });
        var startedTask = factory.TransitionTo(State.Started);
        var stoppedTask = factory.TransitionTo(State.Stopped);

        startedTask.Wait(TimeSpan.FromSeconds(3));
        try
        {
            stoppedTask.Wait(TimeSpan.FromSeconds(3));
            Assert.True(false, "Failed to throw exception.");
        }
        catch (AggregateException ex)
        {
            Assert.Equal(1, ex.InnerExceptions.Count);
            Assert.IsType <InvalidOperationException>(ex.InnerExceptions[0]);
            Assert.Equal(State.Started, factory.State);
        }
    }
Esempio n. 12
0
    public void transition_to_can_be_forbidden()
    {
        var factory = new StateMachineTaskFactory <State>();

        factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
        factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.FromResult(true));
        var startedTask = factory.TransitionTo(State.Started, CancellationToken.None, x => x == State.Undefined);
        var stoppedTask = factory.TransitionTo(State.Stopped, CancellationToken.None, x => x != State.Started);

        startedTask.Wait(TimeSpan.FromSeconds(3));
        try
        {
            stoppedTask.Wait(TimeSpan.FromSeconds(3));
            Assert.True(false, "Failed to throw exception.");
        }
        catch (AggregateException ex)
        {
            Assert.Equal(1, ex.InnerExceptions.Count);
            var ex2 = Assert.IsType <StateTransitionForbiddenException <State> >(ex.InnerExceptions[0]);
            Assert.Equal(State.Stopped, ex2.TargetState);
            Assert.Equal(State.Started, ex2.State);
            Assert.Equal("A transition to state 'Stopped' was forbidden by the validate transition callback.", ex2.Message);
        }
    }
Esempio n. 13
0
    public void transition_to_can_be_canceled()
    {
        var factory = new StateMachineTaskFactory <State>();
        var cancellationTokenSource = new CancellationTokenSource();

        factory.RegisterTransition(State.Starting, State.Started, (ct, o) => TaskUtil.FromResult(true));
        factory.RegisterTransition(State.Stopping, State.Stopped, (ct, o) => TaskUtil.Delay(TimeSpan.FromMilliseconds(150)));
        var startedTask = factory.TransitionTo(State.Started, cancellationTokenSource.Token);

        startedTask.ContinueWith(x => cancellationTokenSource.Cancel());
        var stoppedTask = factory.TransitionTo(State.Stopped, cancellationTokenSource.Token);

        startedTask.Wait(TimeSpan.FromSeconds(3));
        try
        {
            stoppedTask.Wait(TimeSpan.FromSeconds(3));
            Assert.True(false, "Failed to throw exception.");
        }
        catch (AggregateException ex)
        {
            Assert.Equal(1, ex.InnerExceptions.Count);
            Assert.IsType <OperationCanceledException>(ex.InnerExceptions[0]);
        }
    }
 public Task TransitionTo(T endTransitionState, CancellationToken cancellationToken = default(CancellationToken), ValidateTransitionCallback <T> validateTransitionCallback = null, object state = null)
 {
     lock (this.stateSync)
     {
         if (EqualityComparer <T> .Default.Equals(this.state, endTransitionState))
         {
             // already in the requested state - nothing to do
             return(TaskUtil.FromResult(true));
         }
         else if (this.transitionToState.HasValue && EqualityComparer <T> .Default.Equals(this.transitionToState.Value, endTransitionState))
         {
             // already in the process of transitioning to the requested state - return same transition task
             return(this.transitionToTask);
         }
         else if (this.transitionToTask != null)
         {
             // not in the requested state, but there is an outstanding transition in progress, so come back to this request once it's done
             return(this.transitionToTask.Then(x => this.TransitionTo(endTransitionState, cancellationToken, validateTransitionCallback, state)));
         }
         else if (validateTransitionCallback != null && !validateTransitionCallback(this.State))
         {
             // transition is forbidden, so return a failing task to that affect
             var taskCompletionSource = new TaskCompletionSource <bool>();
             var exception            = new StateTransitionForbiddenException <T>(endTransitionState, this.State);
             taskCompletionSource.TrySetException(exception);
             return(taskCompletionSource.Task);
         }
         // else, need to transition to the chosen state
         TransitionRegistrationInfo transitionRegistrationInfo;
         var result = this.transitionRegistrations.TryGetValue(endTransitionState, out transitionRegistrationInfo);
         exceptionHelper.ResolveAndThrowIf(!result, "transitionNotRegistered", endTransitionState);
         var beginTransitionState = transitionRegistrationInfo.BeginTransitionState;
         var task = transitionRegistrationInfo.TaskFactory(cancellationToken, state);
         exceptionHelper.ResolveAndThrowIf(task == null, "taskFactoryReturnedNull", endTransitionState);
         var previousState = this.State;
         this.State             = beginTransitionState;
         this.transitionToState = endTransitionState;
         this.transitionToTask  = task
                                  .ContinueWith(
             x =>
         {
             if (x.IsFaulted || cancellationToken.IsCancellationRequested)
             {
                 // faulted or canceled, so roll back to previous state
                 lock (this.stateSync)
                 {
                     this.State             = previousState;
                     this.transitionToState = null;
                     this.transitionToTask  = null;
                 }
                 if (x.IsFaulted)
                 {
                     throw x.Exception;
                 }
                 cancellationToken.ThrowIfCancellationRequested();
             }
             else
             {
                 // succeeded, so commit to end state
                 lock (this.stateSync)
                 {
                     this.State             = endTransitionState;
                     this.transitionToState = null;
                     this.transitionToTask  = null;
                 }
             }
         });
         return(this.transitionToTask);
     }
 }