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;
        }
コード例 #2
0
		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);
            }
        }
コード例 #4
0
        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);
        }
コード例 #5
0
        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();
        }
コード例 #6
0
        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);
        }
コード例 #7
0
        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);
        }
コード例 #8
0
        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);
        }
コード例 #9
0
        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
        }
コード例 #10
0
        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);
        }
コード例 #11
0
        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));
        }
コード例 #12
0
        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;
            }
        }