public async void UpsertRaceConditionAgainstOtherClientWithHigherVersion() { if (Configuration.SetConcurrentModificationHookAction is null) { return; } var key = "key"; int startVersion = 1, higherVersion = 3, attemptedVersion = 2; var startItem = new TestEntity(key, startVersion, "value1"); var higherItem = startItem.WithVersion(higherVersion).WithValue("value" + higherVersion); using (var store2 = CreateStoreImpl()) { Action concurrentModifier = () => { AsyncUtils.WaitSafely(() => Upsert(store2, TestEntity.Kind, key, higherItem.SerializedItemDescriptor)); }; var store1 = CreateStoreImplWithUpdateHook(concurrentModifier); await Init(store1, new DataBuilder().Add(TestEntity.Kind, startItem).BuildSerialized()); var attemptedItem = startItem.WithVersion(attemptedVersion); await Upsert(store1, TestEntity.Kind, key, attemptedItem.SerializedItemDescriptor); AssertEqualsSerializedItem(higherItem, await Get(store1, TestEntity.Kind, key)); } }
public void VerifyUnrecoverableHttpError(int errorStatus) { var errorCondition = ServerErrorCondition.FromStatus(errorStatus); WithServerErrorCondition(errorCondition, StreamWithEmptyData, (uri, httpConfig, recorder) => { using (var dataSource = MakeDataSource(uri, BasicUser, c => c.DataSource(Components.StreamingDataSource().InitialReconnectDelay(TimeSpan.Zero)) .Http(httpConfig))) { var initTask = dataSource.Start(); var status = _updateSink.ExpectStatusUpdate(); errorCondition.VerifyDataSourceStatusError(status); _updateSink.ExpectNoMoreActions(); recorder.RequireRequest(); recorder.RequireNoRequests(TimeSpan.FromMilliseconds(100)); Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1))); errorCondition.VerifyLogMessage(logCapture); } }); }
public async void UpsertRaceConditionAgainstOtherClientWithLowerVersion() { if (Configuration.SetConcurrentModificationHookAction is null) { return; } var key = "key"; int startVersion = 1, store2VersionStart = 2, store2VersionEnd = 4, store1VersionEnd = 10; var startItem = new TestEntity(key, startVersion, "value1"); using (var store2 = CreateStoreImpl()) { int versionCounter = store2VersionStart; Action concurrentModifier = () => { if (versionCounter <= store2VersionEnd) { AsyncUtils.WaitSafely(() => Upsert(store2, TestEntity.Kind, key, startItem.WithVersion(versionCounter).WithValue("value" + versionCounter).SerializedItemDescriptor)); versionCounter++; } }; var store1 = CreateStoreImplWithUpdateHook(concurrentModifier); await Init(store1, new DataBuilder().Add(TestEntity.Kind, startItem).BuildSerialized()); var endItem = startItem.WithVersion(store1VersionEnd).WithValue("value" + store1VersionEnd); await Upsert(store1, TestEntity.Kind, key, endItem.SerializedItemDescriptor); AssertEqualsSerializedItem(endItem, await Get(store1, TestEntity.Kind, key)); } }
private IMembership QueryMembership(string userKey) { var hash = BigSegmentUserKeyHash(userKey); _logger.Debug("Querying Big Segment state for user hash {0}", hash); return(AsyncUtils.WaitSafely(() => _store.GetMembershipAsync(hash))); }
public void VerifyRecoverableHttpError(int errorStatus) { var errorCondition = ServerErrorCondition.FromStatus(errorStatus); WithServerErrorCondition(errorCondition, StreamWithEmptyData, (uri, httpConfig, recorder) => { using (var dataSource = MakeDataSource(uri, BasicUser, c => c.DataSource(Components.StreamingDataSource().InitialReconnectDelay(TimeSpan.Zero)) .Http(httpConfig))) { var initTask = dataSource.Start(); var status = _updateSink.ExpectStatusUpdate(); errorCondition.VerifyDataSourceStatusError(status); // We don't check here for a second status update to the Valid state, because that was // done by DataSourceUpdatesImpl when Init was called - our test fixture doesn't do it. _updateSink.ExpectInit(BasicUser); recorder.RequireRequest(); recorder.RequireRequest(); Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1))); errorCondition.VerifyLogMessage(logCapture); } }); }
public void PingCausesPoll() { var data = new DataSetBuilder() .Add("flag1", 1, LdValue.Of(true), 0) .Build(); var streamWithPing = Handlers.SSE.Start() .Then(PingEvent) .Then(Handlers.SSE.LeaveOpen()); using (var pollingServer = HttpServer.Start(PollingResponse(data))) { using (var streamingServer = HttpServer.Start(streamWithPing)) { using (var dataSource = MakeDataSource(streamingServer.Uri, BasicUser, c => c.ServiceEndpoints(Components.ServiceEndpoints() .Streaming(streamingServer.Uri).Polling(pollingServer.Uri)))) { var initTask = dataSource.Start(); pollingServer.Recorder.RequireRequest(); var receivedData = _updateSink.ExpectInit(BasicUser); AssertHelpers.DataSetsEqual(data, receivedData); Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1))); Assert.False(initTask.IsFaulted); Assert.True(dataSource.Initialized); } } } }
/// <inheritdoc/> public bool Identify(User user, TimeSpan maxWaitTime) { if (user == null) { throw new ArgumentNullException(nameof(user)); } return(AsyncUtils.WaitSafely(() => IdentifyAsync(user), maxWaitTime)); }
void Start(TimeSpan maxWaitTime) { var success = AsyncUtils.WaitSafely(() => _connectionManager.Start(), maxWaitTime); if (!success) { _log.Warn("Client did not successfully initialize within {0} milliseconds.", maxWaitTime.TotalMilliseconds); } }
protected FluentMockServer MakeServer() { // currently we don't need to customize any server settings var server = FluentMockServer.Start(); // Perform an initial request to make sure the server has warmed up. On Android in particular, startup // of the very first server instance in the test run seems to be very slow, which may cause the first // request made by unit tests to time out. using (var client = new HttpClient()) { AsyncUtils.WaitSafely(() => client.GetAsync(server.Urls[0])); } server.ResetLogEntries(); // so the initial request doesn't interfere with test postconditions return(server); }
public void PutCausesDataToBeStoredAndDataSourceInitialized() { var data = new DataSetBuilder() .Add("flag1", 1, LdValue.Of(true), 0) .Build(); WithDataSourceAndServer(StreamWithInitialData(data), (dataSource, _, initTask) => { var receivedData = _updateSink.ExpectInit(BasicUser); AssertHelpers.DataSetsEqual(data, receivedData); Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1))); Assert.False(initTask.IsFaulted); Assert.True(dataSource.Initialized); }); }
public void SuccessfulRequestCausesDataToBeStoredAndDataSourceInitialized() { using (var server = HttpServer.Start(PollingResponse(AllData))) { using (var dataSource = MakeDataSource(server.Uri, BasicUser)) { var initTask = dataSource.Start(); var receivedData = _updateSink.ExpectInit(BasicUser); AssertHelpers.DataSetsEqual(AllData, receivedData); Assert.True(AsyncUtils.WaitSafely(() => initTask, TimeSpan.FromSeconds(1))); Assert.False(initTask.IsFaulted); Assert.True(dataSource.Initialized); } } }
/// <summary> /// Returns a BigSegmentStoreStatus describing whether the store seems to be available /// (that is, the last query to it did not return an error) and whether it is stale (that is, the last /// known update time is too far in the past). /// </summary> /// <remarks> /// If we have not yet obtained that information (the poll task has not executed yet), then this method /// immediately does a metadata query and waits for it to succeed or fail. This means that if an /// application using Big Segments evaluates a feature flag immediately after creating the SDK /// client, before the first status poll has happened, that evaluation may block for however long it /// takes to query the store. /// </remarks> /// <returns>the store status</returns> internal BigSegmentStoreStatus GetStatus() { BigSegmentStoreStatus?ret; _lock.EnterReadLock(); try { ret = _lastStatus; } finally { _lock.ExitReadLock(); } if (ret.HasValue) { return(ret.Value); } return(AsyncUtils.WaitSafely(() => PollStoreAndUpdateStatusAsync())); }
public bool WaitFor(DataSourceState desiredState, TimeSpan timeout) => AsyncUtils.WaitSafely(() => _dataSourceUpdates.WaitForAsync(desiredState, timeout));
/// <inheritdoc/> public bool SetOffline(bool value, TimeSpan maxWaitTime) { return(AsyncUtils.WaitSafely(() => SetOfflineAsync(value), maxWaitTime)); }