Exemplo n.º 1
0
        private static IStateResult configurePushTransitionsForTimeEntries(
            TransitionHandlerProvider transitions,
            ITogglDatabase database,
            ITogglApi api,
            ITogglDataSource dataSource,
            IRetryDelayService apiDelay,
            IScheduler scheduler,
            IStateResult entryPoint,
            IObservable <Unit> delayCancellation)
        {
            var rnd         = new Random();
            var statusDelay = new RetryDelayService(rnd);

            var push                  = new PushTimeEntriesState(database.TimeEntries);
            var pushOne               = new PushOneEntityState <IDatabaseTimeEntry>();
            var create                = new CreateTimeEntryState(api, dataSource.TimeEntries);
            var update                = new UpdateTimeEntryState(api, dataSource.TimeEntries);
            var delete                = new DeleteTimeEntryState(api, database.TimeEntries);
            var deleteLocal           = new DeleteLocalTimeEntryState(database.TimeEntries);
            var tryResolveClientError = new TryResolveClientErrorState <IDatabaseTimeEntry>();
            var unsyncable            = new UnsyncableTimeEntryState(dataSource.TimeEntries);
            var checkServerStatus     = new CheckServerStatusState(api, scheduler, apiDelay, statusDelay, delayCancellation);
            var finished              = new ResetAPIDelayState(apiDelay);

            return(configurePush(transitions, entryPoint, push, pushOne, create, update, delete, deleteLocal, tryResolveClientError, unsyncable, checkServerStatus, finished));
        }
        public async Task ReturnsCheckServerStatusTransitionWhenTheErrorIsTooManyRequestsException()
        {
            var exception = new TooManyRequestsException(Substitute.For <IRequest>(), Substitute.For <IResponse>());
            var state     = new TryResolveClientErrorState <TestModel>();
            var model     = new TestModel(1, SyncStatus.SyncNeeded);

            var transition = await state.Start((exception, model));

            transition.Result.Should().Be(state.UnresolvedTooManyRequests);
        }
        public void ThrowsWhenExceptionIsNotAClientErrorException()
        {
            var exception = new Exception();
            var state     = new TryResolveClientErrorState <TestModel>();
            var model     = new TestModel(1, SyncStatus.SyncNeeded);

            Action tryResolve = () => state.Start((exception, model)).Wait();

            tryResolve.Should().Throw <ArgumentException>();
        }
        public async Task ReturnsMarkAsUnsyncableWhenTheErrorIsAClientErrorExceptionOtherThanTooManyRequests(Exception exception)
        {
            var state = new TryResolveClientErrorState <TestModel>();
            var model = new TestModel(1, SyncStatus.SyncNeeded);

            var transition = await state.Start((exception, model));

            var parameter = ((Transition <(Exception Reason, TestModel)>)transition).Parameter;

            transition.Result.Should().Be(state.Unresolved);
            parameter.Should().Be((exception, model));
        }
