private VersionedType(VersionedType other)
 {
     this.Id = other.Id;
     this.Name = other.Name;
     this.Number = other.Number;
     this.Version = other.Version;
     this.CreatedAt = other.CreatedAt;
     this.UpdatedAt = other.UpdatedAt;
 }
Ejemplo n.º 2
0
 private VersionedType(VersionedType other)
 {
     this.Id        = other.Id;
     this.Name      = other.Name;
     this.Number    = other.Number;
     this.Version   = other.Version;
     this.CreatedAt = other.CreatedAt;
     this.UpdatedAt = other.UpdatedAt;
 }
        private static ZumoTest CreateSystemPropertiesTest(bool useTypedTable)
        {
            return new ZumoTest("System properties in " + (useTypedTable ? "" : "un") + "typed tables", async delegate(ZumoTest test)
            {
                var client = ZumoTestGlobals.Instance.Client;
                var typedTable = client.GetTable<VersionedType>();
                var untypedTable = client.GetTable(ZumoTestGlobals.StringIdRoundTripTableName);
                untypedTable.SystemProperties =
                    MobileServiceSystemProperties.CreatedAt |
                    MobileServiceSystemProperties.UpdatedAt |
                    MobileServiceSystemProperties.Version;
                DateTime now = DateTime.UtcNow;
                int seed = now.Year * 10000 + now.Month * 100 + now.Day;
                test.AddLog("Using seed: {0}", seed);
                Random rndGen = new Random(seed);
                VersionedType item = null;
                JObject untypedItem = null;
                DateTime createdAt, updatedAt;
                string id;
                if (useTypedTable)
                {
                    item = new VersionedType(rndGen);
                    await typedTable.InsertAsync(item);
                    test.AddLog("Inserted: {0}", item);
                    id = item.Id;
                    createdAt = item.CreatedAt;
                    updatedAt = item.UpdatedAt;
                }
                else
                {
                    untypedItem = new JObject();
                    untypedItem.Add("name", "unused");
                    untypedItem = (JObject)(await untypedTable.InsertAsync(untypedItem));
                    test.AddLog("Inserted: {0}", untypedItem);
                    id = (string)untypedItem["id"];
                    createdAt = untypedItem["__createdAt"].ToObject<DateTime>();
                    updatedAt = untypedItem["__updatedAt"].ToObject<DateTime>();
                }

                test.AddLog("Now adding a new item");
                DateTime otherCreatedAt, otherUpdatedAt;
                string otherId;
                if (useTypedTable)
                {
                    item = new VersionedType(rndGen);
                    await typedTable.InsertAsync(item);
                    test.AddLog("Inserted: {0}", item);
                    otherId = item.Id;
                    otherCreatedAt = item.CreatedAt;
                    otherUpdatedAt = item.UpdatedAt;
                }
                else
                {
                    untypedItem = new JObject();
                    untypedItem.Add("name", "unused");
                    untypedItem = (JObject)(await untypedTable.InsertAsync(untypedItem));
                    test.AddLog("Inserted: {0}", untypedItem);
                    otherId = (string)untypedItem["id"];
                    otherCreatedAt = untypedItem["__createdAt"].ToObject<DateTime>();
                    otherUpdatedAt = untypedItem["__updatedAt"].ToObject<DateTime>();
                }

                if (createdAt >= otherCreatedAt)
                {
                    test.AddLog("Error, first __createdAt value is not smaller than second one");
                    return false;
                }

                if (updatedAt >= otherUpdatedAt)
                {
                    test.AddLog("Error, first __updatedAt value is not smaller than second one");
                    return false;
                }

                createdAt = otherCreatedAt;
                updatedAt = otherUpdatedAt;

                test.AddLog("Now updating the item");
                if (useTypedTable)
                {
                    item = new VersionedType(rndGen) { Id = otherId };
                    await typedTable.UpdateAsync(item);
                    test.AddLog("Updated: {0}", item);
                    otherUpdatedAt = item.UpdatedAt;
                    otherCreatedAt = item.CreatedAt;
                }
                else
                {
                    untypedItem = new JObject(new JProperty("id", otherId), new JProperty("name", "other name"));
                    untypedItem = (JObject)(await untypedTable.UpdateAsync(untypedItem));
                    test.AddLog("Updated: {0}", untypedItem);
                    otherCreatedAt = untypedItem["__createdAt"].ToObject<DateTime>();
                    otherUpdatedAt = untypedItem["__updatedAt"].ToObject<DateTime>();
                }

                if (createdAt != otherCreatedAt)
                {
                    test.AddLog("Error, update changed the value of the __createdAt property");
                    return false;
                }

                if (otherUpdatedAt <= updatedAt)
                {
                    test.AddLog("Error, update did not change the __updatedAt property to a later value");
                    return false;
                }

                test.AddLog("Cleanup: deleting items");
                await untypedTable.DeleteAsync(new JObject(new JProperty("id", id)));
                await untypedTable.DeleteAsync(new JObject(new JProperty("id", otherId)));
                return true;
            });
        }
        private static ZumoTest CreateOptimisticConcurrencyTest(string testName, Func<VersionedType, VersionedType, VersionedType> mergingPolicy)
        {
            return new ZumoTest(testName, async delegate(ZumoTest test)
            {
                var client = ZumoTestGlobals.Instance.Client;
                var table = client.GetTable<VersionedType>();
                DateTime now = DateTime.UtcNow;
                int seed = now.Year * 10000 + now.Month * 100 + now.Day;
                test.AddLog("Using seed: {0}", seed);
                Random rndGen = new Random(seed);
                var item = new VersionedType(rndGen);
                await table.InsertAsync(item);
                test.AddLog("[client 1] Inserted item: {0}", item);

                var client2 = new MobileServiceClient(client.ApplicationUri, client.ApplicationKey);
                var table2 = client.GetTable<VersionedType>();
                var item2 = await table2.LookupAsync(item.Id);
                test.AddLog("[client 2] Retrieved the item");
                item2.Name = Util.CreateSimpleRandomString(rndGen, 20);
                item2.Number = rndGen.Next(100000);
                test.AddLog("[client 2] Updated the item, will update on the server now");
                await table2.UpdateAsync(item2);
                test.AddLog("[client 2] Item has been updated: {0}", item2);

                test.AddLog("[client 1] Will try to update; should fail");
                MobileServicePreconditionFailedException<VersionedType> ex = null;
                try
                {
                    item.Name = Util.CreateSimpleRandomString(rndGen, 20);
                    await table.UpdateAsync(item);
                    test.AddLog("[client 1] Error, the update succeeded, but it should have failed. Item = {0}", item);
                    return false;
                }
                catch (MobileServicePreconditionFailedException<VersionedType> e)
                {
                    test.AddLog("[client 1] Received expected exception; server item = {0}", e.Item);
                    ex = e;
                }

                var serverItem = ex.Item;
                if (serverItem.Version != item2.Version)
                {
                    test.AddLog("[client 1] Error, server item's version is not the same as the second item version");
                    return false;
                }

                var cachedMergedItem = mergingPolicy(item, serverItem);
                var mergedItem = mergingPolicy(item, serverItem);
                test.AddLog("[client 1] Merged item: {0}", mergedItem);
                test.AddLog("[client 1] Trying to update it again, should succeed this time");

                await table.UpdateAsync(mergedItem);
                test.AddLog("[client 1] Updated the item: {0}", mergedItem);

                if (!cachedMergedItem.Equals(mergedItem))
                {
                    test.AddLog("[client 1] Error, the server version of the merged item doesn't match the client one");
                    return false;
                }

                test.AddLog("[client 2] Refreshing the item");
                await table2.RefreshAsync(item2);
                test.AddLog("[client 2] Refreshed the item: {0}", item2);

                if (!item2.Equals(mergedItem))
                {
                    test.AddLog("[client] Error, item is different than the item from the client 1");
                    return false;
                }

                return true;
            });
        }
        private static ZumoTest CreateOptimisticConcurrencyWithServerConflictsTest(string testName, bool clientWins)
        {
            return new ZumoTest(testName, async delegate(ZumoTest test)
            {
                var client = ZumoTestGlobals.Instance.Client;
                var table = client.GetTable<VersionedType>();
                DateTime now = DateTime.UtcNow;
                int seed = now.Year * 10000 + now.Month * 100 + now.Day;
                test.AddLog("Using seed: {0}", seed);
                Random rndGen = new Random(seed);
                var item = new VersionedType(rndGen);
                await table.InsertAsync(item);
                test.AddLog("[client 1] Inserted item: {0}", item);

                var client2 = new MobileServiceClient(client.ApplicationUri, client.ApplicationKey);
                var table2 = client.GetTable<VersionedType>();
                var item2 = await table2.LookupAsync(item.Id);
                test.AddLog("[client 2] Retrieved the item");
                item2.Name = Util.CreateSimpleRandomString(rndGen, 20);
                item2.Number = rndGen.Next(100000);
                test.AddLog("[client 2] Updated the item, will update on the server now");
                await table2.UpdateAsync(item2);
                test.AddLog("[client 2] Item has been updated: {0}", item2);

                test.AddLog("[client 1] Will try to update - using policy that data on {0} wins", clientWins ? "client" : "server");
                string oldName = item2.Name;
                string newName = Util.CreateSimpleRandomString(rndGen, 20);
                item.Name = newName;
                await table.UpdateAsync(item, new Dictionary<string, string> { { "conflictPolicy", clientWins ? "clientWins" : "serverWins" } });
                test.AddLog("[client 1] Updated the item: {0}", item);

                test.AddLog("[client 2] Now refreshing the second item");
                await table2.RefreshAsync(item2);
                test.AddLog("[client 2] Refreshed: {0}", item2);
                if (clientWins)
                {
                    // The name should be the new one
                    if (item.Name != newName || item2.Name != newName)
                    {
                        test.AddLog("Error, name wasn't updated in a 'client wins' policy");
                        return false;
                    }
                }
                else
                {
                    // The name should have remained the old one
                    if (item.Name != oldName || item2.Name != oldName)
                    {
                        test.AddLog("Error, name was updated in a 'server wins' policy");
                        return false;
                    }
                }

                test.AddLog("Table operations behaved as expected. Cleaning up...");
                await table.DeleteAsync(item);
                test.AddLog("...done");
                return true;
            });
        }