private void TestInitialize() { string appUrl = "http://www.test.com/"; string appKey = "secret..."; this.hijack = new TestHttpHandler(); this.hijack.SetResponseContent(String.Empty); var originalFactory = MobileServiceHttpClient.DefaultHandlerFactory; MobileServiceHttpClient.DefaultHandlerFactory = () => this.hijack; this.client = new MobileServiceClient(new Uri(appUrl), appKey, hijack); MobileServiceHttpClient.DefaultHandlerFactory = originalFactory; }
public void TestHttpHandlerWritesCorrectResponse() { using (HttpSimulator simulator = new HttpSimulator("/", @"c:\inetpub\")) { simulator.SetFormVariable("username", "phil").SetReferer(new Uri("http://example.com/1/")).SimulateRequest( new Uri("http://localhost/MyHandler.ashx?id=1234")); TestHttpHandler handler = new TestHttpHandler(); handler.ProcessRequest(HttpContext.Current); HttpContext.Current.Response.Flush(); string expected = @"c:\inetpub\MyHandler.ashx:phil:1234:http://example.com/1/"; Assert.AreEqual(expected, simulator.ResponseText, "The Expected Response is all wrong."); } //HttpContext.Current is set to null again. }
private void TestInitialize(string appUrl = null, string loginPrefix = null, string alternateLoginUri = null) { if (string.IsNullOrEmpty(appUrl)) { appUrl = MobileAppUriValidator.DummyMobileApp; } hijack = new TestHttpHandler(); hijack.SetResponseContent(String.Empty); MobileServiceHttpClient.DefaultHandlerFactory = () => hijack; client = new MobileServiceClient(appUrl, hijack); client.LoginUriPrefix = loginPrefix; if (!string.IsNullOrEmpty(alternateLoginUri)) { client.AlternateLoginHost = new Uri(alternateLoginUri); } }
public async Task SendAsync_GrpcCall_ResponseStreamingPropertySet() { // Arrange var request = new HttpRequestMessage { Version = HttpVersion.Version20, Content = new ByteArrayContent(Array.Empty <byte>()) { Headers = { ContentType = new MediaTypeHeaderValue("application/grpc") } } }; var testHttpHandler = new TestHttpHandler(); var grpcWebHandler = new GrpcWebHandler(GrpcWebMode.GrpcWeb, testHttpHandler); var messageInvoker = new HttpMessageInvoker(grpcWebHandler); // Act await messageInvoker.SendAsync(request, CancellationToken.None); // Assert Assert.AreEqual(true, testHttpHandler.WebAssemblyEnableStreamingResponse); }
public async Task PushAsync_Succeeds_WithClientWinsPolicy() { var hijack = new TestHttpHandler(); hijack.Responses.Add(new HttpResponseMessage(HttpStatusCode.PreconditionFailed) { Content = new StringContent("{\"id\":\"abc\",\"version\":\"Hey\"}") }); hijack.AddResponseContent(@"{""id"": ""abc""}"); var handler = new MobileServiceSyncHandlerMock(); handler.TableOperationAction = async op => { for (int i = 0; i < 2; i++) { try { return(await op.ExecuteAsync()); } catch (MobileServicePreconditionFailedException ex) { op.Item[MobileServiceSystemColumns.Version] = ex.Value[MobileServiceSystemColumns.Version]; } } return(null); }; IMobileServiceClient service = new MobileServiceClient(MobileAppUriValidator.DummyMobileApp, hijack); await service.SyncContext.InitializeAsync(new MobileServiceLocalStoreMock(), handler); IMobileServiceSyncTable table = service.GetSyncTable("someTable"); await table.UpdateAsync(new JObject() { { "id", "abc" }, { "version", "Wow" } }); await service.SyncContext.PushAsync(); }
private static async Task RefreshUserAsync_Setup(string alternateLoginUri = null) { string appUrl = MobileAppUriValidator.DummyMobileApp; string newAuthToken = "new-auth-token"; string userId = "sid:xxxxxxxxxxxxxxxxx"; string responseContent = "{\"authenticationToken\":\"" + newAuthToken + "\",\"user\":{\"userId\":\"" + userId + "\"}}"; TestHttpHandler hijack = new TestHttpHandler(); hijack.Response = new HttpResponseMessage(HttpStatusCode.OK); hijack.Response.Content = new StringContent(responseContent); MobileServiceHttpClient.DefaultHandlerFactory = () => hijack; MobileServiceClient client = new MobileServiceClient(appUrl, hijack); client.CurrentUser = new MobileServiceUser(userId) { MobileServiceAuthenticationToken = "auth-token" }; string refreshUrl; if (!string.IsNullOrEmpty(alternateLoginUri)) { refreshUrl = alternateLoginUri + ".auth/refresh"; client.AlternateLoginHost = new Uri(alternateLoginUri); } else { refreshUrl = appUrl + ".auth/refresh"; } MobileServiceUser user = await client.RefreshUserAsync(); Assert.Equal(EnumValueAttribute.GetValue(MobileServiceFeatures.RefreshToken), hijack.Request.Headers.GetValues(MobileServiceHttpClient.ZumoFeaturesHeader).FirstOrDefault()); Assert.Equal(hijack.Request.RequestUri.OriginalString, refreshUrl); Assert.Equal(newAuthToken, user.MobileServiceAuthenticationToken); Assert.Equal(userId, user.UserId); }
public async Task ReadAsync_WithSystemPropertyType_Generic() { string tableName = "stringId_test_table"; ResetDatabase(tableName); var store = new MobileServiceSQLiteStore(TestDbName); store.DefineTable <ToDoWithSystemPropertiesType>(); var hijack = new TestHttpHandler(); hijack.AddResponseContent(@"{""id"": ""123"", ""version"": ""xyz""}"); IMobileServiceClient service = await CreateClient(hijack, store); var table = service.GetSyncTable <ToDoWithSystemPropertiesType>(); var inserted = new ToDoWithSystemPropertiesType() { Id = "123", Version = "abc", String = "def" }; await table.InsertAsync(inserted); Assert.Equal("abc", inserted.Version); await service.SyncContext.PushAsync(); ToDoWithSystemPropertiesType rehydrated = await table.LookupAsync(inserted.Id); Assert.Equal("xyz", rehydrated.Version); string expectedRequestContent = @"{""id"":""123"",""String"":""def""}"; // version should not be sent with insert request Assert.Equal(hijack.RequestContents[0], expectedRequestContent); }
public async Task Insert_AllTypes_ThenRead_ThenPush_ThenLookup() { ResetDatabase("AllBaseTypesWithAllSystemPropertiesType"); var hijack = new TestHttpHandler(); var store = new MobileServiceSQLiteStore(TestDbName); store.DefineTable <AllBaseTypesWithAllSystemPropertiesType>(); IMobileServiceClient service = await CreateClient(hijack, store); IMobileServiceSyncTable <AllBaseTypesWithAllSystemPropertiesType> table = service.GetSyncTable <AllBaseTypesWithAllSystemPropertiesType>(); // first insert an item var inserted = new AllBaseTypesWithAllSystemPropertiesType() { Id = "abc", Bool = true, Byte = 11, SByte = -11, UShort = 22, Short = -22, UInt = 33, Int = -33, ULong = 44, Long = -44, Float = 55.66f, Double = 66.77, Decimal = 77.88M, String = "EightyEight", Char = '9', DateTime = new DateTime(2010, 10, 10, 10, 10, 10, DateTimeKind.Utc), DateTimeOffset = new DateTimeOffset(2011, 11, 11, 11, 11, 11, 11, TimeSpan.Zero), Nullable = 12.13, NullableDateTime = new DateTime(2010, 10, 10, 10, 10, 10, DateTimeKind.Utc), TimeSpan = new TimeSpan(0, 12, 12, 15, 95), Uri = new Uri("http://example.com"), Enum1 = Enum1.Enum1Value2, Enum2 = Enum2.Enum2Value2, Enum3 = Enum3.Enum3Value2, Enum4 = Enum4.Enum4Value2, Enum5 = Enum5.Enum5Value2, Enum6 = Enum6.Enum6Value2 }; await table.InsertAsync(inserted); IList <AllBaseTypesWithAllSystemPropertiesType> records = await table.ToListAsync(); Assert.Equal(1, records.Count); Assert.Equal(records.First(), inserted); // now push hijack.AddResponseContent(@" {""id"":""abc"", ""bool"":true, ""byte"":11, ""sByte"":-11, ""uShort"":22, ""short"":-22, ""uInt"":33, ""int"":-33, ""uLong"":44, ""long"":-44, ""float"":55.66, ""double"":66.77, ""decimal"":77.88, ""string"":""EightyEight"", ""char"":""9"", ""dateTime"":""2010-10-10T10:10:10.000Z"", ""dateTimeOffset"":""2011-11-11T11:11:11.011Z"", ""nullableDateTime"":""2010-10-10T10:10:10.000Z"", ""timeSpan"":""12:12:15.095"", ""nullable"":12.13, ""uri"":""http://example.com/"", ""enum1"":""Enum1Value2"", ""enum2"":""Enum2Value2"", ""enum3"":""Enum3Value2"", ""enum4"":""Enum4Value2"", ""enum5"":""Enum5Value2"", ""enum6"":""Enum6Value2"", ""version"":""XYZ""}"); await service.SyncContext.PushAsync(); AllBaseTypesWithAllSystemPropertiesType lookedUp = await table.LookupAsync("abc"); inserted.Version = "XYZ"; Assert.Equal(inserted, lookedUp); }
public async Task PushAsync_RetriesOperation_WhenConflictOccursInLastPush() { ResetDatabase(TestTable); var hijack = new TestHttpHandler(); string conflictResult = "{\"id\":\"b\",\"String\":\"Hey\",\"version\":\"def\"}"; hijack.Responses.Add(new HttpResponseMessage(HttpStatusCode.PreconditionFailed) { Content = new StringContent(conflictResult) }); // first push string successResult = "{\"id\":\"b\",\"String\":\"Wow\",\"version\":\"def\"}"; hijack.Responses.Add(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(successResult) }); // second push var store = new MobileServiceSQLiteStore(TestDbName); store.DefineTable <ToDoWithSystemPropertiesType>(); IMobileServiceClient service = await CreateClient(hijack, store); IMobileServiceSyncTable <ToDoWithSystemPropertiesType> table = service.GetSyncTable <ToDoWithSystemPropertiesType>(); // first insert an item var updatedItem = new ToDoWithSystemPropertiesType() { Id = "b", String = "Hey", Version = "abc" }; await table.UpdateAsync(updatedItem); // then push it to server var ex = await Assert.ThrowsAsync <MobileServicePushFailedException>(service.SyncContext.PushAsync); Assert.NotNull(ex.PushResult); Assert.Equal(MobileServicePushStatus.Complete, ex.PushResult.Status); Assert.Single(ex.PushResult.Errors); MobileServiceTableOperationError error = ex.PushResult.Errors.FirstOrDefault(); Assert.NotNull(error); Assert.False(error.Handled); Assert.Equal(MobileServiceTableOperationKind.Update, error.OperationKind); Assert.Equal(error.RawResult, conflictResult); Assert.Equal(error.TableName, TestTable); Assert.Equal(HttpStatusCode.PreconditionFailed, error.Status); var errorItem = error.Item.ToObject <ToDoWithSystemPropertiesType>(JsonSerializer.Create(service.SerializerSettings)); Assert.Equal(errorItem.Id, updatedItem.Id); Assert.Equal(errorItem.String, updatedItem.String); Assert.Equal(errorItem.Version, updatedItem.Version); Assert.Equal(errorItem.CreatedAt, updatedItem.CreatedAt); Assert.Equal(errorItem.UpdatedAt, updatedItem.UpdatedAt); Assert.Equal(error.Result.ToString(Formatting.None), conflictResult); Assert.Equal(1L, service.SyncContext.PendingOperations); // operation not removed updatedItem = await table.LookupAsync("b"); Assert.Equal("Hey", updatedItem.String); // item is not updated await service.SyncContext.PushAsync(); Assert.Equal(0L, service.SyncContext.PendingOperations); // operation now succeeds updatedItem = await table.LookupAsync("b"); Assert.Equal("Wow", updatedItem.String); // item is updated }
public async Task Insert_ThenPush_ThenPull_ThenRead_ThenUpdate_ThenRefresh_ThenDelete_ThenLookup_ThenPush_ThenPurge_ThenRead() { ResetDatabase(TestTable); var hijack = new TestHttpHandler(); hijack.AddResponseContent("{\"id\":\"b\",\"String\":\"Hey\"}"); // insert response hijack.AddResponseContent("[{\"id\":\"b\",\"String\":\"Hey\"},{\"id\":\"a\",\"String\":\"World\"}]"); // pull response hijack.AddResponseContent("[]"); // pull last page IMobileServiceClient service = await CreateTodoClient(hijack); IMobileServiceSyncTable <ToDoWithStringId> table = service.GetSyncTable <ToDoWithStringId>(); // first insert an item await table.InsertAsync(new ToDoWithStringId() { Id = "b", String = "Hey" }); // then push it to server await service.SyncContext.PushAsync(); // then pull changes from server await table.PullAsync(null, null); // order the records by id so we can assert them predictably IList <ToDoWithStringId> items = await table.OrderBy(i => i.Id).ToListAsync(); // we should have 2 records Assert.Equal(2, items.Count); // according to ordering a id comes first Assert.Equal("a", items[0].Id); Assert.Equal("World", items[0].String); // then comes b record Assert.Equal("b", items[1].Id); Assert.Equal("Hey", items[1].String); // we made 2 requests, one for push and two for pull Assert.Equal(3, hijack.Requests.Count); // recreating the client from state in the store service = await CreateTodoClient(hijack); table = service.GetSyncTable <ToDoWithStringId>(); // update the second record items[1].String = "Hello"; await table.UpdateAsync(items[1]); // create an empty record with same id as modified record var second = new ToDoWithStringId() { Id = items[1].Id }; // refresh the empty record await table.RefreshAsync(second); // make sure it is same as modified record now Assert.Equal(second.String, items[1].String); // now delete the record await table.DeleteAsync(second); // now try to get the deleted record ToDoWithStringId deleted = await table.LookupAsync(second.Id); // this should be null Assert.Null(deleted); // try to get the non-deleted record ToDoWithStringId first = await table.LookupAsync(items[0].Id); // this should still be there; Assert.NotNull(first); // make sure it is same as Assert.Equal(first.String, items[0].String); // recreating the client from state in the store service = await CreateTodoClient(hijack); table = service.GetSyncTable <ToDoWithStringId>(); await service.SyncContext.PushAsync(); // now purge the remaining records await table.PurgeAsync(); // now read one last time IEnumerable <ToDoWithStringId> remaining = await table.ReadAsync(); // There shouldn't be anything remaining Assert.Empty(remaining); }
public async Task SystemPropertiesArePreserved_OnlyWhenReturnedFromServer() { ResetDatabase(TestTable); var hijack = new TestHttpHandler(); var store = new MobileServiceSQLiteStore(TestDbName); store.DefineTable <ToDoWithSystemPropertiesType>(); IMobileServiceClient service = await CreateClient(hijack, store); IMobileServiceSyncTable <ToDoWithSystemPropertiesType> table = service.GetSyncTable <ToDoWithSystemPropertiesType>(); // first insert an item var updatedItem = new ToDoWithSystemPropertiesType() { Id = "b", String = "Hey", Version = "abc", CreatedAt = new DateTime(2013, 1, 1, 1, 1, 1, DateTimeKind.Utc), UpdatedAt = new DateTime(2013, 1, 1, 1, 1, 2, DateTimeKind.Utc) }; await table.UpdateAsync(updatedItem); var lookedupItem = await table.LookupAsync("b"); Assert.AreEqual(lookedupItem.String, "Hey"); Assert.AreEqual(lookedupItem.Version, "abc"); // we ignored the sys properties on the local object Assert.AreEqual(lookedupItem.CreatedAt, new DateTime(0, DateTimeKind.Utc)); Assert.AreEqual(lookedupItem.UpdatedAt, new DateTime(0, DateTimeKind.Utc)); Assert.AreEqual(service.SyncContext.PendingOperations, 1L); // operation pending hijack.OnSendingRequest = async req => { // we request all the system properties present on DefineTable<> object Assert.AreEqual(req.RequestUri.Query, "?__systemproperties=__createdAt%2C__updatedAt%2C__version%2C__deleted"); string content = await req.Content.ReadAsStringAsync(); Assert.AreEqual(content, @"{""id"":""b"",""String"":""Hey""}"); // the system properties are not sent to server return(req); }; string updateResult = "{\"id\":\"b\",\"String\":\"Wow\",\"__version\":\"def\",\"__createdAt\":\"2014-01-29T23:01:33.444Z\", \"__updatedAt\":\"2014-01-30T23:01:33.444Z\"}"; hijack.Responses.Add(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent(updateResult) }); // push await service.SyncContext.PushAsync(); Assert.AreEqual(service.SyncContext.PendingOperations, 0L); // operation removed lookedupItem = await table.LookupAsync("b"); Assert.AreEqual(lookedupItem.String, "Wow"); Assert.AreEqual(lookedupItem.Version, "def"); // we preserved the system properties returned from server on update Assert.AreEqual(lookedupItem.CreatedAt.ToUniversalTime(), new DateTime(2014, 01, 29, 23, 1, 33, 444, DateTimeKind.Utc)); Assert.AreEqual(lookedupItem.UpdatedAt.ToUniversalTime(), new DateTime(2014, 01, 30, 23, 1, 33, 444, DateTimeKind.Utc)); }
public async Task PushAsync_Succeeds_WithPendingOperations_AndOpQueueIsConsistent() { // Essentially async ManualResetEvents SemaphoreSlim untilPendingOpsCreated = new SemaphoreSlim(0, 1); SemaphoreSlim untilAboutToExecuteOp = new SemaphoreSlim(0, 1); int pushState = 0; var handler = new MobileServiceSyncHandlerMock(); handler.TableOperationAction = async op => { untilAboutToExecuteOp.Release(); await untilPendingOpsCreated.WaitAsync(); JObject result = await op.ExecuteAsync(); if (0 == pushState) { Assert.Equal(MobileServiceTableOperationKind.Insert, op.Kind); Assert.Equal(0, op.Item.Value <int>("value")); } else { Assert.Equal(MobileServiceTableOperationKind.Update, op.Kind); Assert.Equal(2, op.Item.Value <int>("value")); // We shouldn't see the value == 1, since it should have been collapsed } // We don't care what the server actually returned, as long as there was no exception raised in our Push logic return(result); }; var hijack = new TestHttpHandler(); IMobileServiceClient service = new MobileServiceClient("http://www.test.com", hijack); LocalStoreWithDelay mockLocalStore = new LocalStoreWithDelay(); await service.SyncContext.InitializeAsync(mockLocalStore, handler); JObject item = null; // Add the initial operation and perform a push IMobileServiceSyncTable table = service.GetSyncTable("someTable"); string responseContent = @"{ ""id"": ""abc"", ""value"": ""0"", ""version"": ""v0"" }"; // Whatever is fine, since we won't use it or look at it // Do this Insert/Push/Update+Update/Push cycle several times fast to try to hit any race conditions that would cause an error for (int id = 0; id < 10; id++) { hijack.SetResponseContent(responseContent); string idStr = "id" + id; // Generate a new Id each time in case the mock objects ever care that we insert an item that already exists // The Operations and PushAction don't necessarily clone the JObject, so we need a fresh one for each operation or else we'll change // the in-memory representation of the JObject stored in all operations, as well as in the "batch" the PushAction owns. This is problematic. item = new JObject() { { "id", idStr }, { "value", 0 } }; await table.InsertAsync(item); Task pushComplete = service.SyncContext.PushAsync(); // Make sure the PushAction has actually called into our SyncHandler, otherwise the two UpdateOperations could collapse onto it, and // there won't necessarily even be a second PushAction await untilAboutToExecuteOp.WaitAsync(); // Add some more operations while that push is in flight. Since these operations affect the same item in someTable, the operations // will be stuck awaiting the PushAction since it locks on the row. item = new JObject() { { "id", idStr }, { "value", 1 } }; Task updateOnce = table.UpdateAsync(item); item = new JObject() { { "id", idStr }, { "value", 2 } }; Task updateTwice = table.UpdateAsync(item); // Before we let the push finish, let's inject a delay that will cause it to take a long time deleting the operation from the queue. // This will give the other operations, if there's an unaddressed race condition, a chance to wreak havoc on the op queue. mockLocalStore.SetLookupDelay(500); // Let the first push finish untilPendingOpsCreated.Release(); await pushComplete; mockLocalStore.SetLookupDelay(0); await updateOnce; await updateTwice; // Push again, but now the operation condensed from the two updates should be executed remotely pushState = (pushState + 1) % 2; hijack.SetResponseContent(responseContent); pushComplete = service.SyncContext.PushAsync(); await untilAboutToExecuteOp.WaitAsync(); // not strictly necessary other than to keep the semaphore count at 0 untilPendingOpsCreated.Release(); await pushComplete; pushState = (pushState + 1) % 2; } }