Exemplo n.º 5
0
        private static IStateResult configureCreateOnlyPush <TModel, TDatabase, TThreadsafe>(
            ITransitionConfigurator transitions,
            IStateResult entryPoint,
            IDataSource <TThreadsafe, TDatabase> dataSource,
            IAnalyticsService analyticsService,
            ICreatingApiClient <TModel> creatingApi,
            Func <TModel, TThreadsafe> toClean,
            Func <TThreadsafe, string, TThreadsafe> toUnsyncable,
            ITogglApi api,
            IScheduler scheduler,
            IObservable <Unit> delayCancellation)
            where TModel : IIdentifiable, ILastChangedDatable
            where TDatabase : class, TModel, IDatabaseSyncable
            where TThreadsafe : class, TDatabase, IThreadSafeModel
        {
            var rnd         = new Random();
            var apiDelay    = new RetryDelayService(rnd);
            var statusDelay = new RetryDelayService(rnd);

            var push    = new PushState <TDatabase, TThreadsafe>(dataSource);
            var pushOne = new PushOneEntityState <TThreadsafe>();
            var create  = new CreateEntityState <TModel, TDatabase, TThreadsafe>(creatingApi, dataSource, analyticsService, toClean);
            var tryResolveClientError = new TryResolveClientErrorState <TThreadsafe>();
            var unsyncable            = new UnsyncableEntityState <TThreadsafe>(dataSource, toUnsyncable);
            var checkServerStatus     = new CheckServerStatusState(api, scheduler, apiDelay, statusDelay, delayCancellation);
            var finished = new ResetAPIDelayState(apiDelay);

            transitions.ConfigureTransition(entryPoint, push);
            transitions.ConfigureTransition(push.PushEntity, pushOne);
            transitions.ConfigureTransition(pushOne.CreateEntity, create);

            transitions.ConfigureTransition(pushOne.UpdateEntity, new InvalidTransitionState($"Updating is not supported for {typeof(TModel).Name} during Push sync."));
            transitions.ConfigureTransition(pushOne.DeleteEntity, new InvalidTransitionState($"Deleting is not supported for {typeof(TModel).Name} during Push sync."));
            transitions.ConfigureTransition(pushOne.DeleteEntityLocally, new InvalidTransitionState($"Deleting locally is not supported for {typeof(TModel).Name} during Push sync."));

            transitions.ConfigureTransition(create.ClientError, tryResolveClientError);
            transitions.ConfigureTransition(create.ServerError, checkServerStatus);
            transitions.ConfigureTransition(create.UnknownError, checkServerStatus);

            transitions.ConfigureTransition(tryResolveClientError.UnresolvedTooManyRequests, checkServerStatus);
            transitions.ConfigureTransition(tryResolveClientError.Unresolved, unsyncable);

            transitions.ConfigureTransition(checkServerStatus.Retry, checkServerStatus);
            transitions.ConfigureTransition(checkServerStatus.ServerIsAvailable, push);

            transitions.ConfigureTransition(create.EntityChanged, create);
            transitions.ConfigureTransition(create.Finished, finished);

            transitions.ConfigureTransition(finished.Continue, push);

            return(push.NothingToPush);
        }
Exemplo n.º 6
0
        private static IStateResult configurePush <T>(
            TransitionHandlerProvider transitions,
            IStateResult entryPoint,
            BasePushState <T> push,
            PushOneEntityState <T> pushOne,
            BaseCreateEntityState <T> create,
            BaseUpdateEntityState <T> update,
            BaseDeleteEntityState <T> delete,
            BaseDeleteLocalEntityState <T> deleteLocal,
            TryResolveClientErrorState <T> tryResolveClientError,
            BaseUnsyncableEntityState <T> markUnsyncable,
            CheckServerStatusState checkServerStatus,
            ResetAPIDelayState finished)
            where T : class, IBaseModel, IDatabaseSyncable
        {
            transitions.ConfigureTransition(entryPoint, push.Start);
            transitions.ConfigureTransition(push.PushEntity, pushOne.Start);
            transitions.ConfigureTransition(pushOne.CreateEntity, create.Start);
            transitions.ConfigureTransition(pushOne.UpdateEntity, update.Start);
            transitions.ConfigureTransition(pushOne.DeleteEntity, delete.Start);
            transitions.ConfigureTransition(pushOne.DeleteEntityLocally, deleteLocal.Start);

            transitions.ConfigureTransition(create.ClientError, tryResolveClientError.Start);
            transitions.ConfigureTransition(update.ClientError, tryResolveClientError.Start);
            transitions.ConfigureTransition(delete.ClientError, tryResolveClientError.Start);

            transitions.ConfigureTransition(create.ServerError, checkServerStatus.Start);
            transitions.ConfigureTransition(update.ServerError, checkServerStatus.Start);
            transitions.ConfigureTransition(delete.ServerError, checkServerStatus.Start);

            transitions.ConfigureTransition(create.UnknownError, checkServerStatus.Start);
            transitions.ConfigureTransition(update.UnknownError, checkServerStatus.Start);
            transitions.ConfigureTransition(delete.UnknownError, checkServerStatus.Start);

            transitions.ConfigureTransition(tryResolveClientError.UnresolvedTooManyRequests, checkServerStatus.Start);
            transitions.ConfigureTransition(tryResolveClientError.Unresolved, markUnsyncable.Start);

            transitions.ConfigureTransition(checkServerStatus.Retry, checkServerStatus.Start);
            transitions.ConfigureTransition(checkServerStatus.ServerIsAvailable, push.Start);

            transitions.ConfigureTransition(create.CreatingFinished, finished.Start);
            transitions.ConfigureTransition(update.UpdatingSucceeded, finished.Start);
            transitions.ConfigureTransition(delete.DeletingFinished, finished.Start);
            transitions.ConfigureTransition(deleteLocal.Deleted, finished.Start);
            transitions.ConfigureTransition(deleteLocal.DeletingFailed, finished.Start);

            transitions.ConfigureTransition(finished.Continue, push.Start);

            return(push.NothingToPush);
        }
