Exemplo n.º 1
0
        public async Task Query_PaginationWorks()
        {
            DigitalTwinsClient client = GetClient();
            int    pageSize           = 5;
            string floorModelId       = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            TimeSpan QueryWaitTimeout = TimeSpan.FromMinutes(1); // Wait at most one minute for the created twins to become queryable

            try
            {
                // Create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await CreateAndListModelsAsync(client, new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // Create a room twin, with property "IsOccupied": true
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);

                for (int i = 0; i < pageSize * 2; i++)
                {
                    string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

                    await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);
                }

                string queryString = "SELECT * FROM digitaltwins";

                // act
                CancellationTokenSource queryTimeoutCancellationToken = new CancellationTokenSource(QueryWaitTimeout);
                bool queryHasExpectedCount = false;
                while (!queryHasExpectedCount)
                {
                    if (queryTimeoutCancellationToken.IsCancellationRequested)
                    {
                        throw new AssertionException($"Timed out waiting for at least {pageSize + 1} twins to be queryable");
                    }

                    AsyncPageable <BasicDigitalTwin> asyncPageableResponse = client.QueryAsync <BasicDigitalTwin>(queryString, queryTimeoutCancellationToken.Token);
                    int count = 0;
                    await foreach (Page <BasicDigitalTwin> queriedTwinPage in asyncPageableResponse.AsPages(pageSizeHint: pageSize))
                    {
                        count += queriedTwinPage.Values.Count;
                    }

                    // Once at least (page + 1) twins are query-able, then page size control can be tested.
                    queryHasExpectedCount = count >= pageSize + 1;
                }

                // assert
                // Test that page size hint works, and that all returned pages either have the page size hint amount of
                // elements, or have no continuation token (signaling that it is the last page)
                int pageCount = 0;
                await foreach (Page <BasicDigitalTwin> page in client.QueryAsync <BasicDigitalTwin>(queryString).AsPages(pageSizeHint: pageSize))
                {
                    pageCount++;
                    if (page.ContinuationToken != null)
                    {
                        page.Values.Count.Should().Be(pageSize, "Unexpected page size for a non-terminal page");
                    }
                }

                pageCount.Should().BeGreaterThan(1, "Expected more than one page of query results");
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Creates two digital twins, and connect them with relationships.
        /// </summary>
        public async Task RunSamplesAsync(DigitalTwinsClient client)
        {
            // For the purpose of keeping code snippets readable to the user, hardcoded string literals are used in place of assigned variables, eg Ids.
            // Despite not being a good code practice, this prevents code snippets from being out of context for the user when making API calls that accept Ids as parameters.

            PrintHeader("RELATIONSHIP SAMPLE");

            // Create a building digital twin model.
            string buildingModelPayload = SamplesConstants.TemporaryModelWithRelationshipPayload
                                          .Replace(SamplesConstants.ModelId, "dtmi:samples:SampleBuilding;1")
                                          .Replace(SamplesConstants.ModelDisplayName, "Building")
                                          .Replace(SamplesConstants.RelationshipName, "contains")
                                          .Replace(SamplesConstants.RelationshipTargetModelId, "dtmi:samples:SampleFloor;1");

            Response <IReadOnlyList <Models.ModelData> > createBuildingModelResponse = await client.CreateModelsAsync(
                new[]
            {
                buildingModelPayload
            });

            Console.WriteLine($"Created model with Id dtmi:samples:SampleBuilding;1. Response status: {createBuildingModelResponse.GetRawResponse().Status}.");

            // Create a floor digital twin model.
            string floorModelPayload = SamplesConstants.TemporaryModelWithRelationshipPayload
                                       .Replace(SamplesConstants.ModelId, "dtmi:samples:SampleFloor;1")
                                       .Replace(SamplesConstants.ModelDisplayName, "Floor")
                                       .Replace(SamplesConstants.RelationshipName, "containedIn")
                                       .Replace(SamplesConstants.RelationshipTargetModelId, "dtmi:samples:SampleBuilding;1");

            Response <IReadOnlyList <Models.ModelData> > createFloorModelResponse = await client.CreateModelsAsync(
                new[]
            {
                floorModelPayload
            });

            Console.WriteLine($"Created model with Id dtmi:samples:SampleFloor;1. Response status: {createFloorModelResponse.GetRawResponse().Status}.");

            // Create a building digital twin.
            var buildingDigitalTwin = new BasicDigitalTwin
            {
                Id       = "buildingTwinId",
                Metadata = { ModelId = "dtmi:samples:SampleBuilding;1" }
            };

            string            buildingDigitalTwinPayload        = JsonSerializer.Serialize(buildingDigitalTwin);
            Response <string> createBuildingDigitalTwinResponse = await client.CreateDigitalTwinAsync("buildingTwinId", buildingDigitalTwinPayload);

            Console.WriteLine($"Created a digital twin with Id buildingTwinId. Response status: {createBuildingDigitalTwinResponse.GetRawResponse().Status}.");

            // Create a floor digital.
            var floorDigitalTwin = new BasicDigitalTwin
            {
                Id       = "floorTwinId",
                Metadata = { ModelId = "dtmi:samples:SampleFloor;1" }
            };

            string            floorDigitalTwinPayload        = JsonSerializer.Serialize(floorDigitalTwin);
            Response <string> createFloorDigitalTwinResponse = await client.CreateDigitalTwinAsync("floorTwinId", floorDigitalTwinPayload);

            Console.WriteLine($"Created a digital twin with Id floorTwinId. Response status: {createFloorDigitalTwinResponse.GetRawResponse().Status}.");

            // Create a relationship between building and floor using the BasicRelationship serialization helper.
            #region Snippet:DigitalTwinsSampleCreateBasicRelationship

            var buildingFloorRelationshipPayload = new BasicRelationship
            {
                Id               = "buildingFloorRelationshipId",
                SourceId         = "buildingTwinId",
                TargetId         = "floorTwinId",
                Name             = "contains",
                CustomProperties =
                {
                    { "Prop1", "Prop1 value" },
                    { "Prop2",             6 }
                }
            };

            string            serializedRelationship     = JsonSerializer.Serialize(buildingFloorRelationshipPayload);
            Response <string> createRelationshipResponse = await client.CreateRelationshipAsync("buildingTwinId", "buildingFloorRelationshipId", serializedRelationship);

            Console.WriteLine($"Created a digital twin relationship with Id buildingFloorRelationshipId from digital twin with Id buildingTwinId to digital twin with Id floorTwinId. " +
                              $"Response status: {createRelationshipResponse.GetRawResponse().Status}.");

            #endregion Snippet:DigitalTwinsSampleCreateBasicRelationship

            // You can get a relationship and deserialize it into a BasicRelationship.
            #region Snippet:DigitalTwinsSampleGetBasicRelationship

            Response <string> getBasicRelationshipResponse = await client.GetRelationshipAsync("buildingTwinId", "buildingFloorRelationshipId");

            if (getBasicRelationshipResponse.GetRawResponse().Status == (int)HttpStatusCode.OK)
            {
                BasicRelationship basicRelationship = JsonSerializer.Deserialize <BasicRelationship>(getBasicRelationshipResponse.Value);
                Console.WriteLine($"Retrieved relationship with Id {basicRelationship.Id} from digital twin with Id {basicRelationship.SourceId}. " +
                                  $"Response status: {getBasicRelationshipResponse.GetRawResponse().Status}.\n\t" +
                                  $"Prop1: {basicRelationship.CustomProperties["Prop1"]}\n\t" +
                                  $"Prop2: {basicRelationship.CustomProperties["Prop2"]}");
            }

            #endregion Snippet:DigitalTwinsSampleGetBasicRelationship

            // Alternatively, you can create your own custom data types to serialize and deserialize your relationships.
            // This requires less code or knowledge of the type for interaction.

            // Create a relationship between floorTwinId and buildingTwinId using a custom data type.
            #region Snippet:DigitalTwinsSampleCreateCustomRelationship

            var floorBuildingRelationshipPayload = new CustomRelationship
            {
                Id       = "floorBuildingRelationshipId",
                SourceId = "floorTwinId",
                TargetId = "buildingTwinId",
                Name     = "containedIn",
                Prop1    = "Prop1 val",
                Prop2    = 4
            };
            string serializedCustomRelationship = JsonSerializer.Serialize(floorBuildingRelationshipPayload);

            Response <string> createCustomRelationshipResponse = await client.CreateRelationshipAsync("floorTwinId", "floorBuildingRelationshipId", serializedCustomRelationship);

            Console.WriteLine($"Created a digital twin relationship with Id floorBuildingRelationshipId from digital twin with Id floorTwinId to digital twin with Id buildingTwinId. " +
                              $"Response status: {createCustomRelationshipResponse.GetRawResponse().Status}.");

            #endregion Snippet:DigitalTwinsSampleCreateCustomRelationship

            // Getting and deserializing a relationship into a custom data type is extremely easy.
            #region Snippet:DigitalTwinsSampleGetCustomRelationship

            Response <string> getCustomRelationshipResponse = await client.GetRelationshipAsync("floorTwinId", "floorBuildingRelationshipId");

            if (getCustomRelationshipResponse.GetRawResponse().Status == (int)HttpStatusCode.OK)
            {
                CustomRelationship getCustomRelationship = JsonSerializer.Deserialize <CustomRelationship>(getCustomRelationshipResponse.Value);
                Console.WriteLine($"Retrieved and deserialized relationship with Id {getCustomRelationship.Id} from digital twin with Id {getCustomRelationship.SourceId}. " +
                                  $"Response status: {getCustomRelationshipResponse.GetRawResponse().Status}.\n\t" +
                                  $"Prop1: {getCustomRelationship.Prop1}\n\t" +
                                  $"Prop2: {getCustomRelationship.Prop2}");
            }

            #endregion Snippet:DigitalTwinsSampleGetCustomRelationship

            // Get all relationships in the graph where buildingTwinId is the source of the relationship.
            #region Snippet:DigitalTwinsSampleGetAllRelationships

            AsyncPageable <string> relationships = client.GetRelationshipsAsync("buildingTwinId");

            await foreach (var relationshipJson in relationships)
            {
                BasicRelationship relationship = JsonSerializer.Deserialize <BasicRelationship>(relationshipJson);
                Console.WriteLine($"Found relationship with Id {relationship.Id} with a digital twin source Id {relationship.SourceId} and " +
                                  $"a digital twin target Id {relationship.TargetId}. \n\t " +
                                  $"Prop1: {relationship.CustomProperties["Prop1"]}\n\t" +
                                  $"Prop2: {relationship.CustomProperties["Prop2"]}");
            }

            #endregion Snippet:DigitalTwinsSampleGetAllRelationships

            // Get all incoming relationships in the graph where buildingTwinId is the target of the relationship.
            #region Snippet:DigitalTwinsSampleGetIncomingRelationships

            AsyncPageable <IncomingRelationship> incomingRelationships = client.GetIncomingRelationshipsAsync("buildingTwinId");

            await foreach (IncomingRelationship incomingRelationship in incomingRelationships)
            {
                Console.WriteLine($"Found an incoming relationship with Id {incomingRelationship.RelationshipId} coming from a digital twin with Id {incomingRelationship.SourceId}.");
            }

            #endregion Snippet:DigitalTwinsSampleGetIncomingRelationships

            // Delete the contains relationship, created earlier in the sample code, from building to floor.

            #region Snippet:DigitalTwinsSampleDeleteRelationship

            Response deleteBuildingRelationshipResponse = await client.DeleteRelationshipAsync("buildingTwinId", "buildingFloorRelationshipId");

            Console.WriteLine($"Deleted relationship with Id buildingFloorRelationshipId. Status response: {deleteBuildingRelationshipResponse.Status}.");

            #endregion Snippet:DigitalTwinsSampleDeleteRelationship

            // Delete the containedIn relationship, created earlier in the sample code, from floor to building.
            Response deleteFloorRelationshipResponse = await client.DeleteRelationshipAsync("floorTwinId", "floorBuildingRelationshipId");

            Console.WriteLine($"Deleted relationship with Id floorBuildingRelationshipId. Status response: {deleteFloorRelationshipResponse.Status}.");

            // Clean up.
            try
            {
                // Delete all twins
                await client.DeleteDigitalTwinAsync("buildingTwinId");

                await client.DeleteDigitalTwinAsync("floorTwinId");
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete digital twin due to {ex}.");
            }

            try
            {
                await client.DeleteModelAsync("dtmi:samples:SampleBuilding;1");

                await client.DeleteModelAsync("dtmi:samples:SampleFloor;1");
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete model due to {ex}.");
            }
        }
        public async Task PublishTelemetry_Lifecycle()
        {
            // Setup

            // Create a DigitalTwinsClient instance.
            DigitalTwinsClient client = GetClient();

            string wifiComponentName = "wifiAccessPoint";
            string wifiModelId       = await GetUniqueModelIdAsync(client, TestAssetDefaults.WifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomWithWifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomWithWifiTwinIdPrefix).ConfigureAwait(false);

            string eventRouteId = $"someEventRouteId-{GetRandom()}";

            try
            {
                // Create an event route for the digital twins client.
                DigitalTwinsEventRoute eventRoute = await CreateEventRoute(client, eventRouteId).ConfigureAwait(false);

                // Create the models needed for the digital twin.
                await CreateModelsAndTwins(client, wifiModelId, roomWithWifiModelId, wifiComponentName, roomWithWifiTwinId).ConfigureAwait(false);

                // Act - Test publishing telemetry to a digital twin.
                var telemetryOptions = new PublishTelemetryOptions()
                {
                    TimeStamp = default
                };
                Response publishTelemetryResponse = await client.PublishTelemetryAsync(roomWithWifiTwinId, Recording.Random.NewGuid().ToString(), "{\"Telemetry1\": 5}", telemetryOptions).ConfigureAwait(false);

                // Assert
                publishTelemetryResponse.Status.Should().Be((int)HttpStatusCode.NoContent);

                // Act - Test publishing telemetry to a component in a digital twin.
                var componentTelemetryOptions = new PublishComponentTelemetryOptions()
                {
                    TimeStamp = default
                };
                var telemetryPayload = new Dictionary <string, int>
                {
                    { "ComponentTelemetry1", 9 }
                };
                Response publishComponentTelemetryResponse = await client
                                                             .PublishComponentTelemetryAsync(roomWithWifiTwinId, wifiComponentName, Recording.Random.NewGuid().ToString(), JsonSerializer.Serialize(telemetryPayload), componentTelemetryOptions)
                                                             .ConfigureAwait(false);

                // Assert
                publishComponentTelemetryResponse.Status.Should().Be((int)HttpStatusCode.NoContent);
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(eventRouteId))
                    {
                        await client.DeleteEventRouteAsync(eventRouteId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(roomWithWifiTwinId))
                    {
                        await client.DeleteDigitalTwinAsync(roomWithWifiTwinId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(roomWithWifiModelId))
                    {
                        await client.DeleteModelAsync(roomWithWifiModelId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(wifiModelId))
                    {
                        await client.DeleteModelAsync(wifiModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 4
0
        public async Task Component_UpdateComponentFailsWhenIfMatchHeaderOutOfDate()
        {
            // arrange

            DigitalTwinsClient client = GetClient();

            string wifiModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.WifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomWithWifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomWithWifiTwinIdPrefix).ConfigureAwait(false);

            string wifiComponentName = "wifiAccessPoint";

            try
            {
                // CREATE

                // create roomWithWifi model
                string wifiModel = TestAssetsHelper.GetWifiModelPayload(wifiModelId);

                // create wifi model
                string roomWithWifiModel = TestAssetsHelper.GetRoomWithWifiModelPayload(roomWithWifiModelId, wifiModelId, wifiComponentName);

                await CreateAndListModelsAsync(client, new List <string> {
                    roomWithWifiModel, wifiModel
                }).ConfigureAwait(false);

                // create room digital twin
                BasicDigitalTwin roomWithWifiTwin = TestAssetsHelper.GetRoomWithWifiTwinPayload(roomWithWifiModelId, wifiComponentName);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomWithWifiTwinId, roomWithWifiTwin);

                // Get the component
                Response <object> getComponentResponse = await client
                                                         .GetComponentAsync <object>(
                    roomWithWifiTwinId,
                    wifiComponentName)
                                                         .ConfigureAwait(false);

                ETag?etagBeforeUpdate = (await client.GetDigitalTwinAsync <BasicDigitalTwin>(roomWithWifiTwinId)).Value.ETag;

                // Patch component
                JsonPatchDocument componentUpdatePatchDocument = new JsonPatchDocument();
                componentUpdatePatchDocument.AppendReplace("/Network", "New Network");

                Response updateComponentResponse = await client
                                                   .UpdateComponentAsync(
                    roomWithWifiTwinId,
                    wifiComponentName,
                    componentUpdatePatchDocument)
                                                   .ConfigureAwait(false);

                // Patch component again, but with the now out of date ETag
                JsonPatchDocument secondComponentUpdatePatchDocument = new JsonPatchDocument();
                secondComponentUpdatePatchDocument.AppendReplace("/Network", "Even newer Network");

                Func <Task> act = async() =>
                {
                    await client
                    .UpdateComponentAsync(
                        roomWithWifiTwinId,
                        wifiComponentName,
                        secondComponentUpdatePatchDocument,
                        etagBeforeUpdate)
                    .ConfigureAwait(false);
                };

                act.Should().Throw <RequestFailedException>()
                .And.Status.Should().Be((int)HttpStatusCode.PreconditionFailed);
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomWithWifiTwinId))
                    {
                        await client.DeleteDigitalTwinAsync(roomWithWifiTwinId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(roomWithWifiModelId))
                    {
                        await client.DeleteModelAsync(roomWithWifiModelId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(wifiModelId))
                    {
                        await client.DeleteModelAsync(wifiModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 5
0
        public async Task DigitalTwins_Lifecycle()
        {
            DigitalTwinsClient client = GetClient();

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await client.CreateModelsAsync(new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // act

                // create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                // get twin
                await client.GetDigitalTwinAsync <BasicDigitalTwin>(roomTwinId).ConfigureAwait(false);

                // update twin
                JsonPatchDocument updateTwinPatchDocument = new JsonPatchDocument();
                updateTwinPatchDocument.AppendAdd("/Humidity", 30);
                updateTwinPatchDocument.AppendReplace("/Temperature", 70);
                updateTwinPatchDocument.AppendRemove("/EmployeeId");

                var requestOptions = new UpdateDigitalTwinOptions
                {
                    IfMatch = "*"
                };

                await client.UpdateDigitalTwinAsync(roomTwinId, updateTwinPatchDocument, requestOptions).ConfigureAwait(false);

                // delete a twin
                await client.DeleteDigitalTwinAsync(roomTwinId).ConfigureAwait(false);

                // assert
                Func <Task> act = async() =>
                {
                    await client.GetDigitalTwinAsync <BasicDigitalTwin>(roomTwinId).ConfigureAwait(false);
                };

                act.Should().Throw <RequestFailedException>()
                .And.Status.Should().Be((int)HttpStatusCode.NotFound);
            }
            finally
            {
                // cleanup
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 6
0
        public async Task Component_Lifecycle()
        {
            // arrange

            DigitalTwinsClient client = GetClient();

            string wifiModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.WifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.RoomWithWifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiTwinId = await GetUniqueTwinIdAsync(client, TestAssetSettings.RoomWithWifiTwinIdPrefix).ConfigureAwait(false);

            string wifiComponentName = "wifiAccessPoint";

            try
            {
                // CREATE

                // create roomWithWifi model
                string wifiModel = TestAssetsHelper.GetWifiModelPayload(wifiModelId);

                // create wifi model
                string roomWithWifiModel = TestAssetsHelper.GetRoomWithWifiModelPayload(roomWithWifiModelId, wifiModelId, wifiComponentName);

                await client.CreateModelsAsync(new List <string> {
                    roomWithWifiModel, wifiModel
                }).ConfigureAwait(false);

                // create room digital twin
                string roomWithWifiTwin = TestAssetsHelper.GetRoomWithWifiTwinPayload(roomWithWifiModelId, wifiModelId, wifiComponentName);

                await client.CreateDigitalTwinAsync(roomWithWifiTwinId, roomWithWifiTwin);

                // Get the component
                Response <string> getComponentResponse = await client
                                                         .GetComponentAsync(
                    roomWithWifiTwinId,
                    wifiComponentName)
                                                         .ConfigureAwait(false);

                // The response to the GET request should be 200 (OK)
                getComponentResponse.GetRawResponse().Status.Should().Be((int)HttpStatusCode.OK);

                // Patch component
                Response <string> updateComponentResponse = await client
                                                            .UpdateComponentAsync(
                    roomWithWifiTwinId,
                    wifiComponentName,
                    TestAssetsHelper.GetWifiComponentUpdatePayload())
                                                            .ConfigureAwait(false);

                // The response to the Patch request should be 204 (No content)
                updateComponentResponse.GetRawResponse().Status.Should().Be((int)HttpStatusCode.NoContent);
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomWithWifiTwinId))
                    {
                        await client.DeleteDigitalTwinAsync(roomWithWifiTwinId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(roomWithWifiModelId))
                    {
                        await client.DeleteModelAsync(roomWithWifiModelId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(wifiModelId))
                    {
                        await client.DeleteModelAsync(wifiModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 7
0
        /// <summary>
        /// Creates a new model with a random Id
        /// Decommission the newly created model and check for success
        /// </summary>
        public async Task RunSamplesAsync(DigitalTwinsClient client)
        {
            PrintHeader("MODEL LIFECYCLE SAMPLE");

            // For the purpose of this example we will create temporary models using random model Ids and then decommission a model.
            // We have to make sure these model Ids are unique within the DT instance.

            string newComponentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, client);

            string sampleModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, client);

            string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload
                                              .Replace(SamplesConstants.ComponentId, newComponentModelId);

            string newModelPayload = SamplesConstants.TemporaryModelWithComponentPayload
                                     .Replace(SamplesConstants.ModelId, sampleModelId)
                                     .Replace(SamplesConstants.ComponentId, newComponentModelId);

            // Then we create the model

            try
            {
                #region Snippet:DigitalTwinsSampleCreateModels

                Response <IReadOnlyList <ModelData> > response = await client.CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload });

                Console.WriteLine($"Successfully created a model with Id: {newComponentModelId}, {sampleModelId}, status: {response.GetRawResponse().Status}");

                #endregion Snippet:DigitalTwinsSampleCreateModels
            }
            catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.Conflict)
            {
                Console.WriteLine($"One or more models already existed.");
            }
            catch (Exception ex)
            {
                FatalError($"Failed to create models due to:\n{ex}");
            }

            // Get Model
            try
            {
                #region Snippet:DigitalTwinsSampleGetModel

                Response <ModelData> sampleModel = await client.GetModelAsync(sampleModelId);

                #endregion Snippet:DigitalTwinsSampleGetModel

                Console.WriteLine($"{sampleModel.Value.Id} has decommission status of {sampleModel.Value.Decommissioned}");
            }
            catch (Exception ex)
            {
                FatalError($"Failed to get a model due to:\n{ex}");
            }

            // Now we decommission the model

            #region Snippet:DigitalTwinsSampleDecommisionModel

            try
            {
                await client.DecommissionModelAsync(sampleModelId);

                Console.WriteLine($"Successfully decommissioned model {sampleModelId}");
            }
            catch (RequestFailedException ex)
            {
                FatalError($"Failed to decommision model {sampleModelId} due to:\n{ex}");
            }

            #endregion Snippet:DigitalTwinsSampleDecommisionModel

            // Now delete created model

            #region Snippet:DigitalTwinsSampleDeleteModel

            try
            {
                await client.DeleteModelAsync(sampleModelId);

                Console.WriteLine($"Deleted model {sampleModelId}");
            }
            catch (Exception ex)
            {
                FatalError($"Failed to delete model {sampleModelId} due to:\n{ex}");
            }

            #endregion Snippet:DigitalTwinsSampleDeleteModel
        }
        public async Task Relationships_Lifecycle()
        {
            // arrange

            DigitalTwinsClient client = GetClient();

            var floorContainsRoomRelationshipId    = "FloorToRoomRelationship";
            var floorCooledByHvacRelationshipId    = "FloorToHvacRelationship";
            var hvacCoolsFloorRelationshipId       = "HvacToFloorRelationship";
            var roomContainedInFloorRelationshipId = "RoomToFloorRelationship";

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            string hvacModelId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.HvacModelIdPrefix).ConfigureAwait(false);

            string floorTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.FloorTwinIdPrefix).ConfigureAwait(false);

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string hvacTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.HvacTwinIdPrefix).ConfigureAwait(false);

            try
            {
                // create floor, room and hvac model
                string floorModel = TestAssetsHelper.GetFloorModelPayload(floorModelId, roomModelId, hvacModelId);
                string roomModel  = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                string hvacModel  = TestAssetsHelper.GetHvacModelPayload(hvacModelId, floorModelId);
                await client.CreateModelsAsync(new List <string> {
                    floorModel, roomModel, hvacModel
                }).ConfigureAwait(false);

                // create floor twin
                BasicDigitalTwin floorTwin = TestAssetsHelper.GetFloorTwinPayload(floorModelId);
                await client.CreateDigitalTwinAsync <BasicDigitalTwin>(floorTwinId, floorTwin).ConfigureAwait(false);

                // Create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                // create hvac twin
                BasicDigitalTwin hvacTwin = TestAssetsHelper.GetHvacTwinPayload(hvacModelId);
                await client.CreateDigitalTwinAsync <BasicDigitalTwin>(hvacTwinId, hvacTwin).ConfigureAwait(false);

                BasicRelationship floorContainsRoomPayload                = TestAssetsHelper.GetRelationshipWithPropertyPayload(roomTwinId, ContainsRelationship, "isAccessRestricted", true);
                BasicRelationship floorTwinCoolsRelationshipPayload       = TestAssetsHelper.GetRelationshipPayload(floorTwinId, CoolsRelationship);
                BasicRelationship floorTwinContainedInRelationshipPayload = TestAssetsHelper.GetRelationshipPayload(floorTwinId, ContainedInRelationship);
                BasicRelationship floorCooledByHvacPayload                = TestAssetsHelper.GetRelationshipPayload(hvacTwinId, CooledByRelationship);
                JsonPatchDocument floorContainsRoomUpdatePayload          = new JsonPatchDocument();
                floorContainsRoomUpdatePayload.AppendReplace("/isAccessRestricted", false);

                // CREATE relationships

                // create Relationship from Floor -> Room
                await client
                .CreateRelationshipAsync <BasicRelationship>(
                    floorTwinId,
                    floorContainsRoomRelationshipId,
                    floorContainsRoomPayload)
                .ConfigureAwait(false);

                // create Relationship from Floor -> Hvac
                await client
                .CreateRelationshipAsync <BasicRelationship>(
                    floorTwinId,
                    floorCooledByHvacRelationshipId,
                    floorCooledByHvacPayload)
                .ConfigureAwait(false);

                // create Relationship from Hvac -> Floor
                await client
                .CreateRelationshipAsync <BasicRelationship>(
                    hvacTwinId,
                    hvacCoolsFloorRelationshipId,
                    floorTwinCoolsRelationshipPayload)
                .ConfigureAwait(false);

                // create Relationship from Room -> Floor
                await client
                .CreateRelationshipAsync <BasicRelationship>(
                    roomTwinId,
                    roomContainedInFloorRelationshipId,
                    floorTwinContainedInRelationshipPayload)
                .ConfigureAwait(false);

                // UPDATE relationships

                // create Relationship from Floor -> Room
                await client
                .UpdateRelationshipAsync(
                    floorTwinId,
                    floorContainsRoomRelationshipId,
                    floorContainsRoomUpdatePayload)
                .ConfigureAwait(false);

                // GET relationship
                Response <BasicRelationship> containsRelationshipId = await client
                                                                      .GetRelationshipAsync <BasicRelationship>(
                    floorTwinId,
                    floorContainsRoomRelationshipId)
                                                                      .ConfigureAwait(false);

                // LIST incoming relationships
                AsyncPageable <IncomingRelationship> incomingRelationships = client.GetIncomingRelationshipsAsync(floorTwinId);

                int numberOfIncomingRelationshipsToFloor = 0;
                await foreach (IncomingRelationship relationship in incomingRelationships)
                {
                    ++numberOfIncomingRelationshipsToFloor;
                }
                numberOfIncomingRelationshipsToFloor.Should().Be(2, "floor has incoming relationships from room and hvac");

                // LIST relationships
                AsyncPageable <string> floorRelationships = client.GetRelationshipsAsync(floorTwinId);

                int numberOfFloorRelationships = 0;
                await foreach (var relationship in floorRelationships)
                {
                    ++numberOfFloorRelationships;
                }
                numberOfFloorRelationships.Should().Be(2, "floor has an relationship to room and hvac");

                // LIST relationships by name
                AsyncPageable <string> roomTwinRelationships = client
                                                               .GetRelationshipsAsync(
                    roomTwinId,
                    ContainedInRelationship);
                containsRelationshipId.Value.Id.Should().Be(floorContainsRoomRelationshipId);

                int numberOfRelationships = 0;
                await foreach (var relationship in roomTwinRelationships)
                {
                    ++numberOfRelationships;
                }
                numberOfRelationships.Should().Be(1, "room has only one containedIn relationship to floor");

                await client
                .DeleteRelationshipAsync(
                    floorTwinId,
                    floorContainsRoomRelationshipId)
                .ConfigureAwait(false);

                await client
                .DeleteRelationshipAsync(
                    roomTwinId,
                    roomContainedInFloorRelationshipId)
                .ConfigureAwait(false);

                await client
                .DeleteRelationshipAsync(
                    floorTwinId,
                    floorCooledByHvacRelationshipId)
                .ConfigureAwait(false);

                await client
                .DeleteRelationshipAsync(
                    hvacTwinId,
                    hvacCoolsFloorRelationshipId)
                .ConfigureAwait(false);

                Func <Task> act = async() =>
                {
                    await client
                    .GetRelationshipAsync <BasicRelationship>(
                        floorTwinId,
                        floorContainsRoomRelationshipId)
                    .ConfigureAwait(false);
                };
                act.Should().Throw <RequestFailedException>()
                .And.Status.Should().Be((int)HttpStatusCode.NotFound);

                act = async() =>
                {
                    await client
                    .GetRelationshipAsync <BasicRelationship>(
                        roomTwinId,
                        roomContainedInFloorRelationshipId)
                    .ConfigureAwait(false);
                };
                act.Should().Throw <RequestFailedException>().
                And.Status.Should().Be((int)HttpStatusCode.NotFound);

                act = async() =>
                {
                    await client
                    .GetRelationshipAsync <BasicRelationship>(
                        floorTwinId,
                        floorCooledByHvacRelationshipId)
                    .ConfigureAwait(false);
                };
                act.Should().Throw <RequestFailedException>().
                And.Status.Should().Be((int)HttpStatusCode.NotFound);

                act = async() =>
                {
                    await client
                    .GetRelationshipAsync <BasicRelationship>(
                        hvacTwinId,
                        hvacCoolsFloorRelationshipId)
                    .ConfigureAwait(false);
                };
                act.Should().Throw <RequestFailedException>()
                .And.Status.Should().Be((int)HttpStatusCode.NotFound);
            }
            finally
            {
                // clean up
                try
                {
                    await Task
                    .WhenAll(
                        client.DeleteDigitalTwinAsync(floorTwinId),
                        client.DeleteDigitalTwinAsync(roomTwinId),
                        client.DeleteDigitalTwinAsync(hvacTwinId),
                        client.DeleteModelAsync(hvacModelId),
                        client.DeleteModelAsync(floorModelId),
                        client.DeleteModelAsync(roomModelId))
                    .ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Create a temporary component model, twin model and digital twin instance.
        /// Publish a telemetry message and a component telemetry message to the digital twin instance.
        /// </summary>
        public async Task RunSamplesAsync(DigitalTwinsClient client)
        {
            PrintHeader("PUBLISH TELEMETRY MESSAGE SAMPLE");

            // For the purpose of this example we will create temporary models using a random model Ids.
            // We will also create temporary twin instances to publish the telemetry to.

            string componentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, client);

            string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, client);

            string twinId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client);

            string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload
                                              .Replace(SamplesConstants.ComponentId, componentModelId);

            string newModelPayload = SamplesConstants.TemporaryModelWithComponentPayload
                                     .Replace(SamplesConstants.ModelId, modelId)
                                     .Replace(SamplesConstants.ComponentId, componentModelId);

            // Then we create the models.
            await client
            .CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload });

            Console.WriteLine($"Successfully created models with Ids: {componentModelId}, {modelId}");

            // Create digital twin with Component payload.
            string twinPayload = SamplesConstants.TemporaryTwinPayload
                                 .Replace(SamplesConstants.ModelId, modelId);

            await client.CreateDigitalTwinAsync(twinId, twinPayload);

            Console.WriteLine($"Created digital twin {twinId}.");

            try
            {
                #region Snippet:DigitalTwinsSamplePublishTelemetry

                // construct your json telemetry payload by hand.
                Response publishTelemetryResponse = await client.PublishTelemetryAsync(twinId, "{\"Telemetry1\": 5}");

                Console.WriteLine($"Published telemetry message to twin with Id {twinId}. Response status: {publishTelemetryResponse.Status}");

                #endregion Snippet:DigitalTwinsSamplePublishTelemetry

                #region Snippet:DigitalTwinsSamplePublishComponentTelemetry

                // construct your json telemetry payload by serializing a dictionary.
                var telemetryPayload = new Dictionary <string, int>
                {
                    { "ComponentTelemetry1", 9 }
                };
                Response publishTelemetryToComponentResponse = await client.PublishComponentTelemetryAsync(
                    twinId,
                    "Component1",
                    JsonSerializer.Serialize(telemetryPayload));

                Console.WriteLine($"Published component telemetry message to twin with Id {twinId}. Response status: {publishTelemetryToComponentResponse.Status}");

                #endregion Snippet:DigitalTwinsSamplePublishComponentTelemetry
            }
            catch (Exception ex)
            {
                FatalError($"Failed to publish a telemetry message due to {ex.Message}");
            }

            try
            {
                // Delete the twin.
                await client.DeleteDigitalTwinAsync(twinId);

                // Delete the models.
                await client.DeleteModelAsync(modelId);

                await client.DeleteModelAsync(componentModelId);
            }
            catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.NotFound)
            {
                // Digital twin or models do not exist.
            }
            catch (RequestFailedException ex)
            {
                FatalError($"Failed to delete due to {ex.Message}");
            }
        }
Exemplo n.º 10
0
        public async Task Component_UpdateComponentSucceedsWhenIfMatchHeaderIsCorrect()
        {
            // arrange

            DigitalTwinsClient client = GetClient();

            string wifiModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.WifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomWithWifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomWithWifiTwinIdPrefix).ConfigureAwait(false);

            string wifiComponentName = "wifiAccessPoint";

            try
            {
                // CREATE

                // create roomWithWifi model
                string wifiModel = TestAssetsHelper.GetWifiModelPayload(wifiModelId);

                // create wifi model
                string roomWithWifiModel = TestAssetsHelper.GetRoomWithWifiModelPayload(roomWithWifiModelId, wifiModelId, wifiComponentName);

                await client.CreateModelsAsync(new List <string> {
                    roomWithWifiModel, wifiModel
                }).ConfigureAwait(false);

                // create room digital twin
                BasicDigitalTwin roomWithWifiTwin = TestAssetsHelper.GetRoomWithWifiTwinPayload(roomWithWifiModelId, wifiComponentName);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomWithWifiTwinId, roomWithWifiTwin);

                // Get the component
                Response <object> getComponentResponse = await client
                                                         .GetComponentAsync <object>(
                    roomWithWifiTwinId,
                    wifiComponentName)
                                                         .ConfigureAwait(false);

                // Patch component
                JsonPatchDocument componentUpdatePatchDocument = new JsonPatchDocument();
                componentUpdatePatchDocument.AppendReplace("/Network", "New Network");

                Response updateComponentResponse = await client
                                                   .UpdateComponentAsync(
                    roomWithWifiTwinId,
                    wifiComponentName,
                    componentUpdatePatchDocument)
                                                   .ConfigureAwait(false);

                // Get the latest ETag
                ETag?etagBeforeUpdate = (await client.GetDigitalTwinAsync <BasicDigitalTwin>(roomWithWifiTwinId)).Value.ETag;
                Assert.IsNotNull(etagBeforeUpdate);

                // Patch component again, but with the now out of date ETag
                JsonPatchDocument secondComponentUpdatePatchDocument = new JsonPatchDocument();
                componentUpdatePatchDocument.AppendReplace("/Network", "Even newer Network");

                try
                {
                    await client
                    .UpdateComponentAsync(
                        roomWithWifiTwinId,
                        wifiComponentName,
                        secondComponentUpdatePatchDocument,
                        etagBeforeUpdate)
                    .ConfigureAwait(false);
                }
                catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.PreconditionFailed)
                {
                    throw new AssertionException("UpdateComponent should not have thrown PreconditionFailed because the ETag was up to date", ex);
                }
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomWithWifiTwinId))
                    {
                        await client.DeleteDigitalTwinAsync(roomWithWifiTwinId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(roomWithWifiModelId))
                    {
                        await client.DeleteModelAsync(roomWithWifiModelId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(wifiModelId))
                    {
                        await client.DeleteModelAsync(wifiModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
        public async Task Relationships_PaginationWorks()
        {
            DigitalTwinsClient client = GetClient();

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            string hvacModelId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.HvacModelIdPrefix).ConfigureAwait(false);

            string floorTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.FloorTwinIdPrefix).ConfigureAwait(false);

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string hvacTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.HvacTwinIdPrefix).ConfigureAwait(false);

            try
            {
                // create floor, room and hvac model
                string floorModel = TestAssetsHelper.GetFloorModelPayload(floorModelId, roomModelId, hvacModelId);
                string roomModel  = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                string hvacModel  = TestAssetsHelper.GetHvacModelPayload(hvacModelId, floorModelId);
                await client.CreateModelsAsync(new List <string> {
                    floorModel, roomModel, hvacModel
                }).ConfigureAwait(false);

                // create floor twin
                BasicDigitalTwin floorTwin = TestAssetsHelper.GetFloorTwinPayload(floorModelId);
                await client.CreateDigitalTwinAsync <BasicDigitalTwin>(floorTwinId, floorTwin).ConfigureAwait(false);

                // Create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                BasicRelationship floorContainsRoomPayload = TestAssetsHelper.GetRelationshipWithPropertyPayload(roomTwinId, ContainsRelationship, "isAccessRestricted", true);
                BasicRelationship floorTwinContainedInRelationshipPayload = TestAssetsHelper.GetRelationshipPayload(floorTwinId, ContainedInRelationship);

                // For the sake of test simplicity, we'll just add multiple relationships from the same floor to the same room.
                for (int i = 0; i < bulkRelationshipCount; i++)
                {
                    var floorContainsRoomRelationshipId = $"FloorToRoomRelationship-{GetRandom()}";

                    // create Relationship from Floor -> Room
                    await client
                    .CreateRelationshipAsync <BasicRelationship>(
                        floorTwinId,
                        floorContainsRoomRelationshipId,
                        floorContainsRoomPayload)
                    .ConfigureAwait(false);
                }

                // For the sake of test simplicity, we'll just add multiple relationships from the same room to the same floor.
                for (int i = 0; i < bulkRelationshipCount; i++)
                {
                    var roomContainedInFloorRelationshipId = $"RoomToFloorRelationship-{GetRandom()}";

                    // create Relationship from Room -> Floor
                    await client
                    .CreateRelationshipAsync <BasicRelationship>(
                        roomTwinId,
                        roomContainedInFloorRelationshipId,
                        floorTwinContainedInRelationshipPayload)
                    .ConfigureAwait(false);
                }

                // LIST incoming relationships by page
                AsyncPageable <IncomingRelationship> incomingRelationships = client.GetIncomingRelationshipsAsync(floorTwinId);

                int incomingRelationshipPageCount = 0;
                await foreach (Page <IncomingRelationship> incomingRelationshipPage in incomingRelationships.AsPages())
                {
                    incomingRelationshipPageCount++;
                    if (incomingRelationshipPage.ContinuationToken != null)
                    {
                        incomingRelationshipPage.Values.Count.Should().Be(defaultRelationshipPageSize, "Unexpected page size for a non-terminal page");
                    }
                }

                incomingRelationshipPageCount.Should().BeGreaterThan(1, "Expected more than one page of incoming relationships");

                // LIST outgoing relationships by page
                AsyncPageable <string> outgoingRelationships = client.GetRelationshipsAsync(floorTwinId);

                int outgoingRelationshipPageCount = 0;
                await foreach (Page <string> outgoingRelationshipPage in outgoingRelationships.AsPages())
                {
                    outgoingRelationshipPageCount++;
                    if (outgoingRelationshipPage.ContinuationToken != null)
                    {
                        outgoingRelationshipPage.Values.Count.Should().Be(defaultRelationshipPageSize, "Unexpected page size for a non-terminal page");
                    }
                }

                outgoingRelationshipPageCount.Should().BeGreaterThan(1, "Expected more than one page of outgoing relationships");
            }
            finally
            {
                // clean up
                try
                {
                    await Task
                    .WhenAll(
                        client.DeleteDigitalTwinAsync(floorTwinId),
                        client.DeleteDigitalTwinAsync(roomTwinId),
                        client.DeleteDigitalTwinAsync(hvacTwinId),
                        client.DeleteModelAsync(hvacModelId),
                        client.DeleteModelAsync(floorModelId),
                        client.DeleteModelAsync(roomModelId))
                    .ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
        public async Task TestNewtonsoftObjectSerializerWithDigitalTwins()
        {
            DigitalTwinsClient defaultClient = GetClient();

            string roomTwinId = await GetUniqueTwinIdAsync(defaultClient, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string floorModelId = await GetUniqueModelIdAsync(defaultClient, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(defaultClient, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await CreateAndListModelsAsync(defaultClient, new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // act

                // create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await defaultClient.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                // Create a client with NewtonsoftJsonObjectSerializer configured as the serializer.
                DigitalTwinsClient testClient = GetClient(
                    new DigitalTwinsClientOptions
                {
                    Serializer = new NewtonsoftJsonObjectSerializer()
                });

                // Get digital twin using the simple DigitalTwin model annotated with Newtonsoft attributes
                SimpleNewtonsoftDtModel getResponse = await testClient.GetDigitalTwinAsync <SimpleNewtonsoftDtModel>(roomTwinId).ConfigureAwait(false);

                getResponse.Id.Should().NotBeNullOrEmpty("Digital twin ID should not be null or empty");

                // Query DigitalTwins using the simple DigitalTwin model annotated with Newtonsoft attributes
                AsyncPageable <SimpleNewtonsoftDtModel> queryResponse = testClient.QueryAsync <SimpleNewtonsoftDtModel>("SELECT * FROM DIGITALTWINS");

                await foreach (SimpleNewtonsoftDtModel twin in queryResponse)
                {
                    twin.Id.Should().NotBeNullOrEmpty("Digital twin Id should not be null or empty");
                }
            }
            finally
            {
                // cleanup
                try
                {
                    // delete twin
                    if (!string.IsNullOrWhiteSpace(roomTwinId))
                    {
                        await defaultClient.DeleteDigitalTwinAsync(roomTwinId).ConfigureAwait(false);
                    }

                    // delete models
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await defaultClient.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 13
0
        public async Task Query_PaginationWorks()
        {
            DigitalTwinsClient client = GetClient();
            int    pageSize           = 5;
            string floorModelId       = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // Create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await client.CreateModelsAsync(new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // Create a room twin, with property "IsOccupied": true
                string roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);

                for (int i = 0; i < pageSize + 1; i++)
                {
                    string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

                    await client.CreateDigitalTwinAsync(roomTwinId, roomTwin).ConfigureAwait(false);
                }

                string queryString = "SELECT * FROM digitaltwins";

                // act
                var options = new QueryOptions();
                options.MaxItemsPerPage = pageSize;
                AsyncPageable <string> asyncPageableResponse = client.QueryAsync(queryString, options);

                // assert
                // Test that page size hint works, and that all returned pages either have the page size hint amount of
                // elements, or have no continuation token (signaling that it is the last page)
                int pageCount = 0;
                await foreach (Page <string> page in asyncPageableResponse.AsPages())
                {
                    pageCount++;
                    if (page.ContinuationToken != null)
                    {
                        page.Values.Count.Should().Be(pageSize, "Unexpected page size for a non-terminal page");
                    }
                }

                pageCount.Should().BeGreaterThan(1, "Expected more than one page of query results");
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 14
0
        public async Task Component_Lifecycle()
        {
            // arrange

            DigitalTwinsClient client = GetClient();

            string wifiModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.WifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomWithWifiModelIdPrefix).ConfigureAwait(false);

            string roomWithWifiTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomWithWifiTwinIdPrefix).ConfigureAwait(false);

            string wifiComponentName = "wifiAccessPoint";

            try
            {
                // CREATE

                // create roomWithWifi model
                string wifiModel = TestAssetsHelper.GetWifiModelPayload(wifiModelId);

                // create wifi model
                string roomWithWifiModel = TestAssetsHelper.GetRoomWithWifiModelPayload(roomWithWifiModelId, wifiModelId, wifiComponentName);

                await CreateAndListModelsAsync(client, new List <string> {
                    roomWithWifiModel, wifiModel
                }).ConfigureAwait(false);

                // create room digital twin
                BasicDigitalTwin roomWithWifiTwin = TestAssetsHelper.GetRoomWithWifiTwinPayload(roomWithWifiModelId, wifiComponentName);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomWithWifiTwinId, roomWithWifiTwin);

                // Get the component
                Response <object> getComponentResponse = await client
                                                         .GetComponentAsync <object>(
                    roomWithWifiTwinId,
                    wifiComponentName)
                                                         .ConfigureAwait(false);

                // The response to the GET request should be 200 (OK)
                getComponentResponse.GetRawResponse().Status.Should().Be((int)HttpStatusCode.OK);

                // Patch component
                JsonPatchDocument componentUpdatePatchDocument = new JsonPatchDocument();
                componentUpdatePatchDocument.AppendReplace("/Network", "New Network");

                Response updateComponentResponse = await client
                                                   .UpdateComponentAsync(
                    roomWithWifiTwinId,
                    wifiComponentName,
                    componentUpdatePatchDocument)
                                                   .ConfigureAwait(false);

                // The response to the Patch request should be 204 (No content)
                updateComponentResponse.Status.Should().Be((int)HttpStatusCode.NoContent);
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomWithWifiTwinId))
                    {
                        await client.DeleteDigitalTwinAsync(roomWithWifiTwinId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(roomWithWifiModelId))
                    {
                        await client.DeleteModelAsync(roomWithWifiModelId).ConfigureAwait(false);
                    }
                    if (!string.IsNullOrWhiteSpace(wifiModelId))
                    {
                        await client.DeleteModelAsync(wifiModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 15
0
        public async Task Query_ValidQuery_Success()
        {
            DigitalTwinsClient client = GetClient();

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // Create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await CreateAndListModelsAsync(client, new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // Create a room twin, with property "IsOccupied": true
                string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync(roomTwinId, roomTwin).ConfigureAwait(false);

                // Construct a query string to find the twins with the EXACT model id and provided version. If EXACT is not specified, the query
                // call will get all twins with the same model id but that implement any version higher than the provided version
                string queryString = $"SELECT * FROM digitaltwins WHERE IS_OF_MODEL('{roomModelId}', EXACT) AND IsOccupied = true";

                // act
                AsyncPageable <BasicDigitalTwin> asyncPageableResponse = client.QueryAsync <BasicDigitalTwin>(queryString);

                // assert

                // It takes a few seconds for the service to be able to fetch digital twins through queries after being created. Hence, adding the retry logic
                var digitalTwinFound = false;
                await TestRetryHelper.RetryAsync <AsyncPageable <BasicDigitalTwin> >(async() =>
                {
                    await foreach (BasicDigitalTwin response in asyncPageableResponse)
                    {
                        digitalTwinFound = true;
                        bool isOccupied  = ((JsonElement)response.Contents["IsOccupied"]).GetBoolean();
                        isOccupied.Should().BeTrue();
                        break;
                    }

                    if (!digitalTwinFound)
                    {
                        throw new Exception($"Digital twin based on model Id {roomModelId} not found");
                    }

                    return(null);
                }, s_retryCount, s_retryDelay);

                digitalTwinFound.Should().BeTrue();
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // clean up
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 16
0
        public async Task DigitalTwins_PatchTwinFailsIfInvalidETagProvided()
        {
            DigitalTwinsClient client = GetClient();

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await client.CreateModelsAsync(new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // act

                // create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                // get twin
                ETag?etagBeforeUpdate = (await client.GetDigitalTwinAsync <BasicDigitalTwin>(roomTwinId).ConfigureAwait(false)).Value.ETag;

                Assert.IsNotNull(etagBeforeUpdate);

                // update twin once to make the previous etag fall out of date
                JsonPatchDocument updateTwinPatchDocument = new JsonPatchDocument();
                updateTwinPatchDocument.AppendAdd("/Humidity", 30);
                updateTwinPatchDocument.AppendReplace("/Temperature", 70);
                updateTwinPatchDocument.AppendRemove("/EmployeeId");
                await client.UpdateDigitalTwinAsync(roomTwinId, updateTwinPatchDocument, ETag.All).ConfigureAwait(false);

                // update twin again, but with an out of date etag, which should cause a 412 from service
                JsonPatchDocument secondUpdateTwinPatchDocument = new JsonPatchDocument();
                secondUpdateTwinPatchDocument.AppendReplace("/Humidity", 80);
                Func <Task> act = async() =>
                {
                    await client.UpdateDigitalTwinAsync(roomTwinId, secondUpdateTwinPatchDocument, etagBeforeUpdate).ConfigureAwait(false);
                };

                act.Should().Throw <RequestFailedException>()
                .And.Status.Should().Be((int)HttpStatusCode.PreconditionFailed);
            }
            finally
            {
                // cleanup
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 17
0
        /// <summary>
        /// Creates a digital twin with Component and upates Component
        /// </summary>
        public async Task RunSamplesAsync(DigitalTwinsClient client)
        {
            PrintHeader("COMPONENT SAMPLE");

            // For the purpose of this example we will create temporary models using a random model Ids.
            // We have to make sure these model Ids are unique within the DT instance.

            string componentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, client);

            string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, client);

            string basicDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client);

            string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload
                                              .Replace(SamplesConstants.ComponentId, componentModelId);

            string newModelPayload = SamplesConstants.TemporaryModelWithComponentPayload
                                     .Replace(SamplesConstants.ModelId, modelId)
                                     .Replace(SamplesConstants.ComponentId, componentModelId);

            // Then we create models
            await client.CreateModelsAsync(
                new[]
            {
                newComponentModelPayload,
                newModelPayload
            });

            Console.WriteLine($"Created models {componentModelId} and {modelId}.");

            #region Snippet:DigitalTwinsSampleCreateBasicTwin

            // Create digital twin with component payload using the BasicDigitalTwin serialization helper

            var basicTwin = new BasicDigitalTwin
            {
                Id = basicDtId,
                // model Id of digital twin
                Metadata = { ModelId = modelId },
                Contents =
                {
                    // digital twin properties
                    { "Prop1",          "Value1"            },
                    { "Prop2",                          987 },
                    // component
                    {
                        "Component1",
                        new BasicDigitalTwinComponent
                        {
                            // component properties
                            Contents =
                            {
                                { "ComponentProp1", "Component value 1" },
                                { "ComponentProp2",                 123 },
                            },
                        }
                    },
                },
            };

            Response <BasicDigitalTwin> createDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync(basicDtId, basicTwin);

            Console.WriteLine($"Created digital twin '{createDigitalTwinResponse.Value.Id}'.");

            #endregion Snippet:DigitalTwinsSampleCreateBasicTwin

            // You can also get a digital twin as a BasicDigitalTwin type.
            // It works well for basic stuff, but as you can see it gets more difficult when delving into
            // more complex properties, like components.

            #region Snippet:DigitalTwinsSampleGetBasicDigitalTwin

            Response <BasicDigitalTwin> getBasicDtResponse = await client.GetDigitalTwinAsync <BasicDigitalTwin>(basicDtId);

            if (getBasicDtResponse.GetRawResponse().Status == (int)HttpStatusCode.OK)
            {
                BasicDigitalTwin basicDt = getBasicDtResponse.Value;

                // Must cast Component1 as a JsonElement and get its raw text in order to deserialize it as a dictionary
                string component1RawText = ((JsonElement)basicDt.Contents["Component1"]).GetRawText();
                IDictionary <string, object> component1 = JsonSerializer.Deserialize <IDictionary <string, object> >(component1RawText);

                Console.WriteLine($"Retrieved and deserialized digital twin {basicDt.Id}:\n\t" +
                                  $"ETag: {basicDt.ETag}\n\t" +
                                  $"Prop1: {basicDt.Contents["Prop1"]}\n\t" +
                                  $"Prop2: {basicDt.Contents["Prop2"]}\n\t" +
                                  $"ComponentProp1: {component1["ComponentProp1"]}\n\t" +
                                  $"ComponentProp2: {component1["ComponentProp2"]}");
            }

            #endregion Snippet:DigitalTwinsSampleGetBasicDigitalTwin

            string customDtId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client);

            // Alternatively, you can create your own custom data types to serialize and deserialize your digital twins.
            // By specifying your properties and types directly, it requires less code or knowledge of the type for
            // interaction.

            #region Snippet:DigitalTwinsSampleCreateCustomTwin

            var customTwin = new CustomDigitalTwin
            {
                Id         = customDtId,
                Metadata   = { ModelId = modelId },
                Prop1      = "Prop1 val",
                Prop2      = 987,
                Component1 = new MyCustomComponent
                {
                    ComponentProp1 = "Component prop1 val",
                    ComponentProp2 = 123,
                },
            };
            Response <CustomDigitalTwin> createCustomDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync(customDtId, customTwin);

            Console.WriteLine($"Created digital twin '{createCustomDigitalTwinResponse.Value.Id}'.");

            #endregion Snippet:DigitalTwinsSampleCreateCustomTwin

            // Getting a digital twin as a custom data type is extremely easy.
            // Custom types provide the best possible experience.

            #region Snippet:DigitalTwinsSampleGetCustomDigitalTwin

            Response <CustomDigitalTwin> getCustomDtResponse = await client.GetDigitalTwinAsync <CustomDigitalTwin>(customDtId);

            CustomDigitalTwin customDt = getCustomDtResponse.Value;
            Console.WriteLine($"Retrieved and deserialized digital twin {customDt.Id}:\n\t" +
                              $"ETag: {customDt.ETag}\n\t" +
                              $"Prop1: {customDt.Prop1}\n\t" +
                              $"Prop2: {customDt.Prop2}\n\t" +
                              $"ComponentProp1: {customDt.Component1.ComponentProp1}\n\t" +
                              $"ComponentProp2: {customDt.Component1.ComponentProp2}");

            #endregion Snippet:DigitalTwinsSampleGetCustomDigitalTwin

            #region Snippet:DigitalTwinsSampleUpdateComponent

            // Update Component1 by replacing the property ComponentProp1 value,
            // using an optional utility to build the payload.
            var componentJsonPatchDocument = new JsonPatchDocument();
            componentJsonPatchDocument.AppendReplace("/ComponentProp1", "Some new value");
            await client.UpdateComponentAsync(basicDtId, "Component1", componentJsonPatchDocument);

            Console.WriteLine($"Updated component for digital twin '{basicDtId}'.");

            #endregion Snippet:DigitalTwinsSampleUpdateComponent

            // Get Component

            #region Snippet:DigitalTwinsSampleGetComponent

            await client.GetComponentAsync <MyCustomComponent>(basicDtId, SamplesConstants.ComponentName);

            Console.WriteLine($"Retrieved component for digital twin '{basicDtId}'.");

            #endregion Snippet:DigitalTwinsSampleGetComponent

            // Clean up

            try
            {
                await client.DeleteDigitalTwinAsync(basicDtId);

                await client.DeleteDigitalTwinAsync(customDtId);
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete digital twin due to {ex}");
            }

            try
            {
                await client.DeleteModelAsync(modelId);

                await client.DeleteModelAsync(componentModelId);
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete models due to {ex}");
            }
        }
Exemplo n.º 18
0
        public async Task DigitalTwins_DeleteTwinFailsIfMatchProvidesOutdatedEtag()
        {
            DigitalTwinsClient client = GetClient();

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await client.CreateModelsAsync(new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // act

                // create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                // get twin
                ETag?etagBeforeUpdate = (await client.GetDigitalTwinAsync <BasicDigitalTwin>(roomTwinId).ConfigureAwait(false)).Value.ETag;

                // update twin
                JsonPatchDocument updateTwinPatchDocument = new JsonPatchDocument();
                updateTwinPatchDocument.AppendAdd("/Humidity", 30);
                updateTwinPatchDocument.AppendReplace("/Temperature", 70);
                updateTwinPatchDocument.AppendRemove("/EmployeeId");

                await client.UpdateDigitalTwinAsync(roomTwinId, updateTwinPatchDocument, ETag.All).ConfigureAwait(false);

                // assert
                Func <Task> act = async() =>
                {
                    // since the ETag is out of date, this call should throw a 412
                    await client.DeleteDigitalTwinAsync(roomTwinId, etagBeforeUpdate).ConfigureAwait(false);
                };

                act.Should().Throw <RequestFailedException>()
                .And.Status.Should().Be((int)HttpStatusCode.PreconditionFailed);
            }
            finally
            {
                // cleanup
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
        /// <summary>
        /// Create a temporary component model, twin model and digital twin instance.
        /// Publish a telemetry message and a component telemetry message to the digital twin instance.
        /// </summary>
        public async Task RunSamplesAsync(DigitalTwinsClient client)
        {
            PrintHeader("PUBLISH TELEMETRY MESSAGE SAMPLE");

            // For the purpose of this example we will create temporary models using a random model Ids.
            // We will also create temporary twin instances to publish the telemetry to.

            string componentModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryComponentModelPrefix, client);

            string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, client);

            string twinId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, client);

            string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload
                                              .Replace(SamplesConstants.ComponentId, componentModelId);

            string newModelPayload = SamplesConstants.TemporaryModelWithComponentPayload
                                     .Replace(SamplesConstants.ModelId, modelId)
                                     .Replace(SamplesConstants.ComponentId, componentModelId);

            // Then we create the models.
            await client
            .CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload });

            // Get the models we just created
            AsyncPageable <DigitalTwinsModelData> models = client.GetModelsAsync();

            await foreach (DigitalTwinsModelData model in models)
            {
                Console.WriteLine($"Successfully created model '{model.Id}'");
            }

            // Create digital twin with Component payload.
            string twinPayload = SamplesConstants.TemporaryTwinPayload
                                 .Replace(SamplesConstants.ModelId, modelId);

            BasicDigitalTwin basicDigitalTwin = JsonSerializer.Deserialize <BasicDigitalTwin>(twinPayload);

            Response <BasicDigitalTwin> createDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(twinId, basicDigitalTwin);

            Console.WriteLine($"Created digital twin '{createDigitalTwinResponse.Value.Id}'.");

            try
            {
                #region Snippet:DigitalTwinsSamplePublishTelemetry

                // construct your json telemetry payload by hand.
                await client.PublishTelemetryAsync(twinId, Guid.NewGuid().ToString(), "{\"Telemetry1\": 5}");

                Console.WriteLine($"Published telemetry message to twin '{twinId}'.");

                #endregion Snippet:DigitalTwinsSamplePublishTelemetry

                #region Snippet:DigitalTwinsSamplePublishComponentTelemetry

                // construct your json telemetry payload by serializing a dictionary.
                var telemetryPayload = new Dictionary <string, int>
                {
                    { "ComponentTelemetry1", 9 }
                };
                await client.PublishComponentTelemetryAsync(
                    twinId,
                    "Component1",
                    Guid.NewGuid().ToString(),
                    JsonSerializer.Serialize(telemetryPayload));

                Console.WriteLine($"Published component telemetry message to twin '{twinId}'.");

                #endregion Snippet:DigitalTwinsSamplePublishComponentTelemetry
            }
            catch (Exception ex)
            {
                FatalError($"Failed to publish a telemetry message due to: {ex.Message}");
            }

            try
            {
                // Delete the twin.
                await client.DeleteDigitalTwinAsync(twinId);

                // Delete the models.
                await client.DeleteModelAsync(modelId);

                await client.DeleteModelAsync(componentModelId);
            }
            catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.NotFound)
            {
                // Digital twin or models do not exist.
            }
            catch (RequestFailedException ex)
            {
                FatalError($"Failed to delete due to: {ex.Message}");
            }
        }
Exemplo n.º 20
0
        public async Task DigitalTwins_DeleteTwinSucceedsIfMatchProvidesCorrectEtag()
        {
            DigitalTwinsClient client = GetClient();

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await client.CreateModelsAsync(new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // act

                // create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                // update twin
                JsonPatchDocument updateTwinPatchDocument = new JsonPatchDocument();
                updateTwinPatchDocument.AppendAdd("/Humidity", 30);
                updateTwinPatchDocument.AppendReplace("/Temperature", 70);
                updateTwinPatchDocument.AppendRemove("/EmployeeId");
                await client.UpdateDigitalTwinAsync(roomTwinId, updateTwinPatchDocument, ETag.All).ConfigureAwait(false);

                // get twin
                ETag?correctETag = (await client.GetDigitalTwinAsync <BasicDigitalTwin>(roomTwinId).ConfigureAwait(false)).Value.ETag;
                Assert.IsNotNull(correctETag);

                try
                {
                    // since the ETag is not out of date, this call should not throw a 412
                    await client.DeleteDigitalTwinAsync(roomTwinId, correctETag).ConfigureAwait(false);
                }
                catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.PreconditionFailed)
                {
                    throw new AssertionException("UpdateRelationship should not have thrown PreconditionFailed because the ETag was up to date", ex);
                }
            }
            finally
            {
                // cleanup
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }
Exemplo n.º 21
0
        /// <summary>
        /// Creates two digital twins, and connect them with relationships.
        /// </summary>
        public async Task RunSamplesAsync(DigitalTwinsClient client)
        {
            // For the purpose of keeping code snippets readable to the user, hardcoded string literals are used in place of assigned variables, eg Ids.
            // Despite not being a good code practice, this prevents code snippets from being out of context for the user when making API calls that accept Ids as parameters.

            PrintHeader("RELATIONSHIP SAMPLE");
            string sampleBuildingModelId = "dtmi:com:samples:SampleBuilding;1";
            string sampleFloorModelId    = "dtmi:com:samples:SampleFloor;1";
            await ModelLifecycleSamples.TryDeleteModelAsync(client, sampleBuildingModelId);

            await ModelLifecycleSamples.TryDeleteModelAsync(client, sampleFloorModelId);

            // Create a building digital twin model.
            string buildingModelPayload = SamplesConstants.TemporaryModelWithRelationshipPayload
                                          .Replace(SamplesConstants.RelationshipTargetModelId, sampleFloorModelId)
                                          .Replace(SamplesConstants.ModelId, sampleBuildingModelId)
                                          .Replace(SamplesConstants.ModelDisplayName, "Building")
                                          .Replace(SamplesConstants.RelationshipName, "contains");

            await client.CreateModelsAsync(
                new[]
            {
                buildingModelPayload
            });

            Console.WriteLine($"Created model '{sampleBuildingModelId}'.");

            // Create a floor digital twin model.
            string floorModelPayload = SamplesConstants.TemporaryModelWithRelationshipPayload
                                       .Replace(SamplesConstants.RelationshipTargetModelId, sampleBuildingModelId)
                                       .Replace(SamplesConstants.ModelId, sampleFloorModelId)
                                       .Replace(SamplesConstants.ModelDisplayName, "Floor")
                                       .Replace(SamplesConstants.RelationshipName, "containedIn");

            await client.CreateModelsAsync(new[] { floorModelPayload });

            // Get the model we just created
            Response <DigitalTwinsModelData> getFloorModelResponse = await client.GetModelAsync(sampleFloorModelId).ConfigureAwait(false);

            Console.WriteLine($"Created model '{getFloorModelResponse.Value.Id}'");

            // Create a building digital twin.
            var buildingDigitalTwin = new BasicDigitalTwin
            {
                Id       = "buildingTwinId",
                Metadata = { ModelId = sampleBuildingModelId }
            };

            Response <BasicDigitalTwin> createDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>("buildingTwinId", buildingDigitalTwin);

            Console.WriteLine($"Created twin '{createDigitalTwinResponse.Value.Id}'.");

            // Create a floor digital.
            var floorDigitalTwin = new BasicDigitalTwin
            {
                Id       = "floorTwinId",
                Metadata = { ModelId = sampleFloorModelId }
            };

            Response <BasicDigitalTwin> createFloorDigitalTwinResponse = await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>("floorTwinId", floorDigitalTwin);

            Console.WriteLine($"Created twin '{createFloorDigitalTwinResponse.Value.Id}'.");

            // Create a relationship between building and floor using the BasicRelationship serialization helper.

            #region Snippet:DigitalTwinsSampleCreateBasicRelationship

            var buildingFloorRelationshipPayload = new BasicRelationship
            {
                Id         = "buildingFloorRelationshipId",
                SourceId   = "buildingTwinId",
                TargetId   = "floorTwinId",
                Name       = "contains",
                Properties =
                {
                    { "Prop1", "Prop1 value" },
                    { "Prop2",             6 }
                }
            };

            Response <BasicRelationship> createBuildingFloorRelationshipResponse = await client
                                                                                   .CreateOrReplaceRelationshipAsync <BasicRelationship>("buildingTwinId", "buildingFloorRelationshipId", buildingFloorRelationshipPayload);

            Console.WriteLine($"Created a digital twin relationship '{createBuildingFloorRelationshipResponse.Value.Id}' " +
                              $"from twin '{createBuildingFloorRelationshipResponse.Value.SourceId}' to twin '{createBuildingFloorRelationshipResponse.Value.TargetId}'.");

            #endregion Snippet:DigitalTwinsSampleCreateBasicRelationship

            // You can get a relationship as a BasicRelationship type.

            #region Snippet:DigitalTwinsSampleGetBasicRelationship

            Response <BasicRelationship> getBasicRelationshipResponse = await client.GetRelationshipAsync <BasicRelationship>(
                "buildingTwinId",
                "buildingFloorRelationshipId");

            if (getBasicRelationshipResponse.GetRawResponse().Status == (int)HttpStatusCode.OK)
            {
                BasicRelationship basicRelationship = getBasicRelationshipResponse.Value;
                Console.WriteLine($"Retrieved relationship '{basicRelationship.Id}' from twin {basicRelationship.SourceId}.\n\t" +
                                  $"Prop1: {basicRelationship.Properties["Prop1"]}\n\t" +
                                  $"Prop2: {basicRelationship.Properties["Prop2"]}");
            }

            #endregion Snippet:DigitalTwinsSampleGetBasicRelationship

            // Alternatively, you can create your own custom data types and use these types when calling into the APIs.
            // This requires less code or knowledge of the type for interaction.

            // Create a relationship between floorTwinId and buildingTwinId using a custom data type.

            #region Snippet:DigitalTwinsSampleCreateCustomRelationship

            var floorBuildingRelationshipPayload = new CustomRelationship
            {
                Id       = "floorBuildingRelationshipId",
                SourceId = "floorTwinId",
                TargetId = "buildingTwinId",
                Name     = "containedIn",
                Prop1    = "Prop1 val",
                Prop2    = 4
            };

            Response <CustomRelationship> createCustomRelationshipResponse = await client
                                                                             .CreateOrReplaceRelationshipAsync <CustomRelationship>("floorTwinId", "floorBuildingRelationshipId", floorBuildingRelationshipPayload);

            Console.WriteLine($"Created a digital twin relationship '{createCustomRelationshipResponse.Value.Id}' " +
                              $"from twin '{createCustomRelationshipResponse.Value.SourceId}' to twin '{createCustomRelationshipResponse.Value.TargetId}'.");

            #endregion Snippet:DigitalTwinsSampleCreateCustomRelationship

            // Getting a relationship as a custom data type is extremely easy.

            #region Snippet:DigitalTwinsSampleGetCustomRelationship

            Response <CustomRelationship> getCustomRelationshipResponse = await client.GetRelationshipAsync <CustomRelationship>(
                "floorTwinId",
                "floorBuildingRelationshipId");

            CustomRelationship getCustomRelationship = getCustomRelationshipResponse.Value;
            Console.WriteLine($"Retrieved and deserialized relationship '{getCustomRelationship.Id}' from twin '{getCustomRelationship.SourceId}'.\n\t" +
                              $"Prop1: {getCustomRelationship.Prop1}\n\t" +
                              $"Prop2: {getCustomRelationship.Prop2}");

            #endregion Snippet:DigitalTwinsSampleGetCustomRelationship

            // Get all relationships in the graph where buildingTwinId is the source of the relationship.

            #region Snippet:DigitalTwinsSampleGetAllRelationships

            AsyncPageable <BasicRelationship> relationships = client.GetRelationshipsAsync <BasicRelationship>("buildingTwinId");
            await foreach (BasicRelationship relationship in relationships)
            {
                Console.WriteLine($"Retrieved relationship '{relationship.Id}' with source {relationship.SourceId}' and " +
                                  $"target {relationship.TargetId}.\n\t" +
                                  $"Prop1: {relationship.Properties["Prop1"]}\n\t" +
                                  $"Prop2: {relationship.Properties["Prop2"]}");
            }

            #endregion Snippet:DigitalTwinsSampleGetAllRelationships

            // Get all incoming relationships in the graph where buildingTwinId is the target of the relationship.

            #region Snippet:DigitalTwinsSampleGetIncomingRelationships

            AsyncPageable <IncomingRelationship> incomingRelationships = client.GetIncomingRelationshipsAsync("buildingTwinId");

            await foreach (IncomingRelationship incomingRelationship in incomingRelationships)
            {
                Console.WriteLine($"Found an incoming relationship '{incomingRelationship.RelationshipId}' from '{incomingRelationship.SourceId}'.");
            }

            #endregion Snippet:DigitalTwinsSampleGetIncomingRelationships

            // Delete the contains relationship, created earlier in the sample code, from building to floor.

            #region Snippet:DigitalTwinsSampleDeleteRelationship

            await client.DeleteRelationshipAsync("buildingTwinId", "buildingFloorRelationshipId");

            Console.WriteLine($"Deleted relationship 'buildingFloorRelationshipId'.");

            #endregion Snippet:DigitalTwinsSampleDeleteRelationship

            // Delete the containedIn relationship, created earlier in the sample code, from floor to building.
            await client.DeleteRelationshipAsync("floorTwinId", "floorBuildingRelationshipId");

            Console.WriteLine($"Deleted relationship 'floorBuildingRelationshipId'.");

            // Clean up.
            try
            {
                // Delete all twins
                await client.DeleteDigitalTwinAsync("buildingTwinId");

                await client.DeleteDigitalTwinAsync("floorTwinId");
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete twin due to {ex}.");
            }

            try
            {
                await client.DeleteModelAsync(sampleBuildingModelId);

                await client.DeleteModelAsync(sampleFloorModelId);
            }
            catch (RequestFailedException ex)
            {
                Console.WriteLine($"Failed to delete model due to {ex}.");
            }
        }
Exemplo n.º 22
0
        public async Task DigitalTwins_PatchTwinSucceedsIfCorrectETagProvided()
        {
            DigitalTwinsClient client = GetClient();

            string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetDefaults.RoomTwinIdPrefix).ConfigureAwait(false);

            string floorModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.FloorModelIdPrefix).ConfigureAwait(false);

            string roomModelId = await GetUniqueModelIdAsync(client, TestAssetDefaults.RoomModelIdPrefix).ConfigureAwait(false);

            try
            {
                // arrange

                // create room model
                string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId);
                await CreateAndListModelsAsync(client, new List <string> {
                    roomModel
                }).ConfigureAwait(false);

                // act

                // create room twin
                BasicDigitalTwin roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId);
                await client.CreateOrReplaceDigitalTwinAsync <BasicDigitalTwin>(roomTwinId, roomTwin).ConfigureAwait(false);

                // update twin once
                JsonPatchDocument updateTwinPatchDocument = new JsonPatchDocument();
                updateTwinPatchDocument.AppendAdd("/Humidity", 30);
                updateTwinPatchDocument.AppendReplace("/Temperature", 70);
                updateTwinPatchDocument.AppendRemove("/EmployeeId");
                await client.UpdateDigitalTwinAsync(roomTwinId, updateTwinPatchDocument, ETag.All).ConfigureAwait(false);

                // get twin
                ETag?etagBeforeUpdate = (await client.GetDigitalTwinAsync <BasicDigitalTwin>(roomTwinId).ConfigureAwait(false)).Value.ETag;

                Assert.IsNotNull(etagBeforeUpdate);

                // update twin again, but with the correct etag
                JsonPatchDocument secondUpdateTwinPatchDocument = new JsonPatchDocument();
                secondUpdateTwinPatchDocument.AppendReplace("/Humidity", 80);
                try
                {
                    await client.UpdateDigitalTwinAsync(roomTwinId, secondUpdateTwinPatchDocument, etagBeforeUpdate).ConfigureAwait(false);
                }
                catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.PreconditionFailed)
                {
                    throw new AssertionException("UpdateDigitalTwin should not have thrown PreconditionFailed because the ETag was up to date", ex);
                }
            }
            catch (Exception ex)
            {
                Assert.Fail($"Failure in executing a step in the test case: {ex.Message}.");
            }
            finally
            {
                // cleanup
                try
                {
                    if (!string.IsNullOrWhiteSpace(roomModelId))
                    {
                        await client.DeleteModelAsync(roomModelId).ConfigureAwait(false);
                    }
                }
                catch (Exception ex)
                {
                    Assert.Fail($"Test clean up failed: {ex.Message}");
                }
            }
        }