Example #1
0
        public async Task HandleEventDeltaResponseWithRemovedItem()
        {
            // Arrange
            var deltaResponseHandler = new DeltaResponseHandler();

            // Result string with one removed item.
            var testString = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Collection(event)\",\"@odata.nextLink\":\"https://graph.microsoft.com/v1.0/me/calendarView/delta?$skiptoken=R0usmci39OQxqJrxK4\",\"value\":[{\"@removed\":{\"reason\":\"removed\"},\"id\":\"AAMkADVxTAAA=\"}]}";

            var hrm = new HttpResponseMessage()
            {
                Content = new StringContent(testString,
                                            Encoding.UTF8,
                                            "application/json")
            };

            // Act
            var deltaServiceLibResponse = await deltaResponseHandler.HandleResponse <EventDeltaCollectionResponse>(hrm);

            var eventsDeltaCollectionPage = deltaServiceLibResponse.Value as CollectionPage <Event>;

            eventsDeltaCollectionPage[0].AdditionalData.TryGetValue("changes", out object changes);
            var changeList = (changes as JArray).ToObject <List <string> >();

            // Assert
            Assert.True(changeList.Exists(x => x.Equals("@removed.reason")));
        }
Example #2
0
        public async Task HandleEventDeltaResponseWithEmptyCollectionPage()
        {
            // Arrange
            var deltaResponseHandler = new DeltaResponseHandler();
            var odataContext         = @"https://graph.microsoft.com/v1.0/$metadata#Collection(event)";
            var odataDeltalink       = @"https://graph.microsoft.com/v1.0/me/mailfolders/inbox/messages/delta?$deltatoken=LztZwWjo5IivWBhyxw5rACKxf7mPm0oW6JZZ7fvKxYPS_67JnEYmfQQMPccy6FRun0DWJF5775dvuXxlZnMYhBubC1v4SBVT9ZjO8f7acZI.uCdGKSBS4YxPEbn_Q5zxLSq91WhpGoz9ZKeNZHMWgSA";


            // Empty result
            var testString = "{\"@odata.context\":\"" + odataContext + "\",\"@odata.deltaLink\":\"" + odataDeltalink + "\",\"value\":[]}";

            var hrm = new HttpResponseMessage()
            {
                Content = new StringContent(testString,
                                            Encoding.UTF8,
                                            "application/json")
            };

            // Act
            var deltaJObjectResponse = await deltaResponseHandler.HandleResponse <JObject>(hrm);

            var hasItems = deltaJObjectResponse["value"].HasValues;
            var odataContextFromJObject   = deltaJObjectResponse["@odata.context"].ToString();
            var odataDeltalinkFromJObject = deltaJObjectResponse["@odata.deltaLink"].ToString();

            Assert.False(hasItems);                                  // We don't expect items in an empty collection page
            Assert.Equal(odataContext, odataContextFromJObject);     // We expect that the odata.context isn't transformed.
            Assert.Equal(odataDeltalink, odataDeltalinkFromJObject); // We expect that the odata.deltalink isn't transformed.
        }
Example #3
0
        public async Task HandleEventDeltaResponseWithArrayOfPrimitives()
        {
            // Arrange
            var deltaResponseHandler = new DeltaResponseHandler();

            // Contains string, int, and boolean arrays.
            var testString = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Collection(user)\",\"@odata.nextLink\":\"https://graph.microsoft.com/v1.0/users/delta?$skiptoken=R0usmci39O\",\"value\":[{\"id\":\"AAMkADVxTAAA=\",\"arrayOfString\":[\"SMTP:[email protected]\",\"SMTP:[email protected]\"]},{\"id\":\"AAMkADVxUAAA=\",\"arrayOfBool\":[true,false]},{\"id\":\"AAMkADVxVAAA=\",\"arrayOfInt\":[2,5]}]}";

            var hrm = new HttpResponseMessage()
            {
                Content = new StringContent(testString,
                                            Encoding.UTF8,
                                            "application/json")
            };

            // Act
            var deltaServiceLibResponse = await deltaResponseHandler.HandleResponse <EventDeltaCollectionResponse>(hrm);

            var deltaJObjectResponse = await deltaResponseHandler.HandleResponse <JObject>(hrm);

            string actualStringValue = (string)deltaJObjectResponse.SelectToken("value[0].arrayOfString[0]");
            bool   actualBoolValue   = Convert.ToBoolean((string)deltaJObjectResponse.SelectToken("value[1].arrayOfBool[1]"));
            int    actualIntValue    = Convert.ToInt32((string)deltaJObjectResponse.SelectToken("value[2].arrayOfInt[1]"));

            string arrayOfString = (string)deltaJObjectResponse.SelectToken("value[0].changes[2]");
            string arrayOfBool   = (string)deltaJObjectResponse.SelectToken("value[1].changes[2]");
            string arrayOfInt    = (string)deltaJObjectResponse.SelectToken("value[2].changes[2]");

            // Assert that it actually deserialized into a model we expect.
            Assert.True(deltaServiceLibResponse.Value is IEventDeltaCollectionPage); // We create a valid ICollectionPage.

            // Assert that the value is set.
            Assert.Equal("SMTP:[email protected]", actualStringValue);
            Assert.False(actualBoolValue);
            Assert.Equal(5, actualIntValue);

            // Assert that the change manifest is set.
            Assert.Equal("arrayOfString[1]", arrayOfString); // The third change is the second string array item.
            Assert.Equal("arrayOfBool[1]", arrayOfBool);
            Assert.Equal("arrayOfInt[1]", arrayOfInt);
        }