Exemplo n.º 7
0
        private static IStateResult configurePushSingleton <TModel, TThreadsafe>(
            TransitionHandlerProvider transitions,
            IStateResult entryPoint,
            ISingletonDataSource <TThreadsafe> dataSource,
            IUpdatingApiClient <TModel> updatingApi,
            Func <TModel, TThreadsafe> toClean,
            Func <TThreadsafe, string, TThreadsafe> toUnsyncable,
            ITogglApi api,
            IScheduler scheduler,
            IObservable <Unit> delayCancellation)
            where TModel : class
            where TThreadsafe : class, TModel, IThreadSafeModel, IDatabaseSyncable
        {
            var rnd         = new Random();
            var apiDelay    = new RetryDelayService(rnd);
            var statusDelay = new RetryDelayService(rnd);

            var push    = new PushSingleState <TThreadsafe>(dataSource);
            var pushOne = new PushOneEntityState <TThreadsafe>();
            var update  = new UpdateEntityState <TModel, TThreadsafe>(updatingApi, dataSource, toClean);
            var tryResolveClientError = new TryResolveClientErrorState <TThreadsafe>();
            var unsyncable            = new UnsyncableEntityState <TThreadsafe>(dataSource, toUnsyncable);
            var checkServerStatus     = new CheckServerStatusState(api, scheduler, apiDelay, statusDelay, delayCancellation);
            var finished = new ResetAPIDelayState(apiDelay);

            transitions.ConfigureTransition(entryPoint, push.Start);
            transitions.ConfigureTransition(push.PushEntity, pushOne.Start);
            transitions.ConfigureTransition(pushOne.UpdateEntity, update.Start);

            transitions.ConfigureTransition(pushOne.CreateEntity, new InvalidTransitionState($"Creating is not supported for {typeof(TModel).Name} during Push sync.").Start);
            transitions.ConfigureTransition(pushOne.DeleteEntity, new InvalidTransitionState($"Deleting is not supported for {typeof(TModel).Name} during Push sync.").Start);
            transitions.ConfigureTransition(pushOne.DeleteEntityLocally, new InvalidTransitionState($"Deleting locally is not supported for {typeof(TModel).Name} during Push sync.").Start);

            transitions.ConfigureTransition(update.ClientError, tryResolveClientError.Start);
            transitions.ConfigureTransition(update.ServerError, checkServerStatus.Start);
            transitions.ConfigureTransition(update.UnknownError, checkServerStatus.Start);

            transitions.ConfigureTransition(tryResolveClientError.UnresolvedTooManyRequests, checkServerStatus.Start);
            transitions.ConfigureTransition(tryResolveClientError.Unresolved, unsyncable.Start);

            transitions.ConfigureTransition(checkServerStatus.Retry, checkServerStatus.Start);
            transitions.ConfigureTransition(checkServerStatus.ServerIsAvailable, push.Start);

            transitions.ConfigureTransition(update.UpdatingSucceeded, finished.Start);

            transitions.ConfigureTransition(finished.Continue, push.Start);

            return(push.NothingToPush);
        }