Example #4
0
        public async Task HandleEventDeltaResponse()
        {
            // Arrange
            var deltaResponseHandler = new DeltaResponseHandler();

            // TestString represents a page of results with a nextLink. There are two changed events.
            // The events have key:value properties, key:object properties, and key:array properties.
            // To view and format this test string, replace all \" with ", and use a JSON formatter
            // to make it pretty.
            var testString = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Collection(event)\",\"@odata.nextLink\":\"https://graph.microsoft.com/v1.0/me/calendarView/delta?$skiptoken=R0usmci39OQxqJrxK4\",\"value\":[{\"@odata.type\":\"#microsoft.graph.event\",\"@odata.etag\":\"EZ9r3czxY0m2jz8c45czkwAAFXcvIw==\",\"subject\":\"Get food\",\"body\":{\"contentType\":\"html\",\"content\":\"\"},\"start\":{\"dateTime\":\"2016-12-10T19:30:00.0000000\",\"timeZone\":\"UTC\"},\"end\":{\"dateTime\":\"2016-12-10T21:30:00.0000000\",\"timeZone\":\"UTC\"},\"attendees\":[{\"emailAddress\":{\"name\":\"George\",\"address\":\"[email protected]\"}},{\"emailAddress\":{\"name\":\"Jane\",\"address\":\"[email protected]\"}}],\"organizer\":{\"emailAddress\":{\"name\":\"Samantha Booth\",\"address\":\"[email protected]\"}},\"id\":\"AAMkADVxTAAA=\"},{\"@odata.type\":\"#microsoft.graph.event\",\"@odata.etag\":\"WEZ9r3czxY0m2jz8c45czkwAAFXcvJA==\",\"subject\":\"Prepare food\",\"body\":{\"contentType\":\"html\",\"content\":\"\"},\"start\":{\"dateTime\":\"2016-12-10T22:00:00.0000000\",\"timeZone\":\"UTC\"},\"end\":{\"dateTime\":\"2016-12-11T00:00:00.0000000\",\"timeZone\":\"UTC\"},\"attendees\":[],\"organizer\":{\"emailAddress\":{\"name\":\"Samantha Booth\",\"address\":\"[email protected]\"}},\"id\":\"AAMkADVxUAAA=\"}]}";

            var hrm = new HttpResponseMessage()
            {
                Content = new StringContent(testString,
                                            Encoding.UTF8,
                                            "application/json")
            };

            // Act
            var deltaServiceLibResponse = await deltaResponseHandler.HandleResponse <EventDeltaCollectionResponse>(hrm);

            var deltaJObjectResponse = await deltaResponseHandler.HandleResponse <JObject>(hrm);

            string attendeeName             = (string)deltaJObjectResponse.SelectToken("value[0].attendees[0].emailAddress.name");
            string attendeeNameInChangelist = (deltaJObjectResponse["value"][0]["changes"] as JArray)[9].ToString();
            var    collectionPage           = deltaServiceLibResponse.Value as CollectionPage <Event>;
            var    collectionPageHasChanges = collectionPage[0].AdditionalData.TryGetValue("changes", out object obj);

            // IEventDeltaCollectionPage is what the service library provides.
            // Can't test against the service library model, since it has a reference to the signed
            // public version of this library. see issue #57 for more info.
            // https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/57
            // Service library testing will need to happen in the service library repo once this is published on NuGet.

            // Assert
            Assert.True(deltaServiceLibResponse.Value is IEventDeltaCollectionPage);  // We create a valid ICollectionPage.
            Assert.Equal("George", attendeeName);                                     // We maintain the expected response body when we change it.
            Assert.Equal("attendees[0].emailAddress.name", attendeeNameInChangelist); // We expect that this property is in changelist.
            Assert.True(collectionPageHasChanges);                                    // We expect that the CollectionPage is populated with the changes.
        }