Exemplo n.º 8
0
        private static IStateResult configurePushTransitionsForUsers(
            TransitionHandlerProvider transitions,
            ITogglDatabase database,
            ITogglApi api,
            IScheduler scheduler,
            IStateResult entryPoint,
            IObservable <Unit> delayCancellation)
        {
            var rnd         = new Random();
            var apiDelay    = new RetryDelayService(rnd);
            var statusDelay = new RetryDelayService(rnd);

            var push    = new PushUsersState(database.User);
            var pushOne = new PushOneEntityState <IDatabaseUser>();
            var update  = new UpdateUserState(api, database.User);
            var tryResolveClientError = new TryResolveClientErrorState <IDatabaseUser>();
            var unsyncable            = new UnsyncableUserState(database.User);
            var checkServerStatus     = new CheckServerStatusState(api, scheduler, apiDelay, statusDelay, delayCancellation);
            var finished = new ResetAPIDelayState(apiDelay);

            return(configureUpdateOnlyPush(transitions, entryPoint, push, pushOne, update, tryResolveClientError, unsyncable, checkServerStatus, finished));
        }
Exemplo n.º 9
0
        private static IStateResult configureUpdateOnlyPush <T>(
            TransitionHandlerProvider transitions,
            IStateResult entryPoint,
            BasePushState <T> push,
            PushOneEntityState <T> pushOne,
            BaseUpdateEntityState <T> update,
            TryResolveClientErrorState <T> tryResolveClientError,
            BaseUnsyncableEntityState <T> markUnsyncable,
            CheckServerStatusState checkServerStatus,
            ResetAPIDelayState finished)
            where T : class, IBaseModel, IDatabaseSyncable
        {
            transitions.ConfigureTransition(entryPoint, push.Start);
            transitions.ConfigureTransition(push.PushEntity, pushOne.Start);
            transitions.ConfigureTransition(pushOne.UpdateEntity, update.Start);

            transitions.ConfigureTransition(pushOne.CreateEntity, new InvalidTransitionState($"Creating is not supported for {typeof(T).Name} during Push sync.").Start);
            transitions.ConfigureTransition(pushOne.DeleteEntity, new InvalidTransitionState($"Deleting is not supported for {typeof(T).Name} during Push sync.").Start);
            transitions.ConfigureTransition(pushOne.DeleteEntityLocally, new InvalidTransitionState($"Deleting locally is not supported for {typeof(T).Name} during Push sync.").Start);

            transitions.ConfigureTransition(update.ClientError, tryResolveClientError.Start);
            transitions.ConfigureTransition(update.ServerError, checkServerStatus.Start);
            transitions.ConfigureTransition(update.UnknownError, checkServerStatus.Start);

            transitions.ConfigureTransition(tryResolveClientError.UnresolvedTooManyRequests, checkServerStatus.Start);
            transitions.ConfigureTransition(tryResolveClientError.Unresolved, markUnsyncable.Start);

            transitions.ConfigureTransition(checkServerStatus.Retry, checkServerStatus.Start);
            transitions.ConfigureTransition(checkServerStatus.ServerIsAvailable, push.Start);

            transitions.ConfigureTransition(update.UpdatingSucceeded, finished.Start);

            transitions.ConfigureTransition(finished.Continue, push.Start);

            return(push.NothingToPush);
        }