Example #5
0
        public async Task HandleEventDeltaResponseWithNullValues()
        {
            // Arrange
            var deltaResponseHandler = new DeltaResponseHandler();

            // TestString represents a page of results with a nextLink. There are two changed events.
            // The events have key:value properties, key:object properties, and key:array properties.
            // To view and format this test string, replace all \" with ", and use a JSON formatter
            // to make it pretty.
            // value[0].subject == null
            var testString = "{\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#Collection(event)\",\"@odata.nextLink\":\"https://graph.microsoft.com/v1.0/me/calendarView/delta?$skiptoken=R0usmci39OQxqJrxK4\",\"value\":[{\"@odata.type\":\"#microsoft.graph.event\",\"@odata.etag\":\"EZ9r3czxY0m2jz8c45czkwAAFXcvIw==\",\"subject\":null,\"body\":{\"contentType\":\"html\",\"content\":\"<p>Updated content</p>\"},\"start\":{\"dateTime\":\"2016-12-10T19:30:00.0000000\",\"timeZone\":\"UTC\"},\"end\":{\"dateTime\":\"2016-12-10T21:30:00.0000000\",\"timeZone\":\"UTC\"},\"attendees\":[{\"emailAddress\":{\"name\":\"George\",\"address\":\"[email protected]\"}},{\"emailAddress\":{\"name\":\"Jane\",\"address\":\"[email protected]\"}}],\"organizer\":{\"emailAddress\":{\"name\":\"Samantha Booth\",\"address\":\"[email protected]\"}},\"id\":\"AAMkADVxTAAA=\"},{\"@odata.type\":\"#microsoft.graph.event\",\"@odata.etag\":\"WEZ9r3czxY0m2jz8c45czkwAAFXcvJA==\",\"subject\":\"Prepare food\",\"body\":{\"contentType\":\"html\",\"content\":\"\"},\"start\":{\"dateTime\":\"2016-12-10T22:00:00.0000000\",\"timeZone\":\"UTC\"},\"end\":{\"dateTime\":\"2016-12-11T00:00:00.0000000\",\"timeZone\":\"UTC\"},\"attendees\":[],\"organizer\":{\"emailAddress\":{\"name\":\"Samantha Booth\",\"address\":\"[email protected]\"}},\"id\":\"AAMkADVxUAAA=\"}]}";

            var hrm = new HttpResponseMessage()
            {
                Content = new StringContent(testString,
                                            Encoding.UTF8,
                                            "application/json")
            };

            // Assuming this is the developers model that they want to update based on delta query.
            Event myModel = new Event()
            {
                Subject = "Original subject",
                Body    = new ItemBody()
                {
                    Content     = "Original body",
                    ContentType = BodyType.Text
                },
                AdditionalData = new Dictionary <string, object>()
            };

            // Act
            var deltaServiceLibResponse = await deltaResponseHandler.HandleResponse <EventDeltaCollectionResponse>(hrm);

            var eventsDeltaCollectionPage = deltaServiceLibResponse.Value as CollectionPage <Event>;

            eventsDeltaCollectionPage[0].AdditionalData.TryGetValue("changes", out object changes);
            var changeList = (changes as JArray).ToObject <List <string> >();

            // Updating a non-schematized property on a model such as instance annotations, open types,
            // and schema extensions. We can assume that a customer's  model would not use a dictionary.
            if (changeList.Exists(x => x.Equals("@odata.etag")))
            {
                eventsDeltaCollectionPage[0].AdditionalData.TryGetValue("@odata.etag", out object odataEtag);
                myModel.AdditionalData["@odata.etag"] = odataEtag.ToString();
            }

            // Core scenario - update schematized property regardless of it is set to null.
            // This property has been set to null in the response. We can be confident that
            // whatever the value set is correct, regardless whether it is null.
            if (changeList.Exists(x => x.Equals("subject")))
            {
                myModel.Subject = eventsDeltaCollectionPage[0].Subject;
            }

            // Update the value on a complex type property's value. Developer can't just replace the body
            // as that could result in overwriting other unchanged property. Essentially, they need to inspect
            // every leaf node in the selected property set.
            if (changeList.Exists(x => x.Equals("body.content"))) //
            {
                if (myModel.Body == null)
                {
                    myModel.Body = new ItemBody();
                }

                myModel.Body.Content = eventsDeltaCollectionPage[0].Body.Content;
            }

            // Update complex type property's value when the value is a collection of objects.
            // We don't know whether this is an update or add without querying the client model.
            // We will need to check each object in the model.
            var attendeesChangelist = changeList.FindAll(x => x.Contains("attendees"));

            if (attendeesChangelist.Count > 0)
            {
                // This is where if we provided the delta response as a JSON object,
                // we could let the developer use JMESPath to query the changes.
                if (changeList.Exists(x => x.Equals("attendees[0].emailAddress.name")))
                {
                    if (myModel.Attendees == null) // Attendees are being added for the first time.
                    {
                        var attendees = new List <Attendee>();
                        attendees.AddRange(eventsDeltaCollectionPage[0].Attendees);
                        myModel.Attendees = attendees;
                    }
                    else // Attendees list is being updated.
                    {
                        // We need to inspect each object, and determine which objects and properties
                        // need to be initialized and/or updated.
                    }
                }
            }

            Assert.NotNull(changeList);
            Assert.Null(myModel.Subject);
            Assert.Equal("<p>Updated content</p>", myModel.Body.Content);
            Assert.NotNull(eventsDeltaCollectionPage[0].AdditionalData["@odata.etag"]);
            Assert.Collection(myModel.Attendees,
                              attendee1 =>
            {
                Assert.Equal("George", attendee1.EmailAddress.Name);
                Assert.Equal("*****@*****.**", attendee1.EmailAddress.Address);
            },
                              attendee2 =>
            {
                Assert.Equal("Jane", attendee2.EmailAddress.Name);
                Assert.Equal("*****@*****.**", attendee2.EmailAddress.Address);
            }
                              );
        }