Exemplo n.º 10
0
        private static IStateResult configurePush <TModel, TDatabase, TThreadsafe>(
            TransitionHandlerProvider transitions,
            IStateResult entryPoint,
            IDataSource <TThreadsafe, TDatabase> dataSource,
            ICreatingApiClient <TModel> creatingApi,
            IUpdatingApiClient <TModel> updatingApi,
            IDeletingApiClient <TModel> deletingApi,
            Func <TModel, TThreadsafe> toClean,
            Func <TThreadsafe, string, TThreadsafe> toUnsyncable,
            ITogglApi api,
            IRetryDelayService apiDelay,
            IScheduler scheduler,
            IObservable <Unit> delayCancellation)
            where TModel : class, IIdentifiable, ILastChangedDatable
            where TDatabase : class, TModel, IDatabaseSyncable
            where TThreadsafe : class, TDatabase, IThreadSafeModel
        {
            var rnd         = new Random();
            var statusDelay = new RetryDelayService(rnd);

            var push                  = new PushState <TDatabase, TThreadsafe>(dataSource);
            var pushOne               = new PushOneEntityState <TThreadsafe>();
            var create                = new CreateEntityState <TModel, TThreadsafe>(creatingApi, dataSource, toClean);
            var update                = new UpdateEntityState <TModel, TThreadsafe>(updatingApi, dataSource, toClean);
            var delete                = new DeleteEntityState <TModel, TDatabase, TThreadsafe>(deletingApi, dataSource);
            var deleteLocal           = new DeleteLocalEntityState <TDatabase, TThreadsafe>(dataSource);
            var tryResolveClientError = new TryResolveClientErrorState <TThreadsafe>();
            var unsyncable            = new UnsyncableEntityState <TThreadsafe>(dataSource, toUnsyncable);
            var checkServerStatus     = new CheckServerStatusState(api, scheduler, apiDelay, statusDelay, delayCancellation);
            var finished              = new ResetAPIDelayState(apiDelay);

            transitions.ConfigureTransition(entryPoint, push);
            transitions.ConfigureTransition(push.PushEntity, pushOne);
            transitions.ConfigureTransition(pushOne.CreateEntity, create);
            transitions.ConfigureTransition(pushOne.UpdateEntity, update);
            transitions.ConfigureTransition(pushOne.DeleteEntity, delete);
            transitions.ConfigureTransition(pushOne.DeleteEntityLocally, deleteLocal);

            transitions.ConfigureTransition(create.ClientError, tryResolveClientError);
            transitions.ConfigureTransition(update.ClientError, tryResolveClientError);
            transitions.ConfigureTransition(delete.ClientError, tryResolveClientError);

            transitions.ConfigureTransition(create.ServerError, checkServerStatus);
            transitions.ConfigureTransition(update.ServerError, checkServerStatus);
            transitions.ConfigureTransition(delete.ServerError, checkServerStatus);

            transitions.ConfigureTransition(create.UnknownError, checkServerStatus);
            transitions.ConfigureTransition(update.UnknownError, checkServerStatus);
            transitions.ConfigureTransition(delete.UnknownError, checkServerStatus);

            transitions.ConfigureTransition(tryResolveClientError.UnresolvedTooManyRequests, checkServerStatus);
            transitions.ConfigureTransition(tryResolveClientError.Unresolved, unsyncable);

            transitions.ConfigureTransition(checkServerStatus.Retry, checkServerStatus);
            transitions.ConfigureTransition(checkServerStatus.ServerIsAvailable, push);

            transitions.ConfigureTransition(create.CreatingFinished, finished);
            transitions.ConfigureTransition(update.UpdatingSucceeded, finished);
            transitions.ConfigureTransition(delete.DeletingFinished, finished);
            transitions.ConfigureTransition(deleteLocal.Deleted, finished);
            transitions.ConfigureTransition(deleteLocal.DeletingFailed, finished);

            transitions.ConfigureTransition(finished.Continue, push);

            return(push.NothingToPush);
        }