From 468cd8ae621bc8d6cbd88f324ece581063053e24 Mon Sep 17 00:00:00 2001 From: "David R. Williamson" Date: Sat, 30 May 2020 12:11:15 -0700 Subject: [PATCH 1/2] Add digital twins service client library --- sdk/digitaltwins/.gitignore | 1 + .../Azure.DigitalTwins.Core/.gitignore | 4 + .../Azure.DigitalTwins.Core.sln | 53 + .../Azure.DigitalTwins.Core/CHANGELOG.md | 3 + .../CaptureLogs/capture_logs_readme.md | 11 + .../CaptureLogs/digitaltwins_providers.txt | 1 + .../CaptureLogs/digitaltwins_startlog.cmd | 2 + .../CaptureLogs/digitaltwins_stoplog.cmd | 2 + .../Azure.DigitalTwins.Core/CodeMaid.config | 41 + .../Directory.Build.props | 6 + .../Azure.DigitalTwins.Core/README.md | 78 + .../Azure.DigitalTwins.Core.netstandard2.0.cs | 179 ++ .../ComponentSamples.cs | 94 ++ .../DTDL/DigitalTwins/BuildingTwin.json | 7 + .../DTDL/DigitalTwins/FloorTwin.json | 6 + .../DTDL/DigitalTwins/HVACTwin.json | 8 + .../DTDL/DigitalTwins/RoomTwin.json | 16 + .../DTDL/Models/Building.json | 35 + .../DTDL/Models/Floor.json | 18 + .../DTDL/Models/HVAC.json | 28 + .../DTDL/Models/Room.json | 33 + .../DTDL/Models/Wifi.json | 18 + .../Relationships/HospitalRelationships.json | 27 + .../DigitalTwinsClientSample.csproj | 27 + .../DigitalTwinsLifecycleSamples.cs | 471 ++++++ .../DigitalTwinsClientSample/FileHelper.cs | 51 + .../ModelLifecycleSamples.cs | 117 ++ .../DigitalTwinsClientSample/Options.cs | 58 + .../DigitalTwinsClientSample/Program.cs | 110 ++ .../DigitalTwinsClientSample/SampleLogger.cs | 26 + .../SamplesConstants.cs | 133 ++ .../UniqueIdHelper.cs | 47 + .../Azure.DigitalTwins.Core/samples/Readme.md | 267 +++ .../src/Azure.DigitalTwins.Core.csproj | 56 + .../Customized/DigitalTwinModelsRestClient.cs | 221 +++ .../src/Customized/DigitalTwinsRestClient.cs | 881 ++++++++++ .../src/Customized/Models/Error.cs | 10 + .../src/Customized/Models/ErrorResponse.cs | 10 + .../Customized/Models/EventRouteCollection.cs | 10 + .../src/Customized/Models/GetModelsOptions.cs | 16 + .../Models/IncomingRelationshipCollection.cs | 10 + .../src/Customized/Models/InnerError.cs | 10 + .../Models/ModelData.Serialization.cs | 82 + .../src/Customized/Models/ModelData.cs | 54 + .../Models/PagedModelDataCollection.cs | 10 + .../Models/QueryResult.Serialization.cs | 49 + .../src/Customized/Models/QueryResult.cs | 16 + .../Customized/Models/QuerySpecification.cs | 10 + .../RelationshipCollection.Serialization.cs | 48 + .../Models/RelationshipCollection.cs | 15 + .../src/DigitalTwinsClient.cs | 1285 ++++++++++++++ .../src/DigitalTwinsClientOptions.cs | 60 + .../Generated/DigitalTwinModelsRestClient.cs | 429 +++++ .../src/Generated/DigitalTwinsRestClient.cs | 970 +++++++++++ .../src/Generated/EventRoutesRestClient.cs | 454 +++++ .../Generated/Models/Error.Serialization.cs | 76 + .../src/Generated/Models/Error.cs | 42 + .../Models/ErrorResponse.Serialization.cs | 33 + .../src/Generated/Models/ErrorResponse.cs | 28 + .../Models/EventRoute.Serialization.cs | 67 + .../src/Generated/Models/EventRoute.cs | 45 + .../EventRouteCollection.Serialization.cs | 56 + .../Generated/Models/EventRouteCollection.cs | 34 + .../Models/EventRoutesListOptions.cs | 28 + .../src/Generated/Models/GetModelsOptions.cs | 28 + .../IncomingRelationship.Serialization.cs | 63 + .../Generated/Models/IncomingRelationship.cs | 40 + ...ingRelationshipCollection.Serialization.cs | 56 + .../Models/IncomingRelationshipCollection.cs | 33 + .../Models/InnerError.Serialization.cs | 43 + .../src/Generated/Models/InnerError.cs | 32 + .../Models/ModelData.Serialization.cs | 18 + .../src/Generated/Models/ModelData.cs | 23 + .../PagedModelDataCollection.Serialization.cs | 56 + .../Models/PagedModelDataCollection.cs | 34 + .../Models/QueryResult.Serialization.cs | 17 + .../src/Generated/Models/QueryResult.cs | 31 + .../QuerySpecification.Serialization.cs | 31 + .../Generated/Models/QuerySpecification.cs | 32 + .../RelationshipCollection.Serialization.cs | 17 + .../Models/RelationshipCollection.cs | 31 + .../src/Generated/QueryQueryTwinsHeaders.cs | 22 + .../src/Generated/QueryRestClient.cs | 140 ++ .../src/Models/ModelsConstants.cs | 18 + .../src/Models/TelemetryOptions.cs | 24 + .../src/Properties/AssemblyInfo.cs | 6 + .../src/Queries/QueryChargeHelper.cs | 65 + .../src/RequestOptions.cs | 22 + .../src/Serialization/BasicDigitalTwin.cs | 32 + .../src/Serialization/BasicRelationship.cs | 45 + .../src/Serialization/DigitalTwinMetadata.cs | 27 + .../src/Serialization/PayloadHelper.cs | 22 + .../Serialization/UpdateOperationsUtility.cs | 78 + .../src/Serialization/WritableProperty.cs | 47 + .../Azure.DigitalTwins.Core/src/autorest.md | 10 + .../Azure.DigitalTwins.Core/src/generate.ps1 | 1 + .../src/swagger/digitaltwins.json | 1491 +++++++++++++++++ .../CreateRelationshipAdvancedExample.json | 25 + .../CreateRelationshipBasicExample.json | 21 + .../src/swagger/examples/DeleteModel.json | 9 + .../swagger/examples/DeleteRelationship.json | 10 + .../src/swagger/examples/DeleteTwin.json | 9 + .../swagger/examples/EventRouteDelete.json | 9 + .../src/swagger/examples/EventRouteGet.json | 15 + .../src/swagger/examples/EventRoutePut.json | 13 + .../examples/EventRoutePutWithFilter.json | 13 + .../src/swagger/examples/EventRoutesList.json | 24 + .../src/swagger/examples/GetComponent.json | 53 + .../examples/GetIncomingRelationship.json | 27 + .../src/swagger/examples/GetRelationship.json | 29 + .../swagger/examples/GetRelationshipById.json | 18 + .../GetRelationshipByRelationshipName.json | 30 + .../src/swagger/examples/GetTwin.json | 53 + .../src/swagger/examples/ModelAdd.json | 47 + .../src/swagger/examples/ModelGetById.json | 15 + ...odelGetByIdWithIncludeModelDefinition.json | 41 + .../examples/ModelUpdateDecommissioned.json | 16 + .../src/swagger/examples/ModelsGet.json | 35 + ...DependenciesAndIncludeModelDefinition.json | 70 + .../PatchComponentAdvancedExample.json | 27 + .../examples/PatchComponentBasicExample.json | 18 + .../PatchRelationshipAdvancedExample.json | 26 + .../PatchRelationshipBasicExample.json | 17 + .../examples/PatchTwinAdvancedExample.json | 26 + .../examples/PatchTwinBasicExample.json | 17 + .../examples/PutTwinAdvancedExample.json | 71 + .../swagger/examples/PutTwinBasicExample.json | 22 + .../src/swagger/examples/QueryFirstPage.json | 44 + .../src/swagger/examples/QueryJoin.json | 56 + .../src/swagger/examples/QueryNextPage.json | 43 + .../src/swagger/examples/SendTelemetry.json | 14 + .../examples/SendTelemetryFromComponent.json | 15 + .../Azure.DigitalTwins.Core.Tests.csproj | 47 + .../tests/BasicRelationshipUnitTests.cs | 47 + .../tests/ComponentTests.cs | 96 ++ .../tests/DigitalTwinClientTests.cs | 64 + .../tests/DigitalTwinRelationshipTests.cs | 248 +++ .../tests/DigitalTwinTests.cs | 116 ++ .../tests/DigitalTwins/updateTwin.json | 16 + .../tests/DigitalTwinsTestEnvironment.cs | 17 + .../tests/E2eTestBase.cs | 98 ++ .../tests/EventRouteTests.cs | 118 ++ .../tests/FakeTokenCredential.cs | 26 + .../tests/Models/wifi.json | 18 + .../tests/ModelsTests.cs | 158 ++ .../tests/PayloadHelperUnitTests.cs | 49 + .../tests/QueryTests.cs | 72 + .../ComponentTests/Component_Lifecycle.json | 395 +++++ .../Component_LifecycleAsync.json | 395 +++++ .../Relationships_Lifecycle.json | 1091 ++++++++++++ .../Relationships_LifecycleAsync.json | 1091 ++++++++++++ ...edentials_ThrowsUnauthorizedException.json | 29 + ...ials_ThrowsUnauthorizedExceptionAsync.json | 29 + .../DigitalTwins_Lifecycle.json | 375 +++++ .../DigitalTwins_LifecycleAsync.json | 375 +++++ ..._TwinNotExist_ThrowsNotFoundException.json | 35 + ...NotExist_ThrowsNotFoundExceptionAsync.json | 35 + ...RouteNotExist_ThrowsNotFoundException.json | 35 + ...NotExist_ThrowsNotFoundExceptionAsync.json | 35 + .../EventRoutes_Lifecycle.json | 126 ++ .../EventRoutes_LifecycleAsync.json | 126 ++ ...RouteFilter_ThrowsBadRequestException.json | 35 + ...Filter_ThrowsBadRequestExceptionAsync.json | 35 + ...isplayNameAndDescription_Deserializes.json | 127 ++ ...yNameAndDescription_DeserializesAsync.json | 127 ++ .../ModelsTests/Models_Lifecycle.json | 345 ++++ .../ModelsTests/Models_LifecycleAsync.json | 345 ++++ ...rmedModelId_ThrowsBadRequestException.json | 35 + ...odelId_ThrowsBadRequestExceptionAsync.json | 35 + ...AlreadyExists_ThrowsConflictException.json | 158 ++ ...dyExists_ThrowsConflictExceptionAsync.json | 158 ++ ...odelNotExists_ThrowsNotFoundException.json | 35 + ...otExists_ThrowsNotFoundExceptionAsync.json | 35 + .../QueryTests/Query_ValidQuery_Success.json | 635 +++++++ .../Query_ValidQuery_SuccessAsync.json | 635 +++++++ .../tests/TestAssetSettings.cs | 118 ++ .../tests/TestAssets.Designer.cs | 349 ++++ .../tests/TestAssets.resx | 385 +++++ .../tests/TestAssetsHelper.cs | 120 ++ .../tests/TestSettings.cs | 148 ++ .../tests/UpdateOperationsUtilityUnitTests.cs | 60 + .../tests/UpdateSessionRecords.ps1 | 1 + .../tests/config/common.config.json | 5 + .../config/common.test.assets.config.json | 8 + .../tests/prerequisites/manifest.json | 9 + .../prerequisites/prerequisite readme.md | 39 + .../tests/prerequisites/setup.ps1 | 204 +++ sdk/digitaltwins/Export-AdtApis.ps1 | 1 + sdk/digitaltwins/Update-AdtSnippets.ps1 | 1 + .../remove-test-resources-pre.ps1 | 51 + sdk/digitaltwins/test-resources.json | 153 ++ sdk/digitaltwins/tests.yml | 2 +- 192 files changed, 20461 insertions(+), 1 deletion(-) create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/.gitignore create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/Azure.DigitalTwins.Core.sln create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/CHANGELOG.md create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/capture_logs_readme.md create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_providers.txt create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_startlog.cmd create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_stoplog.cmd create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/CodeMaid.config create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/Directory.Build.props create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/README.md create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/api/Azure.DigitalTwins.Core.netstandard2.0.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ComponentSamples.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/BuildingTwin.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/FloorTwin.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/HVACTwin.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/RoomTwin.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Building.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Floor.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/HVAC.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Room.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Wifi.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Relationships/HospitalRelationships.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsClientSample.csproj create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsLifecycleSamples.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/FileHelper.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ModelLifecycleSamples.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/Options.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/Program.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/SampleLogger.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/SamplesConstants.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/UniqueIdHelper.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/samples/Readme.md create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Azure.DigitalTwins.Core.csproj create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/DigitalTwinModelsRestClient.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/DigitalTwinsRestClient.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/Error.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ErrorResponse.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/EventRouteCollection.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/GetModelsOptions.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/IncomingRelationshipCollection.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/InnerError.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ModelData.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ModelData.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/PagedModelDataCollection.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QueryResult.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QueryResult.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QuerySpecification.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/RelationshipCollection.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/RelationshipCollection.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClient.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClientOptions.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinModelsRestClient.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinsRestClient.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/EventRoutesRestClient.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/Error.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/Error.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ErrorResponse.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ErrorResponse.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoute.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoute.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRouteCollection.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRouteCollection.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoutesListOptions.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/GetModelsOptions.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationship.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationship.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationshipCollection.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationshipCollection.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/InnerError.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/InnerError.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ModelData.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ModelData.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/PagedModelDataCollection.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/PagedModelDataCollection.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QueryResult.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QueryResult.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QuerySpecification.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QuerySpecification.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/RelationshipCollection.Serialization.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/RelationshipCollection.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/QueryQueryTwinsHeaders.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/QueryRestClient.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Models/ModelsConstants.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Models/TelemetryOptions.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Properties/AssemblyInfo.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Queries/QueryChargeHelper.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/RequestOptions.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicDigitalTwin.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicRelationship.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/DigitalTwinMetadata.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/PayloadHelper.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/UpdateOperationsUtility.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/WritableProperty.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/autorest.md create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/generate.ps1 create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/digitaltwins.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/CreateRelationshipAdvancedExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/CreateRelationshipBasicExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteModel.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteRelationship.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteTwin.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRouteDelete.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRouteGet.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutePut.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutePutWithFilter.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutesList.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetComponent.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetIncomingRelationship.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationship.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationshipById.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationshipByRelationshipName.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetTwin.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelAdd.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelGetById.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelGetByIdWithIncludeModelDefinition.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelUpdateDecommissioned.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelsGet.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelsGetWithDependenciesAndIncludeModelDefinition.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchComponentAdvancedExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchComponentBasicExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchRelationshipAdvancedExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchRelationshipBasicExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchTwinAdvancedExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchTwinBasicExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PutTwinAdvancedExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PutTwinBasicExample.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryFirstPage.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryJoin.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryNextPage.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/SendTelemetry.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/SendTelemetryFromComponent.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/Azure.DigitalTwins.Core.Tests.csproj create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/BasicRelationshipUnitTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/ComponentTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinClientTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinRelationshipTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwins/updateTwin.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinsTestEnvironment.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/E2eTestBase.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/EventRouteTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/FakeTokenCredential.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/Models/wifi.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/ModelsTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/PayloadHelperUnitTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/QueryTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ComponentTests/Component_Lifecycle.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ComponentTests/Component_LifecycleAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinRelationshipTests/Relationships_Lifecycle.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinRelationshipTests/Relationships_LifecycleAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_IncorrectCredentials_ThrowsUnauthorizedException.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_IncorrectCredentials_ThrowsUnauthorizedExceptionAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_Lifecycle.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_LifecycleAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_TwinNotExist_ThrowsNotFoundException.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_TwinNotExist_ThrowsNotFoundExceptionAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_EventRouteNotExist_ThrowsNotFoundException.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_EventRouteNotExist_ThrowsNotFoundExceptionAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_Lifecycle.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_LifecycleAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_MalformedEventRouteFilter_ThrowsBadRequestException.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_MalformedEventRouteFilter_ThrowsBadRequestExceptionAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/ModelData_DisplayNameAndDescription_Deserializes.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/ModelData_DisplayNameAndDescription_DeserializesAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_Lifecycle.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_LifecycleAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_MalformedModelId_ThrowsBadRequestException.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_MalformedModelId_ThrowsBadRequestExceptionAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelAlreadyExists_ThrowsConflictException.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelAlreadyExists_ThrowsConflictExceptionAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelNotExists_ThrowsNotFoundException.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelNotExists_ThrowsNotFoundExceptionAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/QueryTests/Query_ValidQuery_Success.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/QueryTests/Query_ValidQuery_SuccessAsync.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssetSettings.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssets.Designer.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssets.resx create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssetsHelper.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestSettings.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/UpdateOperationsUtilityUnitTests.cs create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/UpdateSessionRecords.ps1 create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/config/common.config.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/config/common.test.assets.config.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/manifest.json create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/prerequisite readme.md create mode 100644 sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/setup.ps1 create mode 100644 sdk/digitaltwins/Export-AdtApis.ps1 create mode 100644 sdk/digitaltwins/Update-AdtSnippets.ps1 create mode 100644 sdk/digitaltwins/remove-test-resources-pre.ps1 create mode 100644 sdk/digitaltwins/test-resources.json diff --git a/sdk/digitaltwins/.gitignore b/sdk/digitaltwins/.gitignore index 76b9f1a863989..419f8a9b81e47 100644 --- a/sdk/digitaltwins/.gitignore +++ b/sdk/digitaltwins/.gitignore @@ -1,3 +1,4 @@ *.config.json !*common.config.json !*common.test.assets.config.json +*.etl diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/.gitignore b/sdk/digitaltwins/Azure.DigitalTwins.Core/.gitignore new file mode 100644 index 0000000000000..5d4b0f08d7cca --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/.gitignore @@ -0,0 +1,4 @@ +launchSettings.json +*.config.json +!*common.config.json +!*common.test.assets.config.json diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/Azure.DigitalTwins.Core.sln b/sdk/digitaltwins/Azure.DigitalTwins.Core/Azure.DigitalTwins.Core.sln new file mode 100644 index 0000000000000..55edb7319efb5 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/Azure.DigitalTwins.Core.sln @@ -0,0 +1,53 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29806.167 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.DigitalTwins.Core", "src\Azure.DigitalTwins.Core.csproj", "{E33D09D9-D809-472C-82E6-6A26BDB86FC2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.DigitalTwins.Core.Tests", "tests\Azure.DigitalTwins.Core.Tests.csproj", "{4F476D56-DDE7-43D3-8CB4-BA1E77F5A300}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DigitalTwinsClientSample", "samples\DigitalTwinsClientSample\DigitalTwinsClientSample.csproj", "{293475B6-4D30-4033-95A0-FA94F168CC63}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C8218152-0AC8-4EB8-A501-A721109D37BF}" + ProjectSection(SolutionItems) = preProject + api\Azure.DigitalTwins.Core.netstandard2.0.cs = api\Azure.DigitalTwins.Core.netstandard2.0.cs + ..\ci.yml = ..\ci.yml + ..\Export-AdtApis.ps1 = ..\Export-AdtApis.ps1 + ..\remove-test-resources-pre.ps1 = ..\remove-test-resources-pre.ps1 + ..\test-resources.json = ..\test-resources.json + ..\tests.yml = ..\tests.yml + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core.TestFramework", "..\..\core\Azure.Core.TestFramework\src\Azure.Core.TestFramework.csproj", "{1FC8A3EA-3C0D-4DDF-B710-A7091F2CEBB1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E33D09D9-D809-472C-82E6-6A26BDB86FC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E33D09D9-D809-472C-82E6-6A26BDB86FC2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E33D09D9-D809-472C-82E6-6A26BDB86FC2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E33D09D9-D809-472C-82E6-6A26BDB86FC2}.Release|Any CPU.Build.0 = Release|Any CPU + {4F476D56-DDE7-43D3-8CB4-BA1E77F5A300}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F476D56-DDE7-43D3-8CB4-BA1E77F5A300}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F476D56-DDE7-43D3-8CB4-BA1E77F5A300}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F476D56-DDE7-43D3-8CB4-BA1E77F5A300}.Release|Any CPU.Build.0 = Release|Any CPU + {293475B6-4D30-4033-95A0-FA94F168CC63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {293475B6-4D30-4033-95A0-FA94F168CC63}.Debug|Any CPU.Build.0 = Debug|Any CPU + {293475B6-4D30-4033-95A0-FA94F168CC63}.Release|Any CPU.ActiveCfg = Release|Any CPU + {293475B6-4D30-4033-95A0-FA94F168CC63}.Release|Any CPU.Build.0 = Release|Any CPU + {1FC8A3EA-3C0D-4DDF-B710-A7091F2CEBB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FC8A3EA-3C0D-4DDF-B710-A7091F2CEBB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FC8A3EA-3C0D-4DDF-B710-A7091F2CEBB1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FC8A3EA-3C0D-4DDF-B710-A7091F2CEBB1}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A97F4B90-2591-4689-B1F8-5F21FE6D6CAE} + EndGlobalSection +EndGlobal diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/CHANGELOG.md b/sdk/digitaltwins/Azure.DigitalTwins.Core/CHANGELOG.md new file mode 100644 index 0000000000000..e86ad48fff4bc --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/CHANGELOG.md @@ -0,0 +1,3 @@ +# Release History + +## 1.0.0-preview.1 (Unreleased) \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/capture_logs_readme.md b/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/capture_logs_readme.md new file mode 100644 index 0000000000000..c0bab936ea4cd --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/capture_logs_readme.md @@ -0,0 +1,11 @@ +# Capturing Traces + +## Windows +On Windows logman or PerfView can be used to collect traces. For more information please see https://github.com/dotnet/runtime/blob/master/docs/workflow/debugging/libraries/windows-instructions.md#traces + +## Linux +On Linux and OSX LTTNG and perfcollect can be used to collect traces. For more information please see https://github.com/dotnet/runtime/blob/master/docs/project/linux-performance-tracing.md + +## Azure providers + +* `*Azure-Core {44cbc7c6-6776-5f3c-36c1-75cd3ef19ea9}`: Http Pipeline related traces. \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_providers.txt b/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_providers.txt new file mode 100644 index 0000000000000..fde65f92fbe7b --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_providers.txt @@ -0,0 +1 @@ +"{44cbc7c6-6776-5f3c-36c1-75cd3ef19ea9}" diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_startlog.cmd b/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_startlog.cmd new file mode 100644 index 0000000000000..c249b460ae724 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_startlog.cmd @@ -0,0 +1,2 @@ +logman create trace DigitalTwinsTrace -o digitaltwins.etl -pf digitaltwins_providers.txt +logman start DigitalTwinsTrace diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_stoplog.cmd b/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_stoplog.cmd new file mode 100644 index 0000000000000..d54bf53ea9a05 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/CaptureLogs/digitaltwins_stoplog.cmd @@ -0,0 +1,2 @@ +logman stop DigitalTwinsTrace +logman delete DigitalTwinsTrace diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/CodeMaid.config b/sdk/digitaltwins/Azure.DigitalTwins.Core/CodeMaid.config new file mode 100644 index 0000000000000..5382ce6fd8f0b --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/CodeMaid.config @@ -0,0 +1,41 @@ + + + + +
+ + + + + + True + + + True + + + True + + + 120 + + + False + + + // Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + + + + True + + + 1 + + + False + + + + diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/Directory.Build.props b/sdk/digitaltwins/Azure.DigitalTwins.Core/Directory.Build.props new file mode 100644 index 0000000000000..1a9611bd49242 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/Directory.Build.props @@ -0,0 +1,6 @@ + + + + diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/README.md b/sdk/digitaltwins/Azure.DigitalTwins.Core/README.md new file mode 100644 index 0000000000000..01761e88e9a21 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/README.md @@ -0,0 +1,78 @@ +# Azure IoT Digital Twin client library for .NET + +This library provides access to the Azure Digital Twins service for managing twins, models, relationships, etc. + + [Source code][source] | [Package (nuget)][package] + +## Getting started + +### Authenticate the Client + +### Install the package + +Install the Azure Digital Twins client library for .NET with [NuGet][nuget]: + +```PowerShell +Install-Package Azure.DigitalTwins.Core +``` +### Prerequisites + +* An [Azure subscription][azure_sub]. + +## Key concepts + +## Examples + +## Developer guide + +### Source code folder structure + +### /src +The digital twins public client `DigitalTwinsClient` and the additional configuration options that can be sent to the digital twins service `DigitalTwinsClientOptions`. + +### /src/swagger +The swagger file that defines the structure of the REST APIs used by the digital twins client library. + +To generate the code, run the powershell script present [here](./src/generate.ps1). + +### /src/Generated +The code generated by autorest using the swagger file defined under /src/swagger. + +### /src/Customized +The customzied code written to override the following behavior of auto-generated code: +- Rename some of the generated types, eg. [GetModelsOptions](./src/Customized/Models/GetModelsOptions.cs) +- Declare some of the generated types as **internal**, instead of the autorest default of **public**. +- Declare some methods to accept input parameters as **strings** instead of **objects**. +- Declare some methods to return the response as **strings** instead of **objects**. + +### /src/Models +Constants useful for use with the digital twins client. + +### /src/Properties +Assembly properties required for running unit tests against signed assemblies in Debug mode. + +### /src/Serialization +Serialization helpers provided to help serialize/deseralize commonly used types within the digital twins service. + +Any time the client library code is updated, you will need to run the script [here](./../Export-AdtApis.ps1), which will update the corresponding API surface. + +## Troubleshooting + +## Next steps + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct]. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments. + + +[azure_cli]: https://docs.microsoft.com/cli/azure +[azure_sub]: https://azure.microsoft.com/free/ +[source]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/iot/adt +[package]: https://www.nuget.org/packages/Azure.IoT.DigitalTwins +[code_of_conduct]: https://opensource.microsoft.com/codeofconduct/ +[nuget]: https://www.nuget.org/ +[azure_core_library]: https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/core/Azure.Core diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/api/Azure.DigitalTwins.Core.netstandard2.0.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/api/Azure.DigitalTwins.Core.netstandard2.0.cs new file mode 100644 index 0000000000000..cfade0ca518ce --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/api/Azure.DigitalTwins.Core.netstandard2.0.cs @@ -0,0 +1,179 @@ +namespace Azure.DigitalTwins.Core +{ + public partial class DigitalTwinsClient + { + protected DigitalTwinsClient() { } + public DigitalTwinsClient(System.Uri endpoint, Azure.Core.TokenCredential credential) { } + public DigitalTwinsClient(System.Uri endpoint, Azure.Core.TokenCredential credential, Azure.DigitalTwins.Core.DigitalTwinsClientOptions options) { } + public virtual Azure.Response CreateDigitalTwin(string digitalTwinId, string digitalTwin, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> CreateDigitalTwinAsync(string digitalTwinId, string digitalTwin, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response CreateEventRoute(string eventRouteId, Azure.DigitalTwins.Core.Models.EventRoute eventRoute, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task CreateEventRouteAsync(string eventRouteId, Azure.DigitalTwins.Core.Models.EventRoute eventRoute, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response> CreateModels(System.Collections.Generic.IEnumerable models, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task>> CreateModelsAsync(System.Collections.Generic.IEnumerable models, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response CreateRelationship(string digitalTwinId, string relationshipId, string relationship, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> CreateRelationshipAsync(string digitalTwinId, string relationshipId, string relationship, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response DecommissionModel(string modelId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task DecommissionModelAsync(string modelId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response DeleteDigitalTwin(string digitalTwinId, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task DeleteDigitalTwinAsync(string digitalTwinId, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response DeleteEventRoute(string eventRouteId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task DeleteEventRouteAsync(string eventRouteId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response DeleteModel(string modelId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task DeleteModelAsync(string modelId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response DeleteRelationship(string digitalTwinId, string relationshipId, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task DeleteRelationshipAsync(string digitalTwinId, string relationshipId, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetComponent(string digitalTwinId, string componentPath, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetComponentAsync(string digitalTwinId, string componentPath, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetDigitalTwin(string digitalTwinId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetDigitalTwinAsync(string digitalTwinId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetEventRoute(string eventRouteId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetEventRouteAsync(string eventRouteId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Pageable GetEventRoutes(Azure.DigitalTwins.Core.Models.EventRoutesListOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.AsyncPageable GetEventRoutesAsync(Azure.DigitalTwins.Core.Models.EventRoutesListOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Pageable GetIncomingRelationships(string digitalTwinId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.AsyncPageable GetIncomingRelationshipsAsync(string digitalTwinId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetModel(string modelId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetModelAsync(string modelId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Pageable GetModels(System.Collections.Generic.IEnumerable dependenciesFor = null, bool includeModelDefinition = false, Azure.DigitalTwins.Core.Models.GetModelsOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.AsyncPageable GetModelsAsync(System.Collections.Generic.IEnumerable dependenciesFor = null, bool includeModelDefinition = false, Azure.DigitalTwins.Core.Models.GetModelsOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response GetRelationship(string digitalTwinId, string relationshipId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> GetRelationshipAsync(string digitalTwinId, string relationshipId, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Pageable GetRelationships(string digitalTwinId, string relationshipName = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.AsyncPageable GetRelationshipsAsync(string digitalTwinId, string relationshipName = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response PublishComponentTelemetry(string digitalTwinId, string componentName, string payload, Azure.DigitalTwins.Core.Models.TelemetryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task PublishComponentTelemetryAsync(string digitalTwinId, string componentName, string payload, Azure.DigitalTwins.Core.Models.TelemetryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response PublishTelemetry(string digitalTwinId, string payload, Azure.DigitalTwins.Core.Models.TelemetryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task PublishTelemetryAsync(string digitalTwinId, string payload, Azure.DigitalTwins.Core.Models.TelemetryOptions options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Pageable Query(string query, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.AsyncPageable QueryAsync(string query, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response UpdateComponent(string digitalTwinId, string componentPath, string componentUpdateOperations, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> UpdateComponentAsync(string digitalTwinId, string componentPath, string componentUpdateOperations, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response UpdateDigitalTwin(string digitalTwinId, string digitalTwinUpdateOperations, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task> UpdateDigitalTwinAsync(string digitalTwinId, string digitalTwinUpdateOperations, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual Azure.Response UpdateRelationship(string digitalTwinId, string relationshipId, string relationshipUpdateOperations, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + public virtual System.Threading.Tasks.Task UpdateRelationshipAsync(string digitalTwinId, string relationshipId, string relationshipUpdateOperations, Azure.DigitalTwins.Core.RequestOptions requestOptions = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; } + } + public partial class DigitalTwinsClientOptions : Azure.Core.ClientOptions + { + public DigitalTwinsClientOptions(Azure.DigitalTwins.Core.DigitalTwinsClientOptions.ServiceVersion version = Azure.DigitalTwins.Core.DigitalTwinsClientOptions.ServiceVersion.V2020_05_31_preview) { } + public Azure.DigitalTwins.Core.DigitalTwinsClientOptions.ServiceVersion Version { get { throw null; } } + public enum ServiceVersion + { + V2020_05_31_preview = 1, + } + } + public partial class RequestOptions + { + public RequestOptions() { } + public string IfMatchEtag { get { throw null; } set { } } + } +} +namespace Azure.DigitalTwins.Core.Models +{ + public partial class EventRoute + { + public EventRoute(string endpointName) { } + public string EndpointName { get { throw null; } set { } } + public string Filter { get { throw null; } set { } } + public string Id { get { throw null; } } + } + public partial class EventRoutesListOptions + { + public EventRoutesListOptions() { } + public int? MaxItemCount { get { throw null; } set { } } + } + public partial class GetModelsOptions + { + public GetModelsOptions() { } + public int? MaxItemCount { get { throw null; } set { } } + } + public partial class IncomingRelationship + { + internal IncomingRelationship() { } + public string RelationshipId { get { throw null; } } + public string RelationshipLink { get { throw null; } } + public string RelationshipName { get { throw null; } } + public string SourceId { get { throw null; } } + } + public partial class ModelData + { + internal ModelData() { } + public bool? Decommissioned { get { throw null; } } + public System.Collections.Generic.IDictionary Description { get { throw null; } } + public System.Collections.Generic.IDictionary DisplayName { get { throw null; } } + public string Id { get { throw null; } } + public string Model { get { throw null; } } + public System.DateTimeOffset? UploadTime { get { throw null; } } + } + public partial class TelemetryOptions + { + public TelemetryOptions() { } + public string MessageId { get { throw null; } set { } } + public System.DateTimeOffset TimeStamp { get { throw null; } set { } } + } +} +namespace Azure.DigitalTwins.Core.Queries +{ + public static partial class QueryChargeHelper + { + public static bool TryGetQueryCharge(Azure.Page page, out float queryCharge) { throw null; } + } +} +namespace Azure.DigitalTwins.Core.Serialization +{ + public partial class BasicDigitalTwin + { + public BasicDigitalTwin() { } + [System.Text.Json.Serialization.JsonExtensionDataAttribute] + public System.Collections.Generic.IDictionary CustomProperties { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("$dtId")] + public string Id { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("$metadata")] + public Azure.DigitalTwins.Core.Serialization.DigitalTwinMetadata Metadata { get { throw null; } set { } } + } + public partial class BasicRelationship + { + public BasicRelationship() { } + [System.Text.Json.Serialization.JsonExtensionDataAttribute] + public System.Collections.Generic.IDictionary CustomProperties { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("$relationshipId")] + public string Id { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("$relationshipName")] + public string Name { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("$sourceId")] + public string SourceId { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("$targetId")] + public string TargetId { get { throw null; } set { } } + } + public partial class DigitalTwinMetadata + { + public DigitalTwinMetadata() { } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("$model")] + public string ModelId { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonExtensionDataAttribute] + public System.Collections.Generic.IDictionary ModelProperties { get { throw null; } set { } } + } + public partial class UpdateOperationsUtility + { + public UpdateOperationsUtility() { } + public void AppendAddOp(string path, object value) { } + public void AppendRemoveOp(string path) { } + public void AppendReplaceOp(string path, object value) { } + public string Serialize() { throw null; } + } + public partial class WritableProperty + { + public WritableProperty() { } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("ackCode")] + public int AckCode { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("ackDescription")] + public string AckDescription { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("ackVersion")] + public int AckVersion { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("desiredValue")] + public object DesiredValue { get { throw null; } set { } } + [System.Text.Json.Serialization.JsonPropertyNameAttribute("desiredVersion")] + public int DesiredVersion { get { throw null; } set { } } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ComponentSamples.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ComponentSamples.cs new file mode 100644 index 0000000000000..6984db5e0ae92 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ComponentSamples.cs @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading.Tasks; +using Azure.DigitalTwins.Core.Serialization; +using static Azure.DigitalTwins.Core.Samples.SampleLogger; +using static Azure.DigitalTwins.Core.Samples.UniqueIdHelper; + +namespace Azure.DigitalTwins.Core.Samples +{ + internal class ComponentSamples + { + private DigitalTwinsClient DigitalTwinsClient { get; } + + public ComponentSamples(DigitalTwinsClient dtClient) + { + DigitalTwinsClient = dtClient; + } + + /// + /// Creates a digital twin with Component and upates Component + /// + public async Task RunSamplesAsync() + { + 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, DigitalTwinsClient).ConfigureAwait(false); + string modelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, DigitalTwinsClient).ConfigureAwait(false); + string twinId = await GetUniqueTwinIdAsync(SamplesConstants.TemporaryTwinPrefix, DigitalTwinsClient).ConfigureAwait(false); + + string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload + .Replace(SamplesConstants.ComponentId, componentModelId); + + string newModelPayload = SamplesConstants.TemporaryModelPayload + .Replace(SamplesConstants.ModelId, modelId) + .Replace(SamplesConstants.ComponentId, componentModelId); + + // Then we create models + await DigitalTwinsClient.CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload }).ConfigureAwait(false); + Console.WriteLine($"Successfully created models with Ids: {componentModelId}, {modelId}"); + + // Create digital twin with Component payload + string twinPayload = SamplesConstants.TemporaryTwinPayload + .Replace(SamplesConstants.ModelId, modelId) + .Replace(SamplesConstants.ComponentId, componentModelId); + + await DigitalTwinsClient.CreateDigitalTwinAsync(twinId, twinPayload).ConfigureAwait(false); + Console.WriteLine($"Created digital twin {twinId}."); + + #region Snippet:DigitalTwinSampleUpdateComponent + + // Update Component with replacing property value + string propertyPath = "/ComponentProp1"; + string propValue = "New Value"; + + var componentUpdateUtility = new UpdateOperationsUtility(); + componentUpdateUtility.AppendReplaceOp(propertyPath, propValue); + + Response response = await DigitalTwinsClient.UpdateComponentAsync(twinId, SamplesConstants.ComponentPath, componentUpdateUtility.Serialize()); + + #endregion Snippet:DigitalTwinSampleUpdateComponent + + Console.WriteLine($"Updated component for digital twin {twinId}. Update response status: {response.GetRawResponse().Status}"); + + // Get Component + + #region Snippet:DigitalTwinSampleGetComponent + + response = await DigitalTwinsClient.GetComponentAsync(twinId, SamplesConstants.ComponentPath).ConfigureAwait(false); + + #endregion Snippet:DigitalTwinSampleGetComponent + + Console.WriteLine($"Get component for digital twin: \n{response.Value}. Get response status: {response.GetRawResponse().Status}"); + + // Now delete a Twin + await DigitalTwinsClient.DeleteDigitalTwinAsync(twinId).ConfigureAwait(false); + + // Delete models + try + { + await DigitalTwinsClient.DeleteModelAsync(modelId).ConfigureAwait(false); + await DigitalTwinsClient.DeleteModelAsync(componentModelId).ConfigureAwait(false); + } + catch (RequestFailedException ex) + { + Console.WriteLine($"Failed to delete models due to {ex}"); + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/BuildingTwin.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/BuildingTwin.json new file mode 100644 index 0000000000000..ba5291c2b5715 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/BuildingTwin.json @@ -0,0 +1,7 @@ +{ + "$metadata": { + "$model": "dtmi:samples:Building;1" + }, + "AverageTemperature": 68, + "TemperatureUnit": "Celsius" +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/FloorTwin.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/FloorTwin.json new file mode 100644 index 0000000000000..f9a08edfd8bb7 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/FloorTwin.json @@ -0,0 +1,6 @@ +{ + "$metadata": { + "$model": "dtmi:samples:Floor;1" + }, + "AverageTemperature": 75 +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/HVACTwin.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/HVACTwin.json new file mode 100644 index 0000000000000..49b4ad6172329 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/HVACTwin.json @@ -0,0 +1,8 @@ +{ + "$metadata": { + "$model": "dtmi:samples:HVAC;1" + }, + "Efficiency": 94, + "TargetTemperature": 72, + "TargetHumidity": 30 +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/RoomTwin.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/RoomTwin.json new file mode 100644 index 0000000000000..0e2f909aeeebc --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins/RoomTwin.json @@ -0,0 +1,16 @@ +{ + "$metadata": { + "$model": "dtmi:samples:Room;1" + }, + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "wifiAccessPoint": { + "$metadata": { + "$model": "dtmi:samples:Wifi;1" + }, + "RouterName": "Cisco1", + "Network": "Room1" + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Building.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Building.json new file mode 100644 index 0000000000000..1a032d6364737 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Building.json @@ -0,0 +1,35 @@ +{ + "@id": "dtmi:samples:Building;1", + "@type": "Interface", + "@context": "dtmi:dtdl:context;2", + "displayName": "Building", + "contents": [ + { + "@type": "Relationship", + "name": "has", + "target": "dtmi:samples:Floor;1", + "properties": [ + { + "@type": "Property", + "name": "isAccessRestricted", + "schema": "boolean" + } + ] + }, + { + "@type": "Relationship", + "name": "isEquippedWith", + "target": "dtmi:samples:HVAC;1" + }, + { + "@type": "Property", + "name": "AverageTemperature", + "schema": "double" + }, + { + "@type": "Property", + "name": "TemperatureUnit", + "schema": "string" + } + ] +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Floor.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Floor.json new file mode 100644 index 0000000000000..fe4ea891228b6 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Floor.json @@ -0,0 +1,18 @@ +{ + "@id": "dtmi:samples:Floor;1", + "@type": "Interface", + "@context": "dtmi:dtdl:context;2", + "displayName": "Floor", + "contents": [ + { + "@type": "Relationship", + "name": "contains", + "target": "dtmi:samples:Room;1" + }, + { + "@type": "Property", + "name": "AverageTemperature", + "schema": "double" + } + ] +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/HVAC.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/HVAC.json new file mode 100644 index 0000000000000..35186f130a95a --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/HVAC.json @@ -0,0 +1,28 @@ +{ + "@id": "dtmi:samples:HVAC;1", + "@type": "Interface", + "@context": "dtmi:dtdl:context;2", + "displayName": "HVAC", + "contents": [ + { + "@type": "Property", + "name": "Efficiency", + "schema": "double" + }, + { + "@type": "Property", + "name": "TargetTemperature", + "schema": "double" + }, + { + "@type": "Property", + "name": "TargetHumidity", + "schema": "double" + }, + { + "@type": "Relationship", + "name": "controlsTemperature", + "target": "dtmi:samples:Floor;1" + } + ] +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Room.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Room.json new file mode 100644 index 0000000000000..a6c2dfe6bd781 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Room.json @@ -0,0 +1,33 @@ +{ + "@id": "dtmi:samples:Room;1", + "@type": "Interface", + "@context": "dtmi:dtdl:context;2", + "displayName": "Room", + "contents": [ + { + "@type": "Property", + "name": "Temperature", + "schema": "double" + }, + { + "@type": "Property", + "name": "Humidity", + "schema": "double" + }, + { + "@type": "Property", + "name": "IsOccupied", + "schema": "boolean" + }, + { + "@type": "Property", + "name": "EmployeeId", + "schema": "string" + }, + { + "@type": "Component", + "name": "wifiAccessPoint", + "schema": "dtmi:samples:Wifi;1" + } + ] +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Wifi.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Wifi.json new file mode 100644 index 0000000000000..a2b07b484334c --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models/Wifi.json @@ -0,0 +1,18 @@ +{ + "@id": "dtmi:samples:Wifi;1", + "@type": "Interface", + "@context": "dtmi:dtdl:context;2", + "displayName": "Wifi", + "contents": [ + { + "@type": "Property", + "name": "RouterName", + "schema": "string" + }, + { + "@type": "Property", + "name": "Network", + "schema": "string" + } + ] +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Relationships/HospitalRelationships.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Relationships/HospitalRelationships.json new file mode 100644 index 0000000000000..82d426e17a3d6 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Relationships/HospitalRelationships.json @@ -0,0 +1,27 @@ +[ + { + "$relationshipId": "BuildingHasFloor", + "$sourceId": "BuildingTwin", + "$relationshipName": "has", + "$targetId": "FloorTwin", + "isAccessRestricted": false + }, + { + "$relationshipId": "BuildingIsEquippedWithHVAC", + "$sourceId": "BuildingTwin", + "$relationshipName": "isEquippedWith", + "$targetId": "HVACTwin" + }, + { + "$relationshipId": "HVACCoolsFloor", + "$sourceId": "HVACTwin", + "$relationshipName": "controlsTemperature", + "$targetId": "FloorTwin" + }, + { + "$relationshipId": "FloorContainsRoom", + "$sourceId": "FloorTwin", + "$relationshipName": "contains", + "$targetId": "RoomTwin" + } +] diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsClientSample.csproj b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsClientSample.csproj new file mode 100644 index 0000000000000..b565174efad77 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsClientSample.csproj @@ -0,0 +1,27 @@ + + + + Exe + netcoreapp3.1 + Azure.DigitalTwins.Core.Samples + + + + + + + + + + + + + PreserveNewest + + + + + + + + diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsLifecycleSamples.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsLifecycleSamples.cs new file mode 100644 index 0000000000000..9202695873592 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DigitalTwinsLifecycleSamples.cs @@ -0,0 +1,471 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.DigitalTwins.Core.Models; +using Azure.DigitalTwins.Core.Queries; +using Azure.DigitalTwins.Core.Serialization; +using static Azure.DigitalTwins.Core.Samples.SampleLogger; +using static Azure.DigitalTwins.Core.Samples.UniqueIdHelper; + +namespace Azure.DigitalTwins.Core.Samples +{ + /// + /// This sample creates all the models in \DTDL\Models folder in the ADT service instance + /// and creates the corresponding twins in \DTDL\DigitalTwins folder + /// The Diagram for the Hospital model looks like this: + /// + /// +------------+ + /// | Building +-----isEquippedWith-----+ + /// +------------+ | + /// | v + /// has +-----+ + /// | | HVAC| + /// v +-----+ + /// +------------+ | + /// | Floor +<--controlsTemperature--+ + /// +------------+ + /// | + /// contains + /// | + /// v + /// +------------+ +-----------------+ + /// | Room |-with component->| WifiAccessPoint | + /// +------------+ +-----------------+ + /// + internal class DigitalTwinsLifecycleSamples + { + // Json folders and file paths + private static readonly string s_dtdlDirectoryPath = Path.Combine(GetWorkingDirectory(), "DTDL"); + + private static readonly string s_modelsPath = Path.Combine(s_dtdlDirectoryPath, "Models"); + private static readonly string s_twinsPath = Path.Combine(s_dtdlDirectoryPath, "DigitalTwins"); + private static readonly string s_relationshipsPath = Path.Combine(s_dtdlDirectoryPath, "Relationships"); + + private readonly string _eventhubEndpointName; + private readonly string _eventRouteId = $"sampleEventRouteId-{Guid.NewGuid()}"; + + private DigitalTwinsClient DigitalTwinsClient { get; } + + public DigitalTwinsLifecycleSamples(DigitalTwinsClient dtClient, string eventhubEndpointName) + { + _eventhubEndpointName = eventhubEndpointName; + DigitalTwinsClient = dtClient; + } + + /// + /// Creates all Models in the Models folder + /// Creates all DigitalTwins in the DigitalTwins folder + /// Connects all DigitalTwins using relationships in the Relationships folder. + /// + public async Task RunSamplesAsync() + { + // Ensure existing twins with the same name are deleted first + await DeleteTwinsAsync().ConfigureAwait(false); + + // Delete existing models + await DeleteAllModelsAsync().ConfigureAwait(false); + + // Create all the models + await AddAllModelsAsync().ConfigureAwait(false); + + // Get all models + await GetAllModelsAsync().ConfigureAwait(false); + + // Create twin counterparts for all the models + await CreateAllTwinsAsync().ConfigureAwait(false); + + // Get all twins + await QueryTwinsAsync().ConfigureAwait(false); + + // Create all the relationships + await ConnectTwinsTogetherAsync().ConfigureAwait(false); + + // Creating event route + await CreateEventRoute().ConfigureAwait(false); + + // Get all event routes + await GetEventRoutes().ConfigureAwait(false); + + // Deleting event route + await DeleteEventRoute().ConfigureAwait(false); + } + + /// + /// Delete models created by FullLifecycleSample for the ADT service instance + /// + + private async Task DeleteAllModelsAsync() + { + PrintHeader("DELETING MODELS"); + + try + { + // This is to ensure models are deleted in an order such that no other models are referencing it + var models = new Queue(); + models.Enqueue(SamplesConstants.RoomModelId); + models.Enqueue(SamplesConstants.WifiModelId); + models.Enqueue(SamplesConstants.BuildingModelId); + models.Enqueue(SamplesConstants.FloorModelId); + models.Enqueue(SamplesConstants.HvacModelId); + + foreach (string modelId in models) + { + await DigitalTwinsClient.DeleteModelAsync(modelId).ConfigureAwait(false); + Console.WriteLine($"Deleted model {modelId}"); + } + } + catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.NotFound) + { + // Model does not exist. + } + catch (Exception ex) + { + FatalError($"Failed to delete models due to:\n{ex}"); + } + } + + /// + /// Loads all the models found in the Models directory into memory and uses CreateModelsAsync API to create all the models in the ADT service instance + /// + private async Task AddAllModelsAsync() + { + PrintHeader("CREATING MODELS"); + + List modelsToCreate = FileHelper.LoadAllFilesInPath(s_modelsPath).Values.ToList(); + + if (modelsToCreate == null || !modelsToCreate.Any()) + { + throw new Exception("Could not load models from disk."); + } + + try + { + Response> response = await DigitalTwinsClient.CreateModelsAsync(modelsToCreate).ConfigureAwait(false); + Console.WriteLine($"Created models status: {response.GetRawResponse().Status}"); + } + catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.Conflict) + { + Console.WriteLine($"One or more models already exist. Continuing with the sample optimistically."); + } + catch (Exception ex) + { + FatalError($"Failed to create models due to:\n{ex}"); + } + } + + /// + /// Gets all the models within the ADT service instance. + /// + public async Task GetAllModelsAsync() + { + PrintHeader("LISTING MODELS"); + try + { + // Get all the twin types + + #region Snippet:DigitalTwinSampleGetModels + + AsyncPageable allModels = DigitalTwinsClient.GetModelsAsync(); + await foreach (ModelData model in allModels) + { + Console.WriteLine($"Model Id: {model.Id}, display name: {model.DisplayName["en"]}, upload time: {model.UploadTime}, is decommissioned: {model.Decommissioned}"); + } + + #endregion Snippet:DigitalTwinSampleGetModels + } + catch (Exception ex) + { + FatalError($"Failed to get all the models due to:\n{ex}"); + } + } + + /// + /// Delete a twin, and any relationships it might have + /// + public async Task DeleteTwinsAsync() + { + PrintHeader("DELETE DIGITAL TWINS"); + Dictionary twins = FileHelper.LoadAllFilesInPath(s_twinsPath); + + foreach (KeyValuePair twin in twins) + { + try + { + // Delete all relationships + + #region Snippet:DigitalTwinSampleGetRelationships + + AsyncPageable relationships = DigitalTwinsClient.GetRelationshipsAsync(twin.Key); + + #endregion Snippet:DigitalTwinSampleGetRelationships + + await foreach (var relationshipJson in relationships) + { + BasicRelationship relationship = JsonSerializer.Deserialize(relationshipJson); + await DigitalTwinsClient.DeleteRelationshipAsync(twin.Key, relationship.Id).ConfigureAwait(false); + Console.WriteLine($"Found and deleted relationship {relationship.Id}"); + } + + // Delete any incoming relationships + + #region Snippet:DigitalTwinSampleGetIncomingRelationships + + AsyncPageable incomingRelationships = DigitalTwinsClient.GetIncomingRelationshipsAsync(twin.Key); + + #endregion Snippet:DigitalTwinSampleGetIncomingRelationships + + await foreach (IncomingRelationship incomingRelationship in incomingRelationships) + { + await DigitalTwinsClient.DeleteRelationshipAsync(incomingRelationship.SourceId, incomingRelationship.RelationshipId).ConfigureAwait(false); + Console.WriteLine($"Found and deleted incoming relationship {incomingRelationship.RelationshipId}"); + } + + // Now the digital twin should be safe to delete + + #region Snippet:DigitalTwinSampleDeleteTwin + + await DigitalTwinsClient.DeleteDigitalTwinAsync(twin.Key).ConfigureAwait(false); + + #endregion Snippet:DigitalTwinSampleDeleteTwin + + Console.WriteLine($"Deleted digital twin {twin.Key}"); + } + catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.NotFound) + { + // Digital twin or relationship does not exist + } + catch (RequestFailedException ex) + { + FatalError($"Failed to delete {twin.Key} due to {ex.Message}"); + } + } + } + + /// + /// Creates all twins specified in the \DTDL\DigitalTwins directory + /// + public async Task CreateAllTwinsAsync() + { + PrintHeader("CREATE DIGITAL TWINS"); + Dictionary twins = FileHelper.LoadAllFilesInPath(s_twinsPath); + + // Call APIs to create the twins. + foreach (KeyValuePair twin in twins) + { + try + { + #region Snippet:DigitalTwinSampleCreateTwin + + Response response = await DigitalTwinsClient.CreateDigitalTwinAsync(twin.Key, twin.Value).ConfigureAwait(false); + + #endregion Snippet:DigitalTwinSampleCreateTwin + + Console.WriteLine($"Created digital twin {twin.Key}. Create response status: {response.GetRawResponse().Status}"); + Console.WriteLine($"Body: {response?.Value}"); + } + catch (Exception ex) + { + FatalError($"Could not create digital twin {twin.Key} due to {ex}"); + } + } + } + + public async Task QueryTwinsAsync() + { + PrintHeader("QUERY DIGITAL TWINS"); + + try + { + Console.WriteLine("Making a twin query and iterating over the results."); + + #region Snippet:DigitalTwinSampleQueryTwins + + // This code snippet demonstrates the simplest way to iterate over the digital twin results, where paging + // happens under the covers. + AsyncPageable asyncPageableResponse = DigitalTwinsClient.QueryAsync("SELECT * FROM digitaltwins"); + + // Iterate over the twin instances in the pageable response. + // The "await" keyword here is required because new pages will be fetched when necessary, + // which involves a request to the service. + await foreach (string response in asyncPageableResponse) + { + BasicDigitalTwin twin = JsonSerializer.Deserialize(response); + Console.WriteLine($"Found digital twin: {twin.Id}"); + } + + #endregion Snippet:DigitalTwinSampleQueryTwins + + Console.WriteLine("Making a twin query, with query-charge header extraction."); + + #region Snippet:DigitalTwinSampleQueryTwinsWithQueryCharge + + // This code snippet demonstrates how you could extract the query charges incurred when calling + // the query API. It iterates over the response pages first to access to the query-charge header, + // and then the digital twin results within each page. + + AsyncPageable asyncPageableResponseWithCharge = DigitalTwinsClient.QueryAsync("SELECT * FROM digitaltwins"); + int pageNum = 0; + + // The "await" keyword here is required as a call is made when fetching a new page. + await foreach (Page page in asyncPageableResponseWithCharge.AsPages()) + { + Console.WriteLine($"Page {++pageNum} results:"); + + // Extract the query-charge header from the page + if (QueryChargeHelper.TryGetQueryCharge(page, out float queryCharge)) + { + Console.WriteLine($"Query charge was: {queryCharge}"); + } + + // Iterate over the twin instances. + // The "await" keyword is not required here as the paged response is local. + foreach (string response in page.Values) + { + BasicDigitalTwin twin = JsonSerializer.Deserialize(response); + Console.WriteLine($"Found digital twin: {twin.Id}"); + } + } + + #endregion Snippet:DigitalTwinSampleQueryTwinsWithQueryCharge + } + catch (Exception ex) + { + FatalError($"Could not query digital twins due to {ex}"); + } + } + + /// + /// Creates all the relationships defined in the \DTDL\Relationships directory + /// + public async Task ConnectTwinsTogetherAsync() + { + PrintHeader("CONNECT DIGITAL TWINS"); + + // First we load the relationships into memory + Dictionary allRelationships = FileHelper.LoadAllFilesInPath(s_relationshipsPath); + + foreach (KeyValuePair relationshipSet in allRelationships) + { + // For each relationship array we deserialize it first + // We deserialize as BasicRelationship to get the entire custom relationship (custom relationship properties). + IEnumerable relationships = JsonSerializer.Deserialize>(relationshipSet.Value); + + foreach (BasicRelationship relationship in relationships) + { + try + { + #region Snippet:DigitalTwinSampleCreateRelationship + + string serializedRelationship = JsonSerializer.Serialize(relationship); + + await DigitalTwinsClient + .CreateRelationshipAsync( + relationship.SourceId, + relationship.Id, + serializedRelationship) + .ConfigureAwait(false); + + #endregion Snippet:DigitalTwinSampleCreateRelationship + + Console.WriteLine($"Linked {serializedRelationship}"); + } + catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.Conflict) + { + Console.WriteLine($"Relationship {relationship.Id} already exists: {ex.Message}"); + } + } + } + } + + /// + /// Gets all event routes for digital Twin + /// + public async Task GetEventRoutes() + { + PrintHeader("LISTING EVENT ROUTES"); + try + { + #region Snippet:DigitalTwinSampleGetEventRoutes + + AsyncPageable response = DigitalTwinsClient.GetEventRoutesAsync(); + await foreach (EventRoute er in response) + { + Console.WriteLine($"Event route: {er.Id}, endpoint name: {er.EndpointName}"); + } + + #endregion Snippet:DigitalTwinSampleGetEventRoutes + } + catch (Exception ex) + { + FatalError($"Could not get event routes due to {ex.Message}"); + } + } + + /// + /// Creates event route for digital Twin + /// + public async Task CreateEventRoute() + { + PrintHeader("CREATE EVENT ROUTE"); + try + { + #region Snippet:DigitalTwinSampleCreateEventRoute + + string eventFilter = "$eventType = 'DigitalTwinTelemetryMessages' or $eventType = 'DigitalTwinLifecycleNotification'"; + var eventRoute = new EventRoute(_eventhubEndpointName) + { + Filter = eventFilter + }; + + Response createEventRouteResponse = await DigitalTwinsClient.CreateEventRouteAsync(_eventRouteId, eventRoute).ConfigureAwait(false); + + #endregion Snippet:DigitalTwinSampleCreateEventRoute + + Console.WriteLine($"Created event route: {_eventRouteId} Response status: {createEventRouteResponse.Status}"); + } + catch (Exception ex) + { + FatalError($"CreateEventRoute: Failed to create event route due to: {ex.Message}"); + } + } + + /// + /// Deletes event route for digital Twin + /// + public async Task DeleteEventRoute() + { + PrintHeader("DELETING EVENT ROUTE"); + try + { + #region Snippet:DigitalTwinSampleDeleteEventRoute + + Response response = await DigitalTwinsClient.DeleteEventRouteAsync(_eventRouteId).ConfigureAwait(false); + + #endregion Snippet:DigitalTwinSampleDeleteEventRoute + + Console.WriteLine($"Successfully deleted event route: {_eventRouteId}, status: {response.Status}"); + } + catch (Exception ex) + { + FatalError($"Could not delete event routes due to {ex.Message}"); + } + } + + private static string GetWorkingDirectory() + { + string codeBase = Assembly.GetExecutingAssembly().CodeBase; + var uri = new UriBuilder(codeBase); + string path = Uri.UnescapeDataString(uri.Path); + return Path.GetDirectoryName(path); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/FileHelper.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/FileHelper.cs new file mode 100644 index 0000000000000..5671d31ca51e5 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/FileHelper.cs @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.IO; + +namespace Azure.DigitalTwins.Core.Samples +{ + public static class FileHelper + { + /// + /// Loads all json file contents in a path + /// + /// Path to the target directory + /// List of all file names and their content in dictionary format + public static Dictionary LoadAllFilesInPath(string path) + { + string[] allFilesPath = Directory.GetFiles(path, "*.json"); + var fileContents = new Dictionary(); + try + { + // Read all the DTDL files in the directory into memory + foreach (string filePath in allFilesPath) + { + fileContents[GetFileNameFromPath(filePath)] = File.ReadAllText(filePath); + } + + return fileContents; + } + catch (Exception ex) + { + Console.WriteLine($"Error reading twin types from disk due to: {ex.Message}", ConsoleColor.Red); + Environment.Exit(0); + } + + return null; + } + + public static string LoadFileContentsFromFilePath(string path) + { + return File.ReadAllText(path); + } + + public static string GetFileNameFromPath(string path) + { + string fileNameWithExtension = Path.GetFileName(path); + return fileNameWithExtension.Substring(0, fileNameWithExtension.Length - ".json".Length); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ModelLifecycleSamples.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ModelLifecycleSamples.cs new file mode 100644 index 0000000000000..56b08dad8a4b1 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/ModelLifecycleSamples.cs @@ -0,0 +1,117 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Azure.DigitalTwins.Core; +using Azure.DigitalTwins.Core.Models; +using Azure.DigitalTwins.Core.Samples; +using static Azure.DigitalTwins.Core.Samples.SampleLogger; +using static Azure.DigitalTwins.Core.Samples.UniqueIdHelper; + +namespace Azure.DigitalTwins.Samples +{ + internal class ModelLifecycleSamples + { + private DigitalTwinsClient DigitalTwinsClient { get; } + + public ModelLifecycleSamples(DigitalTwinsClient dtClient) + { + DigitalTwinsClient = dtClient; + } + + /// + /// Creates a new model with a random Id + /// Decommission the newly created model and check for success + /// + public async Task RunSamplesAsync() + { + 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, DigitalTwinsClient).ConfigureAwait(false); + string sampleModelId = await GetUniqueModelIdAsync(SamplesConstants.TemporaryModelPrefix, DigitalTwinsClient).ConfigureAwait(false); + + string newComponentModelPayload = SamplesConstants.TemporaryComponentModelPayload + .Replace(SamplesConstants.ComponentId, newComponentModelId); + + string newModelPayload = SamplesConstants.TemporaryModelPayload + .Replace(SamplesConstants.ModelId, sampleModelId) + .Replace(SamplesConstants.ComponentId, newComponentModelId); + + // Then we create the model + + try + { + #region Snippet:DigitalTwinSampleCreateModels + + Response> response = await DigitalTwinsClient.CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload }).ConfigureAwait(false); + Console.WriteLine($"Successfully created a model with Id: {newComponentModelId}, {sampleModelId}, status: {response.GetRawResponse().Status}"); + + #endregion Snippet:DigitalTwinSampleCreateModels + } + 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:DigitalTwinSampleGetModel + + Response sampleModel = await DigitalTwinsClient.GetModelAsync(sampleModelId).ConfigureAwait(false); + + #endregion Snippet:DigitalTwinSampleGetModel + + 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:DigitalTwinSampleDecommisionModel + + try + { + await DigitalTwinsClient.DecommissionModelAsync(sampleModelId).ConfigureAwait(false); + + Console.WriteLine($"Successfully decommissioned model {sampleModelId}"); + } + catch (Exception ex) + { + FatalError($"Failed to decommision model {sampleModelId} due to:\n{ex}"); + } + + #endregion Snippet:DigitalTwinSampleDecommisionModel + + // Now delete created model + + #region Snippet:DigitalTwinSampleDeleteModel + + try + { + await DigitalTwinsClient.DeleteModelAsync(sampleModelId).ConfigureAwait(false); + + Console.WriteLine($"Deleted model {sampleModelId}"); + } + catch (Exception ex) + { + FatalError($"Failed to delete model {sampleModelId} due to:\n{ex}"); + } + + #endregion Snippet:DigitalTwinSampleDeleteModel + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/Options.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/Options.cs new file mode 100644 index 0000000000000..a596f98d80e60 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/Options.cs @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using CommandLine; + +namespace Azure.DigitalTwins.Core.Samples +{ + public class Options + { + public Options(string adtEndpoint, string clientId, string tenantId, string clientSecret, string eventHubName) + { + AdtEndpoint = adtEndpoint; + ClientId = clientId; + TenantId = tenantId; + ClientSecret = clientSecret; + EventHubName = eventHubName; + } + + [Option("adtEndpoint", Required = true, HelpText = "Digital twins service endpoint")] + public string AdtEndpoint { get; } + + [Option("clientId", Required = true, HelpText = "Application client Id")] + public string ClientId { get; } + + [Option("tenantId", Required = true, HelpText = "Application tenant Id")] + public string TenantId { get; } + + [Option("clientSecret", Required = true, HelpText = "Application client secret")] + public string ClientSecret { get; } + + [Option("eventHubName", Required = true, HelpText = "Event Hub Name linked to digital twins instance")] + public string EventHubName { get; } + + public static void HandleParseError(IEnumerable errors) + { + if (errors.IsVersion()) + { + Console.WriteLine("1.0.0"); + return; + } + + if (errors.IsHelp()) + { + Console.WriteLine("Usage: .\\DigitalTwinServiceClientSample.exe " + + "--adtEndpoint " + + "--clientId " + + "--tenantId " + + "--clientSecret " + + "--eventHubName "); + return; + } + + Console.WriteLine("Parser Fail"); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/Program.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/Program.cs new file mode 100644 index 0000000000000..4502ccebc464c --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/Program.cs @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Net.Http; +using System.Threading.Tasks; +using Azure.Core.Pipeline; +using Azure.DigitalTwins.Samples; +using Azure.Identity; +using CommandLine; + +namespace Azure.DigitalTwins.Core.Samples +{ + public class Program + { + /// + /// Main entry point to the sample. + /// + public static async Task Main(string[] args) + { + Options options = null; + ParserResult result = Parser.Default.ParseArguments(args) + .WithParsed(parsedOptions => { options = parsedOptions; }) + .WithNotParsed(errors => Options.HandleParseError(errors)); + + var httpClient = new HttpClient(); + DigitalTwinsClient dtClient = GetDigitalTwinsClient( + options.TenantId, + options.ClientId, + options.ClientSecret, + options.AdtEndpoint, + httpClient); + + var dtLifecycleSamples = new DigitalTwinsLifecycleSamples(dtClient, options.EventHubName); + await dtLifecycleSamples.RunSamplesAsync().ConfigureAwait(false); + + var modelLifecycleSamples = new ModelLifecycleSamples(dtClient); + await modelLifecycleSamples.RunSamplesAsync().ConfigureAwait(false); + + var componentSamples = new ComponentSamples(dtClient); + await componentSamples.RunSamplesAsync().ConfigureAwait(false); + + httpClient.Dispose(); + } + + /// + /// Illustrates how to construct a with the fewest required parameters, + /// using the implementation of . + /// + /// The Id of the tenant of the application Id. + /// The application Id. + /// A client secret for the application Id. + /// The endpoint of the digital twins instance. + private static DigitalTwinsClient GetDigitalTwinsClient(string tenantId, string clientId, string clientSecret, string adtEndpoint) + { + #region Snippet:DigitalTwinSampleCreateServiceClient + + var clientSecretCredential = new ClientSecretCredential( + tenantId, + clientId, + clientSecret, + new TokenCredentialOptions { AuthorityHost = KnownAuthorityHosts.AzureCloud }); + + var dtClient = new DigitalTwinsClient( + new Uri(adtEndpoint), + clientSecretCredential); + + #endregion Snippet:DigitalTwinSampleCreateServiceClient + + return dtClient; + } + + /// + /// Illustrates how to construct a including client options, + /// using the implementation of . + /// + /// The Id of the tenant of the application Id. + /// The application Id. + /// A client secret for the application Id. + /// The endpoint of the digital twins instance. + /// An HttpClient instance for the client to use + private static DigitalTwinsClient GetDigitalTwinsClient(string tenantId, string clientId, string clientSecret, string adtEndpoint, HttpClient httpClient) + { + #region Snippet:DigitalTwinSampleCreateServiceClientWithHttpClient + + // This illustrates how to specify client options, in this case, by providing an + // instance of HttpClient for the digital twins client to use + + var clientOptions = new DigitalTwinsClientOptions + { + Transport = new HttpClientTransport(httpClient), + }; + + var clientSecretCredential = new ClientSecretCredential( + tenantId, + clientId, + clientSecret, + new TokenCredentialOptions { AuthorityHost = KnownAuthorityHosts.AzureCloud }); + + var dtClient = new DigitalTwinsClient( + new Uri(adtEndpoint), + clientSecretCredential, + clientOptions); + + #endregion Snippet:DigitalTwinSampleCreateServiceClientWithHttpClient + + return dtClient; + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/SampleLogger.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/SampleLogger.cs new file mode 100644 index 0000000000000..d30bfea11caa4 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/SampleLogger.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +namespace Azure.DigitalTwins.Core.Samples +{ + internal static class SampleLogger + { + internal static void PrintHeader(string message) + { + Console.ForegroundColor = ConsoleColor.Cyan; + Console.BackgroundColor = ConsoleColor.Black; + Console.WriteLine($"\n\n==={message.ToUpperInvariant()}===\n"); + Console.ResetColor(); + } + + internal static void FatalError(string message) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(message); + Console.ResetColor(); + Environment.Exit(0); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/SamplesConstants.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/SamplesConstants.cs new file mode 100644 index 0000000000000..b2c63feb2630a --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/SamplesConstants.cs @@ -0,0 +1,133 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.DigitalTwins.Core.Samples +{ + public static class SamplesConstants + { + /// + /// Room model Id + /// + public const string RoomModelId = "dtmi:samples:Room;1"; + + /// + /// WiFi model Id + /// + public const string WifiModelId = "dtmi:samples:Wifi;1"; + + /// + /// Building model Id + /// + public const string BuildingModelId = "dtmi:samples:Building;1"; + + /// + /// Floor model Id + /// + public const string FloorModelId = "dtmi:samples:Floor;1"; + + /// + /// HVAC model Id + /// + public const string HvacModelId = "dtmi:samples:HVAC;1"; + + /// + /// Placeholder for model Id in the temporary payload. + /// + public const string ModelId = "MODEL_ID"; + + /// + /// Placeholder for component Id in the temporary payload. + /// + public const string ComponentId = "COMPONENT_ID"; + + /// + /// Temporary model Id prefix + /// + public const string TemporaryModelPrefix = "dtmi:samples:TempModel;"; + + /// + /// Temporary component model Id prefix + /// + public const string TemporaryComponentModelPrefix = "dtmi:samples:ComponentModel;"; + + /// + /// The application/json description of a temporary model + /// + public const string TemporaryModelPayload = @" + { + ""@id"": ""MODEL_ID"", + ""@type"": ""Interface"", + ""@context"": ""dtmi:dtdl:context;2"", + ""displayName"": ""TempModel"", + ""contents"": [ + { + ""@type"": ""Property"", + ""name"": ""Prop1"", + ""schema"": ""string"" + }, + { + ""@type"": ""Property"", + ""name"": ""Prop2"", + ""schema"": ""string"" + }, + { + ""@type"": ""Component"", + ""name"": ""Component1"", + ""schema"": ""COMPONENT_ID"" + } + ] + }"; + + /// + /// Path for component. + /// + public const string ComponentPath = "Component1"; + + /// + /// The application/json description of a temporary component model + /// + public const string TemporaryComponentModelPayload = @" + { + ""@id"": ""COMPONENT_ID"", + ""@type"": ""Interface"", + ""@context"": ""dtmi:dtdl:context;2"", + ""displayName"": ""Component1"", + ""contents"": [ + { + ""@type"": ""Property"", + ""name"": ""ComponentProp1"", + ""schema"": ""string"" + }, + { + ""@type"": ""Property"", + ""name"": ""ComponentProp2"", + ""schema"": ""string"" + } + ] + }"; + + /// + /// Temporary twin Id prefix + /// + public const string TemporaryTwinPrefix = "sampleTwin"; + + /// + /// The application/json description of a temporary twin + /// + public const string TemporaryTwinPayload = @" + { + ""$metadata"": { + ""$model"": ""MODEL_ID"" + }, + ""Prop1"": ""Value"", + ""Prop2"": ""Value"", + ""Component1"":{ + ""$metadata"":{ + ""$model"": ""COMPONENT_ID"" + }, + ""ComponentProp1"": ""Value"", + ""ComponentProp2"": ""Value"" + } + }"; + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/UniqueIdHelper.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/UniqueIdHelper.cs new file mode 100644 index 0000000000000..701a819b37d7f --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/UniqueIdHelper.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Net; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +namespace Azure.DigitalTwins.Core.Samples +{ + internal static class UniqueIdHelper + { + private static readonly Random s_random = new Random(); + + internal static async Task GetUniqueModelIdAsync(string baseName, DigitalTwinsClient client, [CallerMemberName] string caller = "") + { + return await GetUniqueIdAsync(baseName, (modelId) => client.GetModelAsync(modelId)).ConfigureAwait(false); + } + + internal static async Task GetUniqueTwinIdAsync(string baseName, DigitalTwinsClient client, [CallerMemberName] string caller = "") + { + return await GetUniqueIdAsync(baseName, (twinId) => client.GetDigitalTwinAsync(twinId)).ConfigureAwait(false); + } + + private static async Task GetUniqueIdAsync(string baseName, Func getResource) + { + const int maxAttempts = 10; + const int maxVal = 10000; + var id = $"{baseName}{s_random.Next(maxVal)}"; + + for (int attemptsMade = 0; attemptsMade < maxAttempts; attemptsMade++) + { + try + { + await getResource(id).ConfigureAwait(false); + } + catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.NotFound) + { + return id; + } + id = $"{baseName}{s_random.Next(maxVal)}"; + } + + throw new Exception($"Unique Id could not be found with base {baseName}"); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/Readme.md b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/Readme.md new file mode 100644 index 0000000000000..d0bae7181ac5c --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/Readme.md @@ -0,0 +1,267 @@ +# Digital Twin Samples +You can explore azure digital twin APIs (using the SDK) using the samples project. +Sample project demonstrates the following: +* Create, get and decommision models +* Create, query and delete a Digital Twin +* Get and update components for a Digital Twin +* Create, get and delete relationships between Digital Twins +* Create, get and delete eventroutes for Digital Twin + +## Creating Digital Twin Client + +To create a new Digital Twin Client, you need the endpoint to an Azure Digital Twin and credentials. In the sample below, you can set `AdtEndpoint`, `TenantId`, `ClientId` and, `ClientSecret` as command line arguments. + +```C# Snippet:DigitalTwinSampleCreateServiceClient +var clientSecretCredential = new ClientSecretCredential( + tenantId, + clientId, + clientSecret, + new TokenCredentialOptions { AuthorityHost = KnownAuthorityHosts.AzureCloud }); + +var dtClient = new DigitalTwinsClient( + new Uri(adtEndpoint), + clientSecretCredential); +``` + +If you need to override pipeline behavior, such as provide your own HttpClient instance, you can do that via client options. + +```C# Snippet:DigitalTwinSampleCreateServiceClientWithHttpClient +// This illustrates how to specify client options, in this case, by providing an +// instance of HttpClient for the digital twins client to use + +var clientOptions = new DigitalTwinsClientOptions +{ + Transport = new HttpClientTransport(httpClient), +}; + +var clientSecretCredential = new ClientSecretCredential( + tenantId, + clientId, + clientSecret, + new TokenCredentialOptions { AuthorityHost = KnownAuthorityHosts.AzureCloud }); + +var dtClient = new DigitalTwinsClient( + new Uri(adtEndpoint), + clientSecretCredential, + clientOptions); +``` + +## Create, List, Decommision and Delete Models + +### Create Models + +Let's create models using the code below. You need to pass in List containing list of json models. Check out sample models [here](https://github.com/Azure/azure-sdk-for-net-pr/tree/feature/IoT-ADT/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/Models "Models") + +```C# Snippet:DigitalTwinSampleCreateModels +Response> response = await DigitalTwinsClient.CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload }).ConfigureAwait(false); +Console.WriteLine($"Successfully created a model with Id: {newComponentModelId}, {sampleModelId}, status: {response.GetRawResponse().Status}"); +``` + +### List Models + +Using `GetModelsAsync`, all created models are listed as AsyncPageable + +```C# Snippet:DigitalTwinSampleGetModels +AsyncPageable allModels = DigitalTwinsClient.GetModelsAsync(); +await foreach (ModelData model in allModels) +{ + Console.WriteLine($"Model Id: {model.Id}, display name: {model.DisplayName["en"]}, upload time: {model.UploadTime}, is decommissioned: {model.Decommissioned}"); +} +``` + +Use `GetModelAsync` with model's unique identifier to get a specific model + +```C# Snippet:DigitalTwinSampleGetModel +Response sampleModel = await DigitalTwinsClient.GetModelAsync(sampleModelId).ConfigureAwait(false); +``` + +### Decommission Models + +To decommision a model, pass in a model id for the model you want to decommision + +```C# Snippet:DigitalTwinSampleDecommisionModel +try +{ + await DigitalTwinsClient.DecommissionModelAsync(sampleModelId).ConfigureAwait(false); + + Console.WriteLine($"Successfully decommissioned model {sampleModelId}"); +} +catch (Exception ex) +{ + FatalError($"Failed to decommision model {sampleModelId} due to:\n{ex}"); +} +``` + +### Delete Models + +To delete a model, pass in a model id for the model you want to delete + +```C# Snippet:DigitalTwinSampleDeleteModel +try +{ + await DigitalTwinsClient.DeleteModelAsync(sampleModelId).ConfigureAwait(false); + + Console.WriteLine($"Deleted model {sampleModelId}"); +} +catch (Exception ex) +{ + FatalError($"Failed to delete model {sampleModelId} due to:\n{ex}"); +} +``` + +## Create and delete Digital Twin + +### Create Digital Twin + +For Creating Twin you will need to provide Id of a digital Twin such as `myTwin` and the application/json digital twin based on the model created earlier. You can look at sample application/json [here](https://github.com/Azure/azure-sdk-for-net-pr/tree/feature/IoT-ADT/sdk/digitaltwins/Azure.DigitalTwins.Core/samples/DigitalTwinsClientSample/DTDL/DigitalTwins "DigitalTwin"). + +```C# Snippet:DigitalTwinSampleCreateTwin +Response response = await DigitalTwinsClient.CreateDigitalTwinAsync(twin.Key, twin.Value).ConfigureAwait(false); +``` + +### Query Digital Twin + +Query the Azure Digital Twins instance for digital twins using the [Azure Digital Twins Query Store lanaguage](https://review.docs.microsoft.com/en-us/azure/digital-twins-v2/concepts-query-language?branch=pr-en-us-114648). Query calls support paging. Here's an example of how to query for digital twins and how to iterate over the results. + +```C# Snippet:DigitalTwinSampleQueryTwins +// This code snippet demonstrates the simplest way to iterate over the digital twin results, where paging +// happens under the covers. +AsyncPageable asyncPageableResponse = DigitalTwinsClient.QueryAsync("SELECT * FROM digitaltwins"); + +// Iterate over the twin instances in the pageable response. +// The "await" keyword here is required because new pages will be fetched when necessary, +// which involves a request to the service. +await foreach (string response in asyncPageableResponse) +{ + BasicDigitalTwin twin = JsonSerializer.Deserialize(response); + Console.WriteLine($"Found digital twin: {twin.Id}"); +} +``` + +The SDK also allows you to extract the `query-charge` header from the pagebale response. Here's an example of how to query for digital twins and how to iterate over the pageable response to extract the `query-charge` header. + +```C# Snippet:DigitalTwinSampleQueryTwinsWithQueryCharge +// This code snippet demonstrates how you could extract the query charges incurred when calling +// the query API. It iterates over the response pages first to access to the query-charge header, +// and then the digital twin results within each page. + +AsyncPageable asyncPageableResponseWithCharge = DigitalTwinsClient.QueryAsync("SELECT * FROM digitaltwins"); +int pageNum = 0; + +// The "await" keyword here is required as a call is made when fetching a new page. +await foreach (Page page in asyncPageableResponseWithCharge.AsPages()) +{ + Console.WriteLine($"Page {++pageNum} results:"); + + // Extract the query-charge header from the page + if (QueryChargeHelper.TryGetQueryCharge(page, out float queryCharge)) + { + Console.WriteLine($"Query charge was: {queryCharge}"); + } + + // Iterate over the twin instances. + // The "await" keyword is not required here as the paged response is local. + foreach (string response in page.Values) + { + BasicDigitalTwin twin = JsonSerializer.Deserialize(response); + Console.WriteLine($"Found digital twin: {twin.Id}"); + } +} +``` + +### Delete Digital Twin + +Delete a digital twin simply by providing id of a digital twin as below. + +```C# Snippet:DigitalTwinSampleDeleteTwin +await DigitalTwinsClient.DeleteDigitalTwinAsync(twin.Key).ConfigureAwait(false); +``` + +## Get and update Digital Twin Component + +### Update Digital Twin Component + +To update a component or in other words to replace, remove and/or add a component property or subproperty within Digital Twin, you would need id of a digital twin, component name and application/json-patch+json operations to be performed on the specified digital twin's component. Here is the sample code on how to do it. + +```C# Snippet:DigitalTwinSampleUpdateComponent +// Update Component with replacing property value +string propertyPath = "/ComponentProp1"; +string propValue = "New Value"; + +var componentUpdateUtility = new UpdateOperationsUtility(); +componentUpdateUtility.AppendReplaceOp(propertyPath, propValue); + +Response response = await DigitalTwinsClient.UpdateComponentAsync(twinId, SamplesConstants.ComponentPath, componentUpdateUtility.Serialize()); +``` + +### Get Digital Twin Component + +Get a component by providing name of a component and id of digital twin it belongs to. + +```C# Snippet:DigitalTwinSampleGetComponent +response = await DigitalTwinsClient.GetComponentAsync(twinId, SamplesConstants.ComponentPath).ConfigureAwait(false); +``` + +## Create and list Digital Twin edges + +### Create Digital Twin Edge + +`CreateEdgeAsync` creates a relationship edge on a digital twin provided with id of a digital twin, name of relationship such as "contains", id of an edge such as "FloorContainsRoom" and an application/json edge to be created. Must contain property with key "$targetId" to specify the target of the edge. Sample payloads for relationships can be found [here](https://github.com/Azure/azure-sdk-for-net-pr/blob/feature/IoT-ADT/sdk/iot/Azure.Iot.DigitalTwins/samples/DigitalTwinServiceClientSample/DTDL/Relationships/HospitalEdges.json "RelationshipExamples"). + +```C# Snippet:DigitalTwinSampleCreateRelationship +string serializedRelationship = JsonSerializer.Serialize(relationship); + +await DigitalTwinsClient + .CreateRelationshipAsync( + relationship.SourceId, + relationship.Id, + serializedRelationship) + .ConfigureAwait(false); +``` +### List Digital Twin Edges + +`GetEdgesAsync` and `GetIncomingEdgesAsync` lists all the edges and all incoming edges respectively of a digital twin + +```C# Snippet:DigitalTwinSampleGetRelationships +AsyncPageable relationships = DigitalTwinsClient.GetRelationshipsAsync(twin.Key); +``` + +```C# Snippet:DigitalTwinSampleGetIncomingRelationships +AsyncPageable incomingRelationships = DigitalTwinsClient.GetIncomingRelationshipsAsync(twin.Key); +``` + +## Create, list and delete event routes of Digital Twin + +### Create Event Route + +To create Event route, one needs to provide id of an event route such as "sampleEventRoute" and event route data containing the endpoint and optional filter like the example shown below + +```C# Snippet:DigitalTwinSampleCreateEventRoute +string eventFilter = "$eventType = 'DigitalTwinTelemetryMessages' or $eventType = 'DigitalTwinLifecycleNotification'"; +var eventRoute = new EventRoute(_eventhubEndpointName) +{ + Filter = eventFilter +}; + +Response createEventRouteResponse = await DigitalTwinsClient.CreateEventRouteAsync(_eventRouteId, eventRoute).ConfigureAwait(false); +``` + +### List Event Routes + +List a specific event route given event route id or all event routes setting options with `GetEventRouteAsync` and `GetEventRoutesAsync`. + +```C# Snippet:DigitalTwinSampleGetEventRoutes +AsyncPageable response = DigitalTwinsClient.GetEventRoutesAsync(); +await foreach (EventRoute er in response) +{ + Console.WriteLine($"Event route: {er.Id}, endpoint name: {er.EndpointName}"); +} +``` + +### Delete Event Route + +Delete an event route given event route id + +```C# Snippet:DigitalTwinSampleDeleteEventRoute +Response response = await DigitalTwinsClient.DeleteEventRouteAsync(_eventRouteId).ConfigureAwait(false); +``` diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Azure.DigitalTwins.Core.csproj b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Azure.DigitalTwins.Core.csproj new file mode 100644 index 0000000000000..89008acf9702f --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Azure.DigitalTwins.Core.csproj @@ -0,0 +1,56 @@ + + + + Digital Twins SDK + $(RequiredTargetFrameworks) + + false + true + + $(NoWarn);CA1812 + + + + + IoT;Digital Twins;$(PackageCommonTags) + SDK for the Azure Digital Twins service + 1.0.0-preview.1 + + + + + + + + + + Shared\Azure.Core + + + Shared\Azure.Core + + + Shared\Azure.Core + + + Shared\Azure.Core + + + Shared\Azure.Core + + + Shared\Azure.Core + + + Shared\Azure.Core + + + Shared\Azure.Core + + + Shared\Azure.Core + + + + + diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/DigitalTwinModelsRestClient.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/DigitalTwinModelsRestClient.cs new file mode 100644 index 0000000000000..8f7d71a19ac94 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/DigitalTwinModelsRestClient.cs @@ -0,0 +1,221 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.DigitalTwins.Core.Models; +using Azure.DigitalTwins.Core.Serialization; + +namespace Azure.DigitalTwins.Core +{ + internal partial class DigitalTwinModelsRestClient + { + // The modelUpdates parameter needs to be changed from IEnumerable to IEnumerable + // and not parsed like a json object. + public async Task>> AddAsync(IEnumerable models = null, CancellationToken cancellationToken = default) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinModelsClient.Add"); + scope.Start(); + try + { + using HttpMessage message = CreateAddRequest(models); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + case 201: + { + IReadOnlyList value = default; + using JsonDocument document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + List array = new List(document.RootElement.GetArrayLength()); + foreach (JsonElement item in document.RootElement.EnumerateArray()) + { + array.Add(ModelData.DeserializeModelData(item)); + } + value = array; + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + // The modelUpdates parameter needs to be changed from IEnumerable to IEnumerable + // and not parsed like a json object. + internal Response> Add(IEnumerable models = null, CancellationToken cancellationToken = default) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinModelsClient.Add"); + scope.Start(); + try + { + using HttpMessage message = CreateAddRequest(models); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + case 201: + { + IReadOnlyList value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + List array = new List(document.RootElement.GetArrayLength()); + foreach (JsonElement item in document.RootElement.EnumerateArray()) + { + array.Add(ModelData.DeserializeModelData(item)); + } + value = array; + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + // The modelUpdates parameter needs to be changed from IEnumerable to IEnumerable + // and not parsed like a json object. + internal async Task UpdateAsync(string id, IEnumerable modelUpdates, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (modelUpdates == null) + { + throw new ArgumentNullException(nameof(modelUpdates)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinModelsClient.Update"); + scope.Start(); + try + { + using HttpMessage message = CreateUpdateRequest(id, modelUpdates); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + return message.Response.Status switch + { + 204 => message.Response, + _ => throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false), + }; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + // The modelUpdates parameter needs to be changed from IEnumerable to IEnumerable + // and not parsed like a json object. + internal Response Update(string id, IEnumerable modelUpdates, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (modelUpdates == null) + { + throw new ArgumentNullException(nameof(modelUpdates)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinModelsClient.Update"); + scope.Start(); + try + { + using HttpMessage message = CreateUpdateRequest(id, modelUpdates); + _pipeline.Send(message, cancellationToken); + return message.Response.Status switch + { + 204 => message.Response, + _ => throw _clientDiagnostics.CreateRequestFailedException(message.Response), + }; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + // The strings are already json, so we do not want them to be serialized. + // Instead, the payloads need to be concatenated into a json array. + private HttpMessage CreateAddRequest(IEnumerable models) + { + HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/models", false); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json; charset=utf-8"); + if (models != null) + { + string modelsJsonArray = PayloadHelper.BuildArrayPayload(models); + request.Content = new StringRequestContent(modelsJsonArray); + } + return message; + } + + // The strings are already json, so we do not want them to be serialized. + // Instead, the payloads need to be concatenated into a json array. + internal HttpMessage CreateUpdateRequest(string id, IEnumerable modelUpdates) + { + HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/models/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json; charset=utf-8"); + if (modelUpdates != null) + { + string modelUpdatesArray = PayloadHelper.BuildArrayPayload(modelUpdates); + request.Content = new StringRequestContent(modelUpdatesArray); + } + return message; + } + + #region null overrides + // The following methods are only declared so that autorest does not create these functions in the generated code. + // For methods that we need to override, when the parameter list is the same, autorest knows not to generate them again. + // When the parameter list changes, autorest generates the methods again. + // As such, these methods are declared here and made private, while the public method is declared above, too. + // These methods should never be called. + +#pragma warning disable CA1801, IDE0051, IDE0060 // Remove unused parameter + + // Original return type is Task>>. Changing to object to allow returning null. + private object AddAsync(IEnumerable models = null, CancellationToken cancellationToken = default) => null; + + private Response> Add(IEnumerable models = null, CancellationToken cancellationToken = default) => null; + + // Original return type is ValueTask. Changing to object to allow returing null. + private object UpdateAsync(string id, IEnumerable updateModel, CancellationToken cancellationToken = default) => null; + + private Response Update(string id, IEnumerable updateModel, CancellationToken cancellationToken = default) => null; + + private HttpMessage CreateAddRequest(IEnumerable models) => null; + +#pragma warning restore CA1801, IDE0051, IDE0060 // Remove unused parameter + #endregion + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/DigitalTwinsRestClient.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/DigitalTwinsRestClient.cs new file mode 100644 index 0000000000000..7284b713f2aa0 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/DigitalTwinsRestClient.cs @@ -0,0 +1,881 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; + +namespace Azure.DigitalTwins.Core +{ + // Declaring this class here will make it so that we can force its methods to use strings instead of + // objects for json inputs/return values + internal partial class DigitalTwinsRestClient + { + private const string IfMatchHeaderKey = "If-Match"; + + internal HttpMessage CreateAddRequest(string id, string twin) + { + HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Put; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json; charset=utf-8"); + request.Content = new StringRequestContent(twin); + return message; + } + + internal async Task> AddAsync(string id, string twin, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (twin == null) + { + throw new ArgumentNullException(nameof(twin)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.Add"); + scope.Start(); + try + { + using HttpMessage message = CreateAddRequest(id, twin); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + case 202: + { + string value = default; + using JsonDocument document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + case 201: + return Response.FromValue(null, message.Response); + + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal Response Add(string id, string twin, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (twin == null) + { + throw new ArgumentNullException(nameof(twin)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.Add"); + scope.Start(); + try + { + using HttpMessage message = CreateAddRequest(id, twin); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + case 202: + { + string value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + case 201: + return Response.FromValue(null, message.Response); + + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal async Task> GetByIdAsync(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.GetById"); + scope.Start(); + try + { + using HttpMessage message = CreateGetByIdRequest(id); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + string value = default; + using JsonDocument document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal Response GetById(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.GetById"); + scope.Start(); + try + { + using HttpMessage message = CreateGetByIdRequest(id); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + string value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal async Task> UpdateAsync(string id, string patchDocument, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (patchDocument == null) + { + throw new ArgumentNullException(nameof(patchDocument)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.Update"); + scope.Start(); + try + { + using HttpMessage message = CreateUpdateRequest(id, patchDocument, ifMatch); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 202: + { + string value = default; + using JsonDocument document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + case 204: + return Response.FromValue(null, message.Response); + + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal Response Update(string id, string patchDocument, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (patchDocument == null) + { + throw new ArgumentNullException(nameof(patchDocument)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.Update"); + scope.Start(); + try + { + using HttpMessage message = CreateUpdateRequest(id, patchDocument, ifMatch); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 202: + { + string value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + case 204: + return Response.FromValue(null, message.Response); + + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal async Task> GetRelationshipByIdAsync(string id, string relationshipId, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (relationshipId == null) + { + throw new ArgumentNullException(nameof(relationshipId)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.GetRelationshipById"); + scope.Start(); + try + { + using HttpMessage message = CreateGetRelationshipByIdRequest(id, relationshipId); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + string value = default; + using JsonDocument document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal Response GetRelationshipById(string id, string relationshipId, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (relationshipId == null) + { + throw new ArgumentNullException(nameof(relationshipId)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.GetRelationshipById"); + scope.Start(); + try + { + using HttpMessage message = CreateGetRelationshipByIdRequest(id, relationshipId); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + string value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal async Task> AddRelationshipAsync(string id, string relationshipId, string relationship = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (relationshipId == null) + { + throw new ArgumentNullException(nameof(relationshipId)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.AddRelationship"); + scope.Start(); + try + { + using HttpMessage message = CreateAddRelationshipRequest(id, relationshipId, relationship); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + string value = default; + using JsonDocument document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + case 204: + return Response.FromValue(null, message.Response); + + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal Response AddRelationship(string id, string relationshipId, string relationship = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (relationshipId == null) + { + throw new ArgumentNullException(nameof(relationshipId)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.AddRelationship"); + scope.Start(); + try + { + using HttpMessage message = CreateAddRelationshipRequest(id, relationshipId, relationship); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + string value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + case 204: + return Response.FromValue(null, message.Response); + + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal async Task UpdateRelationshipAsync(string id, string relationshipId, string patchDocument = null, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (relationshipId == null) + { + throw new ArgumentNullException(nameof(relationshipId)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.UpdateRelationship"); + scope.Start(); + try + { + using HttpMessage message = CreateUpdateRelationshipRequest(id, relationshipId, patchDocument, ifMatch); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + return message.Response.Status switch + { + 204 => message.Response, + _ => throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false), + }; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal Response UpdateRelationship(string id, string relationshipId, string patchDocument = null, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (relationshipId == null) + { + throw new ArgumentNullException(nameof(relationshipId)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.UpdateRelationship"); + scope.Start(); + try + { + using HttpMessage message = CreateUpdateRelationshipRequest(id, relationshipId, patchDocument, ifMatch); + _pipeline.Send(message, cancellationToken); + return message.Response.Status switch + { + 204 => message.Response, + _ => throw _clientDiagnostics.CreateRequestFailedException(message.Response), + }; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal async Task> GetComponentAsync(string id, string componentPath, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (componentPath == null) + { + throw new ArgumentNullException(nameof(componentPath)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.GetComponent"); + scope.Start(); + try + { + using HttpMessage message = CreateGetComponentRequest(id, componentPath); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + string value = default; + using JsonDocument document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal Response GetComponent(string id, string componentPath, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (componentPath == null) + { + throw new ArgumentNullException(nameof(componentPath)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.GetComponent"); + scope.Start(); + try + { + using HttpMessage message = CreateGetComponentRequest(id, componentPath); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + string value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal async Task> UpdateComponentAsync(string id, string componentPath, string patchDocument = null, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (componentPath == null) + { + throw new ArgumentNullException(nameof(componentPath)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.UpdateComponent"); + scope.Start(); + try + { + using HttpMessage message = CreateUpdateComponentRequest(id, componentPath, patchDocument, ifMatch); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 202: + { + string value = default; + using JsonDocument document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + case 204: + return Response.FromValue(null, message.Response); + + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal Response UpdateComponent(string id, string componentPath, string patchDocument = null, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (componentPath == null) + { + throw new ArgumentNullException(nameof(componentPath)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.UpdateComponent"); + scope.Start(); + try + { + using HttpMessage message = CreateUpdateComponentRequest(id, componentPath, patchDocument, ifMatch); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 202: + { + string value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + value = document.RootElement.GetRawText(); + return Response.FromValue(value, message.Response); + } + case 204: + return Response.FromValue(null, message.Response); + + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + public async Task SendTelemetryAsync(string id, string ceId, string ceDataschema, string ceSpecversion, string ceType, string ceDatacontenttype = null, string ceSubject = null, string ceTime = null, string telemetry = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (ceId == null) + { + throw new ArgumentNullException(nameof(ceId)); + } + if (ceDataschema == null) + { + throw new ArgumentNullException(nameof(ceDataschema)); + } + if (ceSpecversion == null) + { + throw new ArgumentNullException(nameof(ceSpecversion)); + } + if (ceType == null) + { + throw new ArgumentNullException(nameof(ceType)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.SendTelemetry"); + scope.Start(); + try + { + using HttpMessage message = CreateSendTelemetryRequest(id, ceId, ceDataschema, ceSpecversion, ceType, ceDatacontenttype, ceSubject, ceTime, telemetry); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + return message.Response.Status switch + { + 204 => message.Response, + _ => throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false), + }; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + public Response SendTelemetry(string id, string ceId, string ceDataschema, string ceSpecversion, string ceType, string ceDatacontenttype = null, string ceSubject = null, string ceTime = null, string telemetry = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (ceId == null) + { + throw new ArgumentNullException(nameof(ceId)); + } + if (ceDataschema == null) + { + throw new ArgumentNullException(nameof(ceDataschema)); + } + if (ceSpecversion == null) + { + throw new ArgumentNullException(nameof(ceSpecversion)); + } + if (ceType == null) + { + throw new ArgumentNullException(nameof(ceType)); + } + + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsClient.SendTelemetry"); + scope.Start(); + try + { + using HttpMessage message = CreateSendTelemetryRequest(id, ceId, ceDataschema, ceSpecversion, ceType, ceDatacontenttype, ceSubject, ceTime, telemetry); + _pipeline.Send(message, cancellationToken); + return message.Response.Status switch + { + 204 => message.Response, + _ => throw _clientDiagnostics.CreateRequestFailedException(message.Response), + }; + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + internal HttpMessage CreateUpdateRequest(string id, string patchDocument, string ifMatch = null) + { + HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + if (ifMatch != null) + { + request.Headers.Add(IfMatchHeaderKey, ifMatch); + } + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json; charset=utf-8"); + request.Content = new StringRequestContent(patchDocument); + return message; + } + + private HttpMessage CreateAddRelationshipRequest(string id, string relationshipId, string relationship) + { + HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Put; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/relationships/", false); + uri.AppendPath(relationshipId, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json; charset=utf-8"); + if (relationship != null) + { + request.Content = new StringRequestContent(relationship); + } + return message; + } + + private HttpMessage CreateUpdateRelationshipRequest(string id, string relationshipId, string patchDocument, string ifMatch = null) + { + HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/relationships/", false); + uri.AppendPath(relationshipId, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json-patch+json; charset=utf-8"); + if (patchDocument != null) + { + request.Content = new StringRequestContent(patchDocument); + } + if (ifMatch != null) + { + request.Headers.Add(IfMatchHeaderKey, ifMatch); + } + return message; + } + + private HttpMessage CreateUpdateComponentRequest(string id, string componentPath, string patchDocument, string ifMatch = null) + { + HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/components/", false); + uri.AppendPath(componentPath, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json-patch+json; charset=utf-8"); + if (ifMatch != null) + { + request.Headers.Add(IfMatchHeaderKey, ifMatch); + } + if (patchDocument != null) + { + request.Content = new StringRequestContent(patchDocument); + } + return message; + } + + private HttpMessage CreateSendTelemetryRequest(string id, string ceId, string ceDataschema, string ceSpecversion, string ceType, string ceDatacontenttype, string ceSubject, string ceTime, string telemetry) + { + HttpMessage message = _pipeline.CreateMessage(); + Request request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/telemetry", false); + request.Uri = uri; + request.Headers.Add("ce-id", ceId); + if (ceDatacontenttype != null) + { + request.Headers.Add("ce-datacontenttype", ceDatacontenttype); + } + request.Headers.Add("ce-dataschema", ceDataschema); + request.Headers.Add("ce-specversion", ceSpecversion); + if (ceSubject != null) + { + request.Headers.Add("ce-subject", ceSubject); + } + if (ceTime != null) + { + request.Headers.Add("ce-time", ceTime); + } + request.Headers.Add("ce-type", ceType); + request.Headers.Add("Content-Type", "application/json; charset=utf-8"); + if (telemetry != null) + { + request.Content = new StringRequestContent(telemetry); + } + return message; + } + + #region null overrides + // The following methods are only declared so that autorest does not create these functions in the generated code. + // For methods that we need to override, when the parameter list is the same, autorest knows not to generate them again. + // When the parameter list changes, autorest generates the methods again. + // As such, these methods are declared here and made private, while the public method is declared above, too. + // These methods should never be called. + +#pragma warning disable CA1801, IDE0051, IDE0060 // Remove unused parameter + + // Original return type is Task>. Changing to object to allow returning null. + private object AddAsync(string id, object twin, CancellationToken cancellationToken = default) => null; + + private Response Add(string id, object twin, CancellationToken cancellationToken = default) => null; + + // Original return type is ValueTask. Changing to object to allow returning null. + private object UpdateAsync(string id, IEnumerable patchDocument, string ifMatch = null, CancellationToken cancellationToken = default) => null; + + private Response Update(string id, IEnumerable patchDocument, string ifMatch = null, CancellationToken cancellationToken = default) => null; + + // Original return type is ValueTask>. Changing to object to allow returning null. + private object AddRelationshipAsync(string id, string relationshipId, object relationship = null, CancellationToken cancellationToken = default) => null; + + private Response AddRelationship(string id, string relationshipId, object relationship = null, CancellationToken cancellationToken = default) => null; + + // Original return type is ValueTask. Changing to object to allow returning null. + private object UpdateRelationshipAsync(string id, string relationshipId, string ifMatch = null, IEnumerable patchDocument = null, CancellationToken cancellationToken = default) => null; + + private Response UpdateRelationship(string id, string relationshipId, string ifMatch = null, IEnumerable patchDocument = null, CancellationToken cancellationToken = default) => null; + + // Original return type is ValueTask. Changing to object to allow returning null. + private object UpdateComponentAsync(string id, string componentPath, string ifMatch = null, IEnumerable patchDocument = null, CancellationToken cancellationToken = default) => null; + + private Response UpdateComponent(string id, string componentPath, string ifMatch = null, IEnumerable patchDocument = null, CancellationToken cancellationToken = default) => null; + + private HttpMessage CreateAddRequest(string id, object twin) => null; + +#pragma warning restore CA1801, IDE0051, IDE0060 // Remove unused parameter + #endregion + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/Error.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/Error.cs new file mode 100644 index 0000000000000..0bf83c4ac6dba --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/Error.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class Error + { + // This class declaration makes the generated class of the same name internal instead of public; do not remove. + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ErrorResponse.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ErrorResponse.cs new file mode 100644 index 0000000000000..5c1f0877e8f93 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ErrorResponse.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class ErrorResponse + { + // This class declaration makes the generated class of the same name internal instead of public; do not remove. + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/EventRouteCollection.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/EventRouteCollection.cs new file mode 100644 index 0000000000000..14997e60b2e5a --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/EventRouteCollection.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class EventRouteCollection + { + // This class declaration makes the generated class of the same name internal instead of public; do not remove. + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/GetModelsOptions.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/GetModelsOptions.cs new file mode 100644 index 0000000000000..35c54acb63f3b --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/GetModelsOptions.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + /// + /// Optional parameters to use when getting a list of models. + /// + [CodeGenModel("DigitalTwinModelsListOptions")] + public partial class GetModelsOptions + { + // This class declaration changes the name of the generated class; do not remove. + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/IncomingRelationshipCollection.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/IncomingRelationshipCollection.cs new file mode 100644 index 0000000000000..8546b776c2c2d --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/IncomingRelationshipCollection.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class IncomingRelationshipCollection + { + // This class declaration makes the generated class of the same name internal instead of public; do not remove. + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/InnerError.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/InnerError.cs new file mode 100644 index 0000000000000..5ffc86751a8a7 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/InnerError.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class InnerError + { + // This class declaration makes the generated class of the same name internal instead of public; do not remove. + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ModelData.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ModelData.Serialization.cs new file mode 100644 index 0000000000000..f5169c5ef136f --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ModelData.Serialization.cs @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + public partial class ModelData + { + // This class definition overrides deserialization implementation in order to turn the **object** type definitions for displayName and description into + // dictionaries, as defined in swagger comments. + + internal static ModelData DeserializeModelData(JsonElement element) + { + Dictionary displayName = default; + Dictionary description = default; + string id = default; + DateTimeOffset? uploadTime = default; + bool? decommissioned = default; + string model = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("displayName")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + // manual change: deserialize as a dictionary + displayName = JsonSerializer.Deserialize>(property.Value.GetRawText()); + continue; + } + if (property.NameEquals("description")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + // manual change: deserialize as a dictionary + description = JsonSerializer.Deserialize>(property.Value.GetRawText()); + continue; + } + if (property.NameEquals("id")) + { + id = property.Value.GetString(); + continue; + } + if (property.NameEquals("uploadTime")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + uploadTime = property.Value.GetDateTimeOffset("O"); + continue; + } + if (property.NameEquals("decommissioned")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + decommissioned = property.Value.GetBoolean(); + continue; + } + if (property.NameEquals("model")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + model = property.Value.GetRawText(); + continue; + } + } + return new ModelData(displayName, description, id, uploadTime, decommissioned, model); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ModelData.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ModelData.cs new file mode 100644 index 0000000000000..0215d504fe56f --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/ModelData.cs @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + public partial class ModelData + { + // This class declaration makes the generated class of the same name declare Model as a **string** rather than an **object**. + // It also changes displayName and description from objects (per swagger) to dictionaries (per swagger comment). + + /// Initializes a new instance of ModelData. + /// A language map that contains the localized display names as specified in the model definition. + /// A language map that contains the localized descriptions as specified in the model definition. + /// The id of the model as specified in the model definition. + /// The time the model was uploaded to the service. + /// Indicates if the model is decommissioned. Decommissioned models cannot be referenced by newly created digital twins. + /// The model definition. + internal ModelData(IDictionary displayName, IDictionary description, string id, DateTimeOffset? uploadTime, bool? decommissioned, string model) + { + DisplayName = displayName; + Description = description; + Id = id; + UploadTime = uploadTime; + Decommissioned = decommissioned; + Model = model; + } + + /// + /// The model definition. + /// + public string Model { get; } + + /// + /// A language map that contains the localized display names as specified in the model definition. + /// + public IDictionary DisplayName { get; } + + /// + /// A language map that contains the localized descriptions as specified in the model definition. + /// + public IDictionary Description { get; } + + #region null overrides +#pragma warning disable CA1801 // Remove unused parameter + + private ModelData(string id) { } + +#pragma warning restore CA1801 // Remove unused parameter + #endregion + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/PagedModelDataCollection.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/PagedModelDataCollection.cs new file mode 100644 index 0000000000000..4b66663d1ab4f --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/PagedModelDataCollection.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class PagedModelDataCollection + { + // This class declaration makes the generated class of the same name internal instead of public; do not remove. + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QueryResult.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QueryResult.Serialization.cs new file mode 100644 index 0000000000000..db0121fc89c9b --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QueryResult.Serialization.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class QueryResult + { + // This class declaration makes the generated class of the same name internal instead of public; do not remove. + // It also overrides deserialization implementation in order to treat the **object** type definition for "items" as json strings. + + internal static QueryResult DeserializeQueryResult(JsonElement element) + { + IReadOnlyList items = default; + string continuationToken = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("items")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + // manual change: get json text + array.Add(item.GetRawText()); + } + items = array; + continue; + } + if (property.NameEquals("continuationToken")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + continuationToken = property.Value.GetString(); + continue; + } + } + return new QueryResult(items, continuationToken); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QueryResult.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QueryResult.cs new file mode 100644 index 0000000000000..c93a39127cadd --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QueryResult.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class QueryResult + { + // This class declaration makes the generated class of the same name use IReadOnlyList instead of IReadOnlyList + // and makes the class internal; do not remove. + + /// The query results. + internal IReadOnlyList Items { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QuerySpecification.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QuerySpecification.cs new file mode 100644 index 0000000000000..0b1b2e02459c3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/QuerySpecification.cs @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class QuerySpecification + { + // This class declaration makes the generated class of the same name internal instead of public; do not remove. + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/RelationshipCollection.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/RelationshipCollection.Serialization.cs new file mode 100644 index 0000000000000..4652f17f87422 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/RelationshipCollection.Serialization.cs @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Text.Json; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class RelationshipCollection + { + // This class declaration makes the generated class of the same name internal instead of public; do not remove. + // It also overrides deserialization implementation in order to treat the **object** type definition for "value" as a list of json strings. + + internal static RelationshipCollection DeserializeRelationshipCollection(JsonElement element) + { + IReadOnlyList value = default; + string nextLink = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("value")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + // manual change: get json text + array.Add(item.GetRawText()); + } + value = array; + continue; + } + if (property.NameEquals("nextLink")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + nextLink = property.Value.GetString(); + continue; + } + } + return new RelationshipCollection(value, nextLink); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/RelationshipCollection.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/RelationshipCollection.cs new file mode 100644 index 0000000000000..724a33b03031e --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Customized/Models/RelationshipCollection.cs @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class RelationshipCollection + { + // This class declaration makes the generated class of the same name use IReadOnlyList instead of IReadOnlyList + // and makes the class internal; do not remove. + + internal IReadOnlyList Value { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClient.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClient.cs new file mode 100644 index 0000000000000..4f17f7e483b52 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClient.cs @@ -0,0 +1,1285 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.DigitalTwins.Core.Models; + +namespace Azure.DigitalTwins.Core +{ + /// + /// The Digital Twins Service Client contains methods to retrieve digital twin information, like models, components, and relationships. + /// + public class DigitalTwinsClient + { + private const bool IncludeModelDefinition = true; + private const string DateTimeOffsetFormat = "MM/dd/yy H:mm:ss zzz"; + + private readonly HttpPipeline _httpPipeline; + private readonly ClientDiagnostics _clientDiagnostics; + + private readonly DigitalTwinsRestClient _dtRestClient; + private readonly DigitalTwinModelsRestClient _dtModelsRestClient; + private readonly EventRoutesRestClient _eventRoutesRestClient; + private readonly QueryRestClient _queryClient; + + /// + /// Initializes a new instance of the class. + /// + /// The Azure digital twins service instance URI to connect to. + /// The implementation which will be used to request for the authentication token. + /// + /// + /// var clientSecretCredential = new ClientSecretCredential( + /// tenantId, + /// clientId, + /// clientSecret, + /// new TokenCredentialOptions { AuthorityHost = KnownAuthorityHosts.AzureCloud }); + /// + /// var dtClient = new DigitalTwinsClient( + /// new Uri(adtEndpoint), + /// clientSecretCredential); + /// + /// + public DigitalTwinsClient(Uri endpoint, TokenCredential credential) + : this(endpoint, credential, new DigitalTwinsClientOptions()) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The Azure digital twins service instance URI to connect to. + /// The implementation which will be used to request for the authentication token. + /// Options that allow configuration of requests sent to the digital twins service. + /// + /// + /// // This illustrates how to specify client options, in this case, by providing an + /// // instance of HttpClient for the digital twins client to use + /// + /// var clientOptions = new DigitalTwinsClientOptions + /// { + /// Transport = new HttpClientTransport(httpClient), + /// }; + /// + /// var clientSecretCredential = new ClientSecretCredential( + /// tenantId, + /// clientId, + /// clientSecret, + /// new TokenCredentialOptions { AuthorityHost = KnownAuthorityHosts.AzureCloud }); + /// + /// var dtClient = new DigitalTwinsClient( + /// new Uri(adtEndpoint), + /// clientSecretCredential, + /// clientOptions); + /// + /// + public DigitalTwinsClient(Uri endpoint, TokenCredential credential, DigitalTwinsClientOptions options) + { + Argument.AssertNotNull(options, nameof(options)); + + _clientDiagnostics = new ClientDiagnostics(options); + + options.AddPolicy(new BearerTokenAuthenticationPolicy(credential, GetAuthorizationScopes(endpoint)), HttpPipelinePosition.PerCall); + _httpPipeline = HttpPipelineBuilder.Build(options); + + _dtRestClient = new DigitalTwinsRestClient(_clientDiagnostics, _httpPipeline, endpoint, options.GetVersionString()); + _dtModelsRestClient = new DigitalTwinModelsRestClient(_clientDiagnostics, _httpPipeline, endpoint, options.GetVersionString()); + _eventRoutesRestClient = new EventRoutesRestClient(_clientDiagnostics, _httpPipeline, endpoint, options.GetVersionString()); + _queryClient = new QueryRestClient(_clientDiagnostics, _httpPipeline, endpoint); + } + + /// + /// Initializes a new instance of the class. + /// + protected DigitalTwinsClient() + { + // This constructor only exists for mocking purposes in unit tests. It should not be used otherwise + } + + /// + /// Get a digital twin. + /// + /// + /// The returned application/json string can always be deserialized into an instance of . + /// It may also be deserialized into custom digital twin types that extend the with additional + /// strongly typed properties provided that you know the definition of the retrieved digital twin prior to deserialization. + /// + /// The Id of the digital twin. + /// The cancellation token. + /// The application/json digital twin and the http response. + public virtual Task> GetDigitalTwinAsync(string digitalTwinId, CancellationToken cancellationToken = default) + { + return _dtRestClient.GetByIdAsync(digitalTwinId, cancellationToken); + } + + /// + /// Get a digital twin. + /// + /// + /// The returned application/json string can always be deserialized into an instance of . + /// It may also be deserialized into custom digital twin types that extend the with additional + /// strongly typed properties provided that you know the definition of the retrieved digital twin prior to deserialization. + /// + /// The Id of the digital twin. + /// The cancellation token. + /// The application/json digital twin and the http response. + public virtual Response GetDigitalTwin(string digitalTwinId, CancellationToken cancellationToken = default) + { + return _dtRestClient.GetById(digitalTwinId, cancellationToken); + } + + /// + /// Create a digital twin. + /// + /// The Id of the digital twin. + /// The application/json digital twin to create. + /// The cancellation token. + /// The created application/json digital twin and the http response. + /// The digital twin must be the serialization of an instance of or the serialization of an extension of that type. + /// + /// + /// Response<string> response = await DigitalTwinsClient.CreateDigitalTwinAsync(twin.Key, twin.Value).ConfigureAwait(false); + /// + /// + public virtual Task> CreateDigitalTwinAsync(string digitalTwinId, string digitalTwin, CancellationToken cancellationToken = default) + { + return _dtRestClient.AddAsync(digitalTwinId, digitalTwin, cancellationToken); + } + + /// + /// Create a digital twin. + /// + /// The Id of the digital twin. + /// The application/json digital twin to create. + /// The cancellation token. + /// The created application/json digital twin and the http response. + /// The digital twin must be the serialization of an instance of or the serialization of an extension of that type. + public virtual Response CreateDigitalTwin(string digitalTwinId, string digitalTwin, CancellationToken cancellationToken = default) + { + return _dtRestClient.Add(digitalTwinId, digitalTwin, cancellationToken); + } + + /// + /// Delete a digital twin. + /// + /// The Id of the digital twin to delete. + /// The optional settings for this request. + /// The cancellation token. + /// The http response. + /// + /// To delete a digital twin, any relationships referencing it must be deleted first. + /// + /// + /// + /// await DigitalTwinsClient.DeleteDigitalTwinAsync(twin.Key).ConfigureAwait(false); + /// + /// + public virtual Task DeleteDigitalTwinAsync(string digitalTwinId, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + return _dtRestClient.DeleteAsync(digitalTwinId, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Delete a digital twin. + /// + /// The Id of the digital twin to delete. + /// The optional settings for this request. + /// The cancellation token. + /// The http response. + /// + /// To delete a digital twin, any relationships referencing it must be deleted first. + /// + public virtual Response DeleteDigitalTwin(string digitalTwinId, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + return _dtRestClient.Delete(digitalTwinId, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Update a digital twin. + /// + /// The Id of the digital twin to update. + /// The application/json-patch+json operations to be performed on the specified digital twin. + /// The optional settings for this request. + /// The http response. + /// The cancellationToken. + /// The http response. + public virtual Task> UpdateDigitalTwinAsync(string digitalTwinId, string digitalTwinUpdateOperations, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + return _dtRestClient.UpdateAsync(digitalTwinId, digitalTwinUpdateOperations, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Update a digital twin. + /// + /// The Id of the digital twin to update. + /// The application/json-patch+json operations to be performed on the specified digital twin. + /// The optional settings for this request. + /// The http response. + /// The cancellationToken. + public virtual Response UpdateDigitalTwin(string digitalTwinId, string digitalTwinUpdateOperations, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + return _dtRestClient.Update(digitalTwinId, digitalTwinUpdateOperations, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Gets a component on a digital twin. + /// + /// The Id of the digital twin. + /// The component being retrieved. + /// The cancellation token. + /// Json string representation of the component corresponding to the provided componentPath and the HTTP response. + /// + /// + /// response = await DigitalTwinsClient.GetComponentAsync(twinId, SamplesConstants.ComponentPath).ConfigureAwait(false); + /// + /// + public virtual Task> GetComponentAsync(string digitalTwinId, string componentPath, CancellationToken cancellationToken = default) + { + return _dtRestClient.GetComponentAsync(digitalTwinId, componentPath, cancellationToken); + } + + /// + /// Gets a component on a digital twin. + /// + /// The Id of the digital twin. + /// The component being retrieved. + /// The cancellation token. + /// Json string representation of the component corresponding to the provided componentPath and the HTTP response. + public virtual Response GetComponent(string digitalTwinId, string componentPath, CancellationToken cancellationToken = default) + { + return _dtRestClient.GetComponent(digitalTwinId, componentPath, cancellationToken); + } + + /// + /// Updates properties of a component on a digital twin. + /// + /// The Id of the digital twin. + /// The component being modified. + /// The application/json-patch+json operations to be performed on the specified digital twin's component. + /// The optional settings for this request. + /// The cancellation token. + /// The HTTP response. + /// + /// + /// // Update Component with replacing property value + /// string propertyPath = "/ComponentProp1"; + /// string propValue = "New Value"; + /// + /// var componentUpdateUtility = new UpdateOperationsUtility(); + /// componentUpdateUtility.AppendReplaceOp(propertyPath, propValue); + /// + /// Response<string> response = await DigitalTwinsClient.UpdateComponentAsync(twinId, SamplesConstants.ComponentPath, componentUpdateUtility.Serialize()); + /// + /// + public virtual Task> UpdateComponentAsync(string digitalTwinId, string componentPath, string componentUpdateOperations, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + // TODO how can we make this patch easier to construct? + return _dtRestClient.UpdateComponentAsync(digitalTwinId, componentPath, componentUpdateOperations, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Updates properties of a component on a digital twin. + /// + /// The Id of the digital twin. + /// The component being modified. + /// The application/json-patch+json operations to be performed on the specified digital twin's component. + /// The optional settings for this request. + /// The cancellation token. + /// The HTTP response. + public virtual Response UpdateComponent(string digitalTwinId, string componentPath, string componentUpdateOperations, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + return _dtRestClient.UpdateComponent(digitalTwinId, componentPath, componentUpdateOperations, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Gets all the relationships on a digital twin. + /// + /// The Id of the source digital twin. + /// The name of a relationship to filter to. If null, all relationships for the digital twin will be returned. + /// The cancellation token. + /// The pageable list of application/json relationships belonging to the specified digital twin and the http response. + /// + /// + /// AsyncPageable<string> relationships = DigitalTwinsClient.GetRelationshipsAsync(twin.Key); + /// + /// + public virtual AsyncPageable GetRelationshipsAsync(string digitalTwinId, string relationshipName = null, CancellationToken cancellationToken = default) + { + if (digitalTwinId == null) + { + throw new ArgumentNullException(nameof(digitalTwinId)); + } + + async Task> FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(GetRelationships)}"); + scope.Start(); + try + { + Response response = await _dtRestClient.ListRelationshipsAsync(digitalTwinId, relationshipName, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + async Task> NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(GetRelationships)}"); + scope.Start(); + try + { + Response response = await _dtRestClient.ListRelationshipsNextPageAsync(nextLink, digitalTwinId, relationshipName, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + return PageableHelpers.CreateAsyncEnumerable(FirstPageFunc, NextPageFunc); + } + + /// + /// Gets all the relationships on a digital twin. + /// + /// The Id of the source digital twin. + /// The name of a relationship to filter to. If null, all relationships for the digital twin will be returned. + /// The cancellation token. + /// The pageable list of application/json relationships belonging to the specified digital twin and the http response. + public virtual Pageable GetRelationships(string digitalTwinId, string relationshipName = null, CancellationToken cancellationToken = default) + { + if (digitalTwinId == null) + { + throw new ArgumentNullException(nameof(digitalTwinId)); + } + + Page FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(GetRelationships)}"); + scope.Start(); + try + { + Response response = _dtRestClient.ListRelationships(digitalTwinId, relationshipName, cancellationToken); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + Page NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(GetRelationships)}"); + scope.Start(); + try + { + Response response = _dtRestClient.ListRelationshipsNextPage(nextLink, digitalTwinId, relationshipName, cancellationToken); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + return PageableHelpers.CreateEnumerable(FirstPageFunc, NextPageFunc); + } + + /// + /// Gets all the relationships referencing a digital twin as a target. + /// + /// The Id of the target digital twin. + /// The cancellation token. + /// The pageable list of application/json relationships directed towards the specified digital twin and the http response. + /// + /// + /// AsyncPageable<IncomingRelationship> incomingRelationships = DigitalTwinsClient.GetIncomingRelationshipsAsync(twin.Key); + /// + /// + public virtual AsyncPageable GetIncomingRelationshipsAsync(string digitalTwinId, CancellationToken cancellationToken = default) + { + async Task> FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(GetIncomingRelationships)}"); + scope.Start(); + try + { + Response response = await _dtRestClient.ListIncomingRelationshipsAsync(digitalTwinId, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + async Task> NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(GetIncomingRelationships)}"); + scope.Start(); + try + { + Response response = await _dtRestClient.ListIncomingRelationshipsNextPageAsync(nextLink, digitalTwinId, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + return PageableHelpers.CreateAsyncEnumerable(FirstPageFunc, NextPageFunc); + } + + /// + /// Gets all the relationships referencing a digital twin as a target. + /// + /// The Id of the target digital twin. + /// The cancellation token. + /// The pageable list of application/json relationships directed towards the specified digital twin and the http response. + public virtual Pageable GetIncomingRelationships(string digitalTwinId, CancellationToken cancellationToken = default) + { + Page FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsGeneratedClient.ListIncomingRelationships"); + scope.Start(); + try + { + Response response = _dtRestClient.ListIncomingRelationships(digitalTwinId, cancellationToken); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + Page NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinsGeneratedClient.ListIncomingRelationships"); + scope.Start(); + try + { + Response response = _dtRestClient.ListIncomingRelationshipsNextPage(nextLink, digitalTwinId, cancellationToken); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + return PageableHelpers.CreateEnumerable(FirstPageFunc, NextPageFunc); + } + + /// + /// Get a relationship on a digital twin. + /// + /// The Id of the source digital twin. + /// The Id of the relationship to retrieve. + /// The cancellation token. + /// The application/json relationship corresponding to the provided relationshipId and the http response. + /// This returned application/json string can always be serialized into an instance of or into an extension of that type. + public virtual Task> GetRelationshipAsync(string digitalTwinId, string relationshipId, CancellationToken cancellationToken = default) + { + return _dtRestClient.GetRelationshipByIdAsync(digitalTwinId, relationshipId, cancellationToken); + } + + /// + /// Get a relationship on a digital twin. + /// + /// The Id of the source digital twin. + /// The Id of the relationship to retrieve. + /// The cancellation token. + /// The application/json relationship corresponding to the provided relationshipId and the http response. + /// This returned application/json string can always be serialized into an instance of or into an extension of that type. + public virtual Response GetRelationship(string digitalTwinId, string relationshipId, CancellationToken cancellationToken = default) + { + return _dtRestClient.GetRelationshipById(digitalTwinId, relationshipId, cancellationToken); + } + + /// + /// Delete a relationship on a digital twin. + /// + /// The Id of the source digital twin. + /// The Id of the relationship to delete. + /// The optional settings for this request. + /// The cancellation token. + /// The http response. + public virtual Task DeleteRelationshipAsync(string digitalTwinId, string relationshipId, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + return _dtRestClient.DeleteRelationshipAsync(digitalTwinId, relationshipId, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Delete a relationship on a digital twin. + /// + /// The Id of the source digital twin. + /// The Id of the relationship to delete. + /// The optional settings for this request. + /// The cancellation token. + /// The http response. + public virtual Response DeleteRelationship(string digitalTwinId, string relationshipId, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + return _dtRestClient.DeleteRelationship(digitalTwinId, relationshipId, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Create a relationship on a digital twin. + /// + /// The Id of the source digital twin. + /// The Id of the relationship which is being created. + /// The application/json relationship to be created. + /// The cancellation token. + /// The http response. + /// + /// Relationships are a one-way link from a source digital twin to another, as described at creation time of the assigned model of the digital twin. + /// This argument must be the serialization of an instance of or the serialization of an extension of that type. + /// + /// + /// + /// string serializedRelationship = JsonSerializer.Serialize(relationship); + /// + /// await DigitalTwinsClient + /// .CreateRelationshipAsync( + /// relationship.SourceId, + /// relationship.Id, + /// serializedRelationship) + /// .ConfigureAwait(false); + /// + /// + public virtual Task> CreateRelationshipAsync(string digitalTwinId, string relationshipId, string relationship, CancellationToken cancellationToken = default) + { + return _dtRestClient.AddRelationshipAsync(digitalTwinId, relationshipId, relationship, cancellationToken); + } + + /// + /// Create a relationship on a digital twin. + /// + /// The Id of the source digital twin. + /// The Id of the relationship to delete. + /// The application/json relationship to be created. + /// The cancellation token. + /// The http response. + /// + /// Relationships are a one-way link from a source digital twin to another, as described at creation time of the assigned model of the digital twin. + /// This argument must be the serialization of an instance of or the serialization of an extension of that type. + /// + public virtual Response CreateRelationship(string digitalTwinId, string relationshipId, string relationship, CancellationToken cancellationToken = default) + { + return _dtRestClient.AddRelationship(digitalTwinId, relationshipId, relationship, cancellationToken); + } + + /// + /// Updates the properties of a relationship on a digital twin. + /// + /// The Id of the source digital twin. + /// The Id of the relationship to be updated. + /// The application/json-patch+json operations to be performed on the specified digital twin's relationship. + /// The optional settings for this request. + /// The cancellation token. + /// The http response. + public virtual Task UpdateRelationshipAsync(string digitalTwinId, string relationshipId, string relationshipUpdateOperations, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + // TODO how can we make this patch easier to construct? + return _dtRestClient.UpdateRelationshipAsync(digitalTwinId, relationshipId, relationshipUpdateOperations, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Updates the properties of a relationship on a digital twin. + /// + /// The Id of the source digital twin. + /// The Id of the relationship to be updated. + /// The application/json-patch+json operations to be performed on the specified digital twin's relationship. + /// The optional settings for this request. + /// The cancellation token. + /// The http response. + public virtual Response UpdateRelationship(string digitalTwinId, string relationshipId, string relationshipUpdateOperations, RequestOptions requestOptions = default, CancellationToken cancellationToken = default) + { + return _dtRestClient.UpdateRelationship(digitalTwinId, relationshipId, relationshipUpdateOperations, requestOptions?.IfMatchEtag, cancellationToken); + } + + /// + /// Gets the list of models. + /// + /// The model Ids to have dependencies retrieved. + /// Whether to include the model definition in the result. If false, only the model metadata will be returned. + /// The options to follow when listing the models. For example, the page size hint can be specified. + /// The cancellation token. + /// A pageable set of application/json models and the http response. + /// + /// + /// AsyncPageable<ModelData> allModels = DigitalTwinsClient.GetModelsAsync(); + /// await foreach (ModelData model in allModels) + /// { + /// Console.WriteLine($"Model Id: {model.Id}, display name: {model.DisplayName["en"]}, upload time: {model.UploadTime}, is decommissioned: {model.Decommissioned}"); + /// } + /// + /// + public virtual AsyncPageable GetModelsAsync(IEnumerable dependenciesFor = default, bool includeModelDefinition = false, GetModelsOptions options = default, CancellationToken cancellationToken = default) + { + async Task> FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinModelsClient.List"); + scope.Start(); + try + { + Response response = await _dtModelsRestClient.ListAsync(dependenciesFor, includeModelDefinition, options, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + async Task> NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinModelsClient.List"); + scope.Start(); + try + { + Response response = await _dtModelsRestClient.ListNextPageAsync(nextLink, dependenciesFor, includeModelDefinition, options, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + return PageableHelpers.CreateAsyncEnumerable(FirstPageFunc, NextPageFunc); + } + + /// + /// Gets the list of models. + /// + /// The model Ids to have dependencies retrieved. + /// Whether to include the model definition in the result. If false, only the model metadata will be returned. + /// The options to follow when listing the models. For example, the page size hint can be specified. + /// The cancellation token. + /// A pageable set of application/json models and the http response. + public virtual Pageable GetModels(IEnumerable dependenciesFor = default, bool includeModelDefinition = false, GetModelsOptions options = default, CancellationToken cancellationToken = default) + { + Page FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinModelsClient.List"); + scope.Start(); + try + { + Response response = _dtModelsRestClient.List(dependenciesFor, includeModelDefinition, options, cancellationToken); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + Page NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("DigitalTwinModelsClient.List"); + scope.Start(); + try + { + Response response = _dtModelsRestClient.ListNextPage(nextLink, dependenciesFor, includeModelDefinition, options, cancellationToken); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + return PageableHelpers.CreateEnumerable(FirstPageFunc, NextPageFunc); + } + + /// + /// Get a model, including the model metadata and the model definition. + /// + /// The Id of the model. + /// The cancellation token. + /// The application/json model and the http response. + /// + /// + /// Response<ModelData> sampleModel = await DigitalTwinsClient.GetModelAsync(sampleModelId).ConfigureAwait(false); + /// + /// + public virtual Task> GetModelAsync(string modelId, CancellationToken cancellationToken = default) + { + // The GetModel API will include the model definition in its response by default. + return _dtModelsRestClient.GetByIdAsync(modelId, IncludeModelDefinition, cancellationToken); + } + + /// + /// Get a model, including the model metadata and the model definition. + /// + /// The Id of the model. + /// The cancellation token. + /// The application/json model and the http response. + public virtual Response GetModel(string modelId, CancellationToken cancellationToken = default) + { + // The GetModel API will include the model definition in its response by default. + return _dtModelsRestClient.GetById(modelId, IncludeModelDefinition, cancellationToken); + } + + /// + /// Decommission a model. + /// + /// The Id of the model to decommission. + /// The cancellation token. + /// The http response. + /// + /// When a model is decomissioned, new digital twins will no longer be able to be defined by this model. + /// However, existing digital twins may continue to use this model. + /// Once a model is decomissioned, it may not be recommissioned. + /// + /// + /// + /// try + /// { + /// await DigitalTwinsClient.DecommissionModelAsync(sampleModelId).ConfigureAwait(false); + /// + /// Console.WriteLine($"Successfully decommissioned model {sampleModelId}"); + /// } + /// catch (Exception ex) + /// { + /// FatalError($"Failed to decommision model {sampleModelId} due to:\n{ex}"); + /// } + /// + /// + public virtual Task DecommissionModelAsync(string modelId, CancellationToken cancellationToken = default) + { + return _dtModelsRestClient.UpdateAsync(modelId, ModelsConstants.DecommissionModelOperationList, cancellationToken); + } + + /// + /// Decommission a model. + /// + /// The Id of the model to decommission. + /// The cancellation token. + /// The http response. + /// + /// When a model is decomissioned, new digital twins will no longer be able to be defined by this model. + /// However, existing digital twins may continue to use this model. + /// Once a model is decomissioned, it may not be recommissioned. + /// + public virtual Response DecommissionModel(string modelId, CancellationToken cancellationToken = default) + { + return _dtModelsRestClient.Update(modelId, ModelsConstants.DecommissionModelOperationList, cancellationToken); + } + + /// + /// Create one or many models. + /// + /// The set of models to create. Each string corresponds to exactly one model. + /// The cancellation token. + /// The created models and the http response. + /// + /// Bulk model creation is useful when several models have references to each other. + /// It simplifies creation for the client because otherwise the models would have to be created in a very specific order. + /// The service evaluates all models to ensure all references are satisfied, and then accepts or rejects the set. + /// So using this method, model creation is transactional. + /// + /// + /// + /// Response<IReadOnlyList<ModelData>> response = await DigitalTwinsClient.CreateModelsAsync(new[] { newComponentModelPayload, newModelPayload }).ConfigureAwait(false); + /// Console.WriteLine($"Successfully created a model with Id: {newComponentModelId}, {sampleModelId}, status: {response.GetRawResponse().Status}"); + /// + /// + public virtual Task>> CreateModelsAsync(IEnumerable models, CancellationToken cancellationToken = default) + { + return _dtModelsRestClient.AddAsync(models, cancellationToken); + } + + /// + /// Create one or many models. + /// + /// The set of models to create. Each string corresponds to exactly one model. + /// The cancellation token. + /// The created models and the http response. + /// + /// Bulk model creation is useful when several models have references to each other. + /// It simplifies creation for the client because otherwise the models would have to be created in a very specific order. + /// The service evaluates all models to ensure all references are satisfied, and then accepts or rejects the set. + /// So using this method, model creation is transactional. + /// + public virtual Response> CreateModels(IEnumerable models, CancellationToken cancellationToken = default) + { + return _dtModelsRestClient.Add(models, cancellationToken); + } + + /// + /// Deletes a model. + /// + /// The id for the model. The id is globally unique and case sensitive. + /// The cancellation token to use. + /// + /// A model can only be deleted if no other models reference it. + /// Status codes: + /// 204 (No Content): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no model with the provided id. + /// 409 (Conflict): There are dependencies on the model that prevent it from being deleted. + /// + /// + /// + /// try + /// { + /// await DigitalTwinsClient.DeleteModelAsync(sampleModelId).ConfigureAwait(false); + /// + /// Console.WriteLine($"Deleted model {sampleModelId}"); + /// } + /// catch (Exception ex) + /// { + /// FatalError($"Failed to delete model {sampleModelId} due to:\n{ex}"); + /// } + /// + /// + public virtual Task DeleteModelAsync(string modelId, CancellationToken cancellationToken = default) + { + return _dtModelsRestClient.DeleteAsync(modelId, cancellationToken); + } + + /// + /// Deletes a model. + /// + /// The id for the model. The id is globally unique and case sensitive. + /// The cancellation token to use. + /// + /// A model can only be deleted if no other models reference it. + /// Status codes: + /// 204 (No Content): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no model with the provided id. + /// 409 (Conflict): There are dependencies on the model that prevent it from being deleted. + /// + public virtual Response DeleteModel(string modelId, CancellationToken cancellationToken = default) + { + return _dtModelsRestClient.Delete(modelId, cancellationToken); + } + + /// + /// Query for digital twins. + /// + /// The query string, in SQL-like syntax. + /// The cancellation token. + /// The pageable list of query results. + /// + /// + /// // This code snippet demonstrates the simplest way to iterate over the digital twin results, where paging + /// // happens under the covers. + /// AsyncPageable<string> asyncPageableResponse = DigitalTwinsClient.QueryAsync("SELECT * FROM digitaltwins"); + /// + /// // Iterate over the twin instances in the pageable response. + /// // The "await" keyword here is required because new pages will be fetched when necessary, + /// // which involves a request to the service. + /// await foreach (string response in asyncPageableResponse) + /// { + /// BasicDigitalTwin twin = JsonSerializer.Deserialize<BasicDigitalTwin>(response); + /// Console.WriteLine($"Found digital twin: {twin.Id}"); + /// } + /// + /// + public virtual AsyncPageable QueryAsync(string query, CancellationToken cancellationToken = default) + { + // Note: pageSizeHint is not supported as a parameter in the service for query API, so ignoring it. + // Cannot remove the parameter as the function signature in Azure.Core helper needs it. + async Task> FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(Query)}"); + scope.Start(); + try + { + var querySpecification = new QuerySpecification + { + Query = query + }; + Response response = await _queryClient.QueryTwinsAsync(querySpecification, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Items, response.Value.ContinuationToken, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + async Task> NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(Query)}"); + scope.Start(); + try + { + var querySpecification = new QuerySpecification + { + ContinuationToken = nextLink + }; + Response response = await _queryClient.QueryTwinsAsync(querySpecification, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Items, response.Value.ContinuationToken, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + return PageableHelpers.CreateAsyncEnumerable(FirstPageFunc, NextPageFunc); + } + + /// + /// Query for digital twins. + /// + /// The query string, in SQL-like syntax. + /// The cancellation token. + /// The pageable list of query results. + /// + /// A basic query for all digital twins: SELECT * FROM digitalTwins. + /// + public virtual Pageable Query(string query, CancellationToken cancellationToken = default) + { + // Note: pageSizeHint is not supported as a parameter in the service for query API, so ignoring it. + // Cannot remove the parameter as the function signature in Azure.Core helper needs it. + Page FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(Query)}"); + scope.Start(); + try + { + var querySpecification = new QuerySpecification + { + Query = query + }; + Response response = _queryClient.QueryTwins(querySpecification, cancellationToken); + return Page.FromValues(response.Value.Items, response.Value.ContinuationToken, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + Page NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(DigitalTwinsClient)}.{nameof(Query)}"); + scope.Start(); + try + { + var querySpecification = new QuerySpecification + { + ContinuationToken = nextLink + }; + Response response = _queryClient.QueryTwins(querySpecification, cancellationToken); + return Page.FromValues(response.Value.Items, response.Value.ContinuationToken, response.GetRawResponse()); + } + catch (Exception ex) + { + scope.Failed(ex); + throw; + } + } + + return PageableHelpers.CreateEnumerable(FirstPageFunc, NextPageFunc); + } + + /// . + /// List the event routes in a digital twins instance. + /// + /// The options to use when listing the event routes. One can set the maximum number of items to retrieve per request, however the service may return less than requested. + /// The cancellation token. + /// A pageable set of application/json event routes and the http response. + /// + /// + /// AsyncPageable<EventRoute> response = DigitalTwinsClient.GetEventRoutesAsync(); + /// await foreach (EventRoute er in response) + /// { + /// Console.WriteLine($"Event route: {er.Id}, endpoint name: {er.EndpointName}"); + /// } + /// + /// + public virtual AsyncPageable GetEventRoutesAsync(EventRoutesListOptions options = default, CancellationToken cancellationToken = default) + { + async Task> FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("EventRoutesClient.List"); + scope.Start(); + try + { + Response response = await _eventRoutesRestClient.ListAsync(options, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + async Task> NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("EventRoutesClient.List"); + scope.Start(); + try + { + Response response = await _eventRoutesRestClient.ListNextPageAsync(nextLink, options, cancellationToken).ConfigureAwait(false); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + return PageableHelpers.CreateAsyncEnumerable(FirstPageFunc, NextPageFunc); + } + + /// . + /// List the event routes in a digital twins instance. + /// + /// The options to use when listing the event routes. One can set the maximum number of items to retrieve per request, however the service may return less than requested. + /// The cancellation token. + /// A pageable set of application/json event routes and the http response. + public virtual Pageable GetEventRoutes(EventRoutesListOptions options = default, CancellationToken cancellationToken = default) + { + Page FirstPageFunc(int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("EventRoutesClient.List"); + scope.Start(); + try + { + Response response = _eventRoutesRestClient.List(options, cancellationToken); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + Page NextPageFunc(string nextLink, int? pageSizeHint) + { + using DiagnosticScope scope = _clientDiagnostics.CreateScope("EventRoutesClient.List"); + scope.Start(); + try + { + Response response = _eventRoutesRestClient.ListNextPage(nextLink, options, cancellationToken); + return Page.FromValues(response.Value.Value, response.Value.NextLink, response.GetRawResponse()); + } + catch (Exception e) + { + scope.Failed(e); + throw; + } + } + + return PageableHelpers.CreateEnumerable(FirstPageFunc, NextPageFunc); + } + + /// + /// Get an event route by Id. + /// + /// The Id of the event route. + /// The cancellation token. + /// The application/json event routes and the http response. + public virtual Task> GetEventRouteAsync(string eventRouteId, CancellationToken cancellationToken = default) + { + return _eventRoutesRestClient.GetByIdAsync(eventRouteId, cancellationToken); + } + + /// + /// Get an event route by Id. + /// + /// The Id of the event route. + /// The cancellation token. + /// The application/json event routes and the http response. + public virtual Response GetEventRoute(string eventRouteId, CancellationToken cancellationToken = default) + { + return _eventRoutesRestClient.GetById(eventRouteId, cancellationToken); + } + + /// + /// Create an event route. + /// + /// The Id of the event route to create. + /// The event route data containing the endpoint and optional filter. + /// The cancellation token. + /// The http response. + /// + /// + /// string eventFilter = "$eventType = 'DigitalTwinTelemetryMessages' or $eventType = 'DigitalTwinLifecycleNotification'"; + /// var eventRoute = new EventRoute(_eventhubEndpointName) + /// { + /// Filter = eventFilter + /// }; + /// + /// Response createEventRouteResponse = await DigitalTwinsClient.CreateEventRouteAsync(_eventRouteId, eventRoute).ConfigureAwait(false); + /// + /// + public virtual Task CreateEventRouteAsync(string eventRouteId, EventRoute eventRoute, CancellationToken cancellationToken = default) + { + return _eventRoutesRestClient.AddAsync(eventRouteId, eventRoute, cancellationToken); + } + + /// + /// Create an event route. + /// + /// The Id of the event route to create. + /// The event route data containing the endpoint and optional filter. + /// The cancellation token. + /// The http response. + public virtual Response CreateEventRoute(string eventRouteId, EventRoute eventRoute, CancellationToken cancellationToken = default) + { + return _eventRoutesRestClient.Add(eventRouteId, eventRoute, cancellationToken); + } + + /// + /// Delete an event route. + /// + /// The Id of the event route to delete. + /// The cancellation token. + /// The http response. + /// + /// + /// Response response = await DigitalTwinsClient.DeleteEventRouteAsync(_eventRouteId).ConfigureAwait(false); + /// + /// + public virtual Task DeleteEventRouteAsync(string eventRouteId, CancellationToken cancellationToken = default) + { + return _eventRoutesRestClient.DeleteAsync(eventRouteId, cancellationToken); + } + + /// + /// Delete an event route. + /// + /// The Id of the event route to delete. + /// The cancellation token. + /// The http response. + public virtual Response DeleteEventRoute(string eventRouteId, CancellationToken cancellationToken = default) + { + return _eventRoutesRestClient.Delete(eventRouteId, cancellationToken); + } + + /// + /// Publish telemetry from a digital twin, which is then consumed by one or many destination endpoints (subscribers) defined under . + /// These event routes need to be set before publishing a telemetry message, in order for the telemetry message to be consumed. + /// + /// The Id of the digital twin. + /// The application/json telemetry payload to be sent. + /// The additional information to be used when processing a telemetry request. + /// The cancellation token. + /// The http response. + public virtual Task PublishTelemetryAsync(string digitalTwinId, string payload, TelemetryOptions options = default, CancellationToken cancellationToken = default) + { + TelemetryOptions telemetryOptions = options ?? new TelemetryOptions(); + var dateTimeInString = TypeFormatters.ToString(telemetryOptions.TimeStamp, DateTimeOffsetFormat); + + return _dtRestClient + .SendTelemetryAsync(digitalTwinId, telemetryOptions.MessageId, payload, dateTimeInString, cancellationToken); + } + + /// + /// Publish telemetry from a digital twin, which is then consumed by one or many destination endpoints (subscribers) defined under . + /// These event routes need to be set before publishing a telemetry message, in order for the telemetry message to be consumed. + /// + /// The Id of the digital twin. + /// The application/json telemetry payload to be sent. + /// The additional information to be used when processing a telemetry request. + /// The cancellation token. + /// The http response. + public virtual Response PublishTelemetry(string digitalTwinId, string payload, TelemetryOptions options = default, CancellationToken cancellationToken = default) + { + TelemetryOptions telemetryOptions = options ?? new TelemetryOptions(); + var dateTimeInString = TypeFormatters.ToString(telemetryOptions.TimeStamp, DateTimeOffsetFormat); + + return _dtRestClient.SendTelemetry(digitalTwinId, telemetryOptions.MessageId, payload, dateTimeInString, cancellationToken); + } + + /// + /// Publish telemetry from a digital twin's component, which is then consumed by one or many destination endpoints (subscribers) defined under . + /// These event routes need to be set before publishing a telemetry message, in order for the telemetry message to be consumed. + /// + /// The Id of the digital twin. + /// The name of the DTDL component. + /// The application/json telemetry payload to be sent. + /// The additional information to be used when processing a telemetry request. + /// The cancellation token. + /// The http response. + public virtual Task PublishComponentTelemetryAsync(string digitalTwinId, string componentName, string payload, TelemetryOptions options = default, CancellationToken cancellationToken = default) + { + TelemetryOptions telemetryOptions = options ?? new TelemetryOptions(); + var dateTimeInString = TypeFormatters.ToString(telemetryOptions.TimeStamp, DateTimeOffsetFormat); + + return _dtRestClient + .SendComponentTelemetryAsync(digitalTwinId, componentName, telemetryOptions.MessageId, payload, dateTimeInString, cancellationToken); + } + + /// + /// Publish telemetry from a digital twin's component, which is then consumed by one or many destination endpoints (subscribers) defined under . + /// These event routes need to be set before publishing a telemetry message, in order for the telemetry message to be consumed. + /// + /// The Id of the digital twin. + /// The name of the DTDL component. + /// The application/json telemetry payload to be sent. + /// The additional information to be used when processing a telemetry request. + /// The cancellation token. + /// The http response. + public virtual Response PublishComponentTelemetry(string digitalTwinId, string componentName, string payload, TelemetryOptions options = default, CancellationToken cancellationToken = default) + { + TelemetryOptions telemetryOptions = options ?? new TelemetryOptions(); + var dateTimeInString = TypeFormatters.ToString(telemetryOptions.TimeStamp, DateTimeOffsetFormat); + + return _dtRestClient.SendComponentTelemetry(digitalTwinId, componentName, telemetryOptions.MessageId, payload, dateTimeInString, cancellationToken); + } + + /// + /// Gets the scope for authentication/authorization policy. + /// + /// Azure digital twins instance Uri. + /// List of scopes for the specified endpoint. + internal static string[] GetAuthorizationScopes(Uri endpoint) + { + Argument.AssertNotNull(endpoint, nameof(endpoint)); + Argument.AssertNotNullOrEmpty(endpoint.AbsoluteUri, nameof(endpoint.AbsoluteUri)); + + // Uri representation for azure digital twin app Id "0b07f429-9f4b-4714-9392-cc5e8e80c8b0" in the public cloud. + const string adtPublicCloudAppId = "https://digitaltwins.azure.net"; + const string defaultPermissionConsent = "/.default"; + + // If the endpoint is in Azure public cloud, the suffix will have "azure.net" or "ppe.net". + // Once ADT becomes available in other clouds, their corresponding scope has to be matched and set. + if (endpoint.AbsoluteUri.IndexOf("azure.net", StringComparison.OrdinalIgnoreCase) > 0 + || endpoint.AbsoluteUri.IndexOf("ppe.net", StringComparison.OrdinalIgnoreCase) > 0) + { + return new[] { adtPublicCloudAppId + defaultPermissionConsent }; + } + + throw new InvalidOperationException($"Azure digital twins instance endpoint '{endpoint.AbsoluteUri}' is not valid."); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClientOptions.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClientOptions.cs new file mode 100644 index 0000000000000..7943d55e2f5d2 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/DigitalTwinsClientOptions.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using Azure.Core; + +namespace Azure.DigitalTwins.Core +{ + /// + /// Options that allow configuration of requests sent to the digital twins service. + /// + public class DigitalTwinsClientOptions : ClientOptions + { + internal const ServiceVersion LatestVersion = ServiceVersion.V2020_05_31_preview; + + /// + /// The versions of Azure Digital Twins supported by this client + /// library. + /// + public enum ServiceVersion + { +#pragma warning disable CA1707 // Identifiers should not contain underscores + + /// + /// 2020-05-31-preview + /// + V2020_05_31_preview = 1 + +#pragma warning restore CA1707 // Identifiers should not contain underscores + } + + /// + /// Gets the of the service API used when + /// making requests. + /// + public ServiceVersion Version { get; } + + /// + /// Initializes a new instance of the + /// class. + /// + /// + /// The of the service API used when + /// making requests. + /// + public DigitalTwinsClientOptions(ServiceVersion version = LatestVersion) + { + Version = version; + } + + internal string GetVersionString() + { + return Version switch + { + ServiceVersion.V2020_05_31_preview => "2020-05-31-preview", + _ => throw new ArgumentException(Version.ToString()), + }; + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinModelsRestClient.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinModelsRestClient.cs new file mode 100644 index 0000000000000..3322e1f0e2e21 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinModelsRestClient.cs @@ -0,0 +1,429 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.DigitalTwins.Core.Models; + +namespace Azure.DigitalTwins.Core +{ + internal partial class DigitalTwinModelsRestClient + { + private Uri endpoint; + private string apiVersion; + private ClientDiagnostics _clientDiagnostics; + private HttpPipeline _pipeline; + + /// Initializes a new instance of DigitalTwinModelsRestClient. + /// The handler for diagnostic messaging in the client. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// server parameter. + /// Api Version. + /// This occurs when one of the required arguments is null. + public DigitalTwinModelsRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Uri endpoint = null, string apiVersion = "2020-05-31-preview") + { + endpoint ??= new Uri("https://digitaltwins-name.digitaltwins.azure.net"); + if (apiVersion == null) + { + throw new ArgumentNullException(nameof(apiVersion)); + } + + this.endpoint = endpoint; + this.apiVersion = apiVersion; + _clientDiagnostics = clientDiagnostics; + _pipeline = pipeline; + } + + internal HttpMessage CreateListRequest(IEnumerable dependenciesFor, bool? includeModelDefinition, GetModelsOptions digitalTwinModelsListOptions) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/models", false); + if (dependenciesFor != null) + { + uri.AppendQueryDelimited("dependenciesFor", dependenciesFor, ",", true); + } + if (includeModelDefinition != null) + { + uri.AppendQuery("includeModelDefinition", includeModelDefinition.Value, true); + } + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + if (digitalTwinModelsListOptions?.MaxItemCount != null) + { + request.Headers.Add("x-ms-max-item-count", digitalTwinModelsListOptions.MaxItemCount.Value); + } + return message; + } + + /// + /// Retrieves model metadata and, optionally, model definitions. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The set of the models which will have their dependencies retrieved. If omitted, all models are retrieved. + /// When true the model definition will be returned as part of the result. + /// Parameter group. + /// The cancellation token to use. + public async Task> ListAsync(IEnumerable dependenciesFor = null, bool? includeModelDefinition = null, GetModelsOptions digitalTwinModelsListOptions = null, CancellationToken cancellationToken = default) + { + using var message = CreateListRequest(dependenciesFor, includeModelDefinition, digitalTwinModelsListOptions); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + PagedModelDataCollection value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = PagedModelDataCollection.DeserializePagedModelDataCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves model metadata and, optionally, model definitions. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The set of the models which will have their dependencies retrieved. If omitted, all models are retrieved. + /// When true the model definition will be returned as part of the result. + /// Parameter group. + /// The cancellation token to use. + public Response List(IEnumerable dependenciesFor = null, bool? includeModelDefinition = null, GetModelsOptions digitalTwinModelsListOptions = null, CancellationToken cancellationToken = default) + { + using var message = CreateListRequest(dependenciesFor, includeModelDefinition, digitalTwinModelsListOptions); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + PagedModelDataCollection value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = PagedModelDataCollection.DeserializePagedModelDataCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateGetByIdRequest(string id, bool? includeModelDefinition) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/models/", false); + uri.AppendPath(id, true); + if (includeModelDefinition != null) + { + uri.AppendQuery("includeModelDefinition", includeModelDefinition.Value, true); + } + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + return message; + } + + /// + /// Retrieves model metadata and optionally the model definition. + /// Status codes: + /// 200 (OK): Success. + /// 404 (Not Found): There is no model with the provided id. + /// + /// The id for the model. The id is globally unique and case sensitive. + /// When true the model definition will be returned as part of the result. + /// The cancellation token to use. + public async Task> GetByIdAsync(string id, bool? includeModelDefinition = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateGetByIdRequest(id, includeModelDefinition); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + ModelData value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = ModelData.DeserializeModelData(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves model metadata and optionally the model definition. + /// Status codes: + /// 200 (OK): Success. + /// 404 (Not Found): There is no model with the provided id. + /// + /// The id for the model. The id is globally unique and case sensitive. + /// When true the model definition will be returned as part of the result. + /// The cancellation token to use. + public Response GetById(string id, bool? includeModelDefinition = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateGetByIdRequest(id, includeModelDefinition); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + ModelData value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = ModelData.DeserializeModelData(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateUpdateRequest(string id, IEnumerable updateModel) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/models/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json-patch+json"); + using var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteStartArray(); + foreach (var item in updateModel) + { + content.JsonWriter.WriteObjectValue(item); + } + content.JsonWriter.WriteEndArray(); + request.Content = content; + return message; + } + + internal HttpMessage CreateDeleteRequest(string id) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Delete; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/models/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + return message; + } + + /// + /// Deletes a model. A model can only be deleted if no other models reference it. + /// Status codes: + /// 204 (No Content): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no model with the provided id. + /// 409 (Conflict): There are dependencies on the model that prevent it from being deleted. + /// + /// The id for the model. The id is globally unique and case sensitive. + /// The cancellation token to use. + public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateDeleteRequest(id); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Deletes a model. A model can only be deleted if no other models reference it. + /// Status codes: + /// 204 (No Content): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no model with the provided id. + /// 409 (Conflict): There are dependencies on the model that prevent it from being deleted. + /// + /// The id for the model. The id is globally unique and case sensitive. + /// The cancellation token to use. + public Response Delete(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateDeleteRequest(id); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateListNextPageRequest(string nextLink, IEnumerable dependenciesFor, bool? includeModelDefinition, GetModelsOptions digitalTwinModelsListOptions) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendRawNextLink(nextLink, false); + request.Uri = uri; + if (digitalTwinModelsListOptions?.MaxItemCount != null) + { + request.Headers.Add("x-ms-max-item-count", digitalTwinModelsListOptions.MaxItemCount.Value); + } + return message; + } + + /// + /// Retrieves model metadata and, optionally, model definitions. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The URL to the next page of results. + /// The set of the models which will have their dependencies retrieved. If omitted, all models are retrieved. + /// When true the model definition will be returned as part of the result. + /// Parameter group. + /// The cancellation token to use. + public async Task> ListNextPageAsync(string nextLink, IEnumerable dependenciesFor = null, bool? includeModelDefinition = null, GetModelsOptions digitalTwinModelsListOptions = null, CancellationToken cancellationToken = default) + { + if (nextLink == null) + { + throw new ArgumentNullException(nameof(nextLink)); + } + + using var message = CreateListNextPageRequest(nextLink, dependenciesFor, includeModelDefinition, digitalTwinModelsListOptions); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + PagedModelDataCollection value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = PagedModelDataCollection.DeserializePagedModelDataCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves model metadata and, optionally, model definitions. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The URL to the next page of results. + /// The set of the models which will have their dependencies retrieved. If omitted, all models are retrieved. + /// When true the model definition will be returned as part of the result. + /// Parameter group. + /// The cancellation token to use. + public Response ListNextPage(string nextLink, IEnumerable dependenciesFor = null, bool? includeModelDefinition = null, GetModelsOptions digitalTwinModelsListOptions = null, CancellationToken cancellationToken = default) + { + if (nextLink == null) + { + throw new ArgumentNullException(nameof(nextLink)); + } + + using var message = CreateListNextPageRequest(nextLink, dependenciesFor, includeModelDefinition, digitalTwinModelsListOptions); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + PagedModelDataCollection value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = PagedModelDataCollection.DeserializePagedModelDataCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinsRestClient.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinsRestClient.cs new file mode 100644 index 0000000000000..646241adaa6dc --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinsRestClient.cs @@ -0,0 +1,970 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.DigitalTwins.Core.Models; + +namespace Azure.DigitalTwins.Core +{ + internal partial class DigitalTwinsRestClient + { + private Uri endpoint; + private string apiVersion; + private ClientDiagnostics _clientDiagnostics; + private HttpPipeline _pipeline; + + /// Initializes a new instance of DigitalTwinsRestClient. + /// The handler for diagnostic messaging in the client. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// server parameter. + /// Api Version. + /// This occurs when one of the required arguments is null. + public DigitalTwinsRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Uri endpoint = null, string apiVersion = "2020-05-31-preview") + { + endpoint ??= new Uri("https://digitaltwins-name.digitaltwins.azure.net"); + if (apiVersion == null) + { + throw new ArgumentNullException(nameof(apiVersion)); + } + + this.endpoint = endpoint; + this.apiVersion = apiVersion; + _clientDiagnostics = clientDiagnostics; + _pipeline = pipeline; + } + + internal HttpMessage CreateGetByIdRequest(string id) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + return message; + } + + internal HttpMessage CreateDeleteRequest(string id, string ifMatch) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Delete; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + if (ifMatch != null) + { + request.Headers.Add("If-Match", ifMatch); + } + return message; + } + + /// + /// Deletes a digital twin. All relationships referencing the digital twin must already be deleted. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// Only perform the operation if the entity's etag matches one of the etags provided or * is provided. + /// The cancellation token to use. + public async Task DeleteAsync(string id, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateDeleteRequest(id, ifMatch); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Deletes a digital twin. All relationships referencing the digital twin must already be deleted. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// Only perform the operation if the entity's etag matches one of the etags provided or * is provided. + /// The cancellation token to use. + public Response Delete(string id, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateDeleteRequest(id, ifMatch); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateUpdateRequest(string id, IEnumerable patchDocument, string ifMatch) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + if (ifMatch != null) + { + request.Headers.Add("If-Match", ifMatch); + } + request.Headers.Add("Content-Type", "application/json-patch+json"); + using var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteStartArray(); + foreach (var item in patchDocument) + { + content.JsonWriter.WriteObjectValue(item); + } + content.JsonWriter.WriteEndArray(); + request.Content = content; + return message; + } + + internal HttpMessage CreateGetRelationshipByIdRequest(string id, string relationshipId) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/relationships/", false); + uri.AppendPath(relationshipId, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + return message; + } + + internal HttpMessage CreateAddRelationshipRequest(string id, string relationshipId, object relationship) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Put; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/relationships/", false); + uri.AppendPath(relationshipId, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("If-None-Match", "*"); + request.Headers.Add("Content-Type", "application/json"); + if (relationship != null) + { + using var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(relationship); + request.Content = content; + } + return message; + } + + internal HttpMessage CreateDeleteRelationshipRequest(string id, string relationshipId, string ifMatch) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Delete; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/relationships/", false); + uri.AppendPath(relationshipId, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + if (ifMatch != null) + { + request.Headers.Add("If-Match", ifMatch); + } + return message; + } + + /// + /// Deletes a relationship between two digital twins. + /// Status codes: + /// 200 (OK): Success. + /// 404 (Not Found): There is either no digital twin or relationship with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The id of the relationship. The id is unique within the digital twin and case sensitive. + /// Only perform the operation if the entity's etag matches one of the etags provided or * is provided. + /// The cancellation token to use. + public async Task DeleteRelationshipAsync(string id, string relationshipId, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (relationshipId == null) + { + throw new ArgumentNullException(nameof(relationshipId)); + } + + using var message = CreateDeleteRelationshipRequest(id, relationshipId, ifMatch); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Deletes a relationship between two digital twins. + /// Status codes: + /// 200 (OK): Success. + /// 404 (Not Found): There is either no digital twin or relationship with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The id of the relationship. The id is unique within the digital twin and case sensitive. + /// Only perform the operation if the entity's etag matches one of the etags provided or * is provided. + /// The cancellation token to use. + public Response DeleteRelationship(string id, string relationshipId, string ifMatch = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (relationshipId == null) + { + throw new ArgumentNullException(nameof(relationshipId)); + } + + using var message = CreateDeleteRelationshipRequest(id, relationshipId, ifMatch); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateUpdateRelationshipRequest(string id, string relationshipId, string ifMatch, IEnumerable patchDocument) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/relationships/", false); + uri.AppendPath(relationshipId, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + if (ifMatch != null) + { + request.Headers.Add("If-Match", ifMatch); + } + request.Headers.Add("Content-Type", "application/json-patch+json"); + if (patchDocument != null) + { + using var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteStartArray(); + foreach (var item in patchDocument) + { + content.JsonWriter.WriteObjectValue(item); + } + content.JsonWriter.WriteEndArray(); + request.Content = content; + } + return message; + } + + internal HttpMessage CreateListRelationshipsRequest(string id, string relationshipName) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/relationships", false); + if (relationshipName != null) + { + uri.AppendQuery("relationshipName", relationshipName, true); + } + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + return message; + } + + /// + /// Retrieves the relationships from a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The name of the relationship. + /// The cancellation token to use. + public async Task> ListRelationshipsAsync(string id, string relationshipName = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateListRelationshipsRequest(id, relationshipName); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + RelationshipCollection value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = RelationshipCollection.DeserializeRelationshipCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves the relationships from a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The name of the relationship. + /// The cancellation token to use. + public Response ListRelationships(string id, string relationshipName = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateListRelationshipsRequest(id, relationshipName); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + RelationshipCollection value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = RelationshipCollection.DeserializeRelationshipCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateListIncomingRelationshipsRequest(string id) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/incomingrelationships", false); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + return message; + } + + /// + /// Retrieves all incoming relationship for a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The cancellation token to use. + public async Task> ListIncomingRelationshipsAsync(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateListIncomingRelationshipsRequest(id); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + IncomingRelationshipCollection value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = IncomingRelationshipCollection.DeserializeIncomingRelationshipCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves all incoming relationship for a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The cancellation token to use. + public Response ListIncomingRelationships(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateListIncomingRelationshipsRequest(id); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + IncomingRelationshipCollection value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = IncomingRelationshipCollection.DeserializeIncomingRelationshipCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateSendTelemetryRequest(string id, string dtId, object telemetry, string dtTimestamp) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/telemetry", false); + request.Uri = uri; + request.Headers.Add("dt-id", dtId); + if (dtTimestamp != null) + { + request.Headers.Add("dt-timestamp", dtTimestamp); + } + request.Headers.Add("Content-Type", "application/json"); + using var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(telemetry); + request.Content = content; + return message; + } + + /// + /// Sends telemetry on behalf of a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages. + /// The telemetry measurements to send from the digital twin. + /// An RFC 3339 timestamp that identifies the time the telemetry was measured. + /// The cancellation token to use. + public async Task SendTelemetryAsync(string id, string dtId, object telemetry, string dtTimestamp = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (dtId == null) + { + throw new ArgumentNullException(nameof(dtId)); + } + if (telemetry == null) + { + throw new ArgumentNullException(nameof(telemetry)); + } + + using var message = CreateSendTelemetryRequest(id, dtId, telemetry, dtTimestamp); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Sends telemetry on behalf of a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages. + /// The telemetry measurements to send from the digital twin. + /// An RFC 3339 timestamp that identifies the time the telemetry was measured. + /// The cancellation token to use. + public Response SendTelemetry(string id, string dtId, object telemetry, string dtTimestamp = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (dtId == null) + { + throw new ArgumentNullException(nameof(dtId)); + } + if (telemetry == null) + { + throw new ArgumentNullException(nameof(telemetry)); + } + + using var message = CreateSendTelemetryRequest(id, dtId, telemetry, dtTimestamp); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateSendComponentTelemetryRequest(string id, string componentPath, string dtId, object telemetry, string dtTimestamp) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/components/", false); + uri.AppendPath(componentPath, true); + uri.AppendPath("/telemetry", false); + request.Uri = uri; + request.Headers.Add("dt-id", dtId); + if (dtTimestamp != null) + { + request.Headers.Add("dt-timestamp", dtTimestamp); + } + request.Headers.Add("Content-Type", "application/json"); + using var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(telemetry); + request.Content = content; + return message; + } + + /// + /// Sends telemetry on behalf of a component in a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is either no digital twin with the provided id or the component path is invalid. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The name of the DTDL component. + /// A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages. + /// The telemetry measurements to send from the digital twin's component. + /// An RFC 3339 timestamp that identifies the time the telemetry was measured. + /// The cancellation token to use. + public async Task SendComponentTelemetryAsync(string id, string componentPath, string dtId, object telemetry, string dtTimestamp = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (componentPath == null) + { + throw new ArgumentNullException(nameof(componentPath)); + } + if (dtId == null) + { + throw new ArgumentNullException(nameof(dtId)); + } + if (telemetry == null) + { + throw new ArgumentNullException(nameof(telemetry)); + } + + using var message = CreateSendComponentTelemetryRequest(id, componentPath, dtId, telemetry, dtTimestamp); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Sends telemetry on behalf of a component in a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is either no digital twin with the provided id or the component path is invalid. + /// + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The name of the DTDL component. + /// A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages. + /// The telemetry measurements to send from the digital twin's component. + /// An RFC 3339 timestamp that identifies the time the telemetry was measured. + /// The cancellation token to use. + public Response SendComponentTelemetry(string id, string componentPath, string dtId, object telemetry, string dtTimestamp = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + if (componentPath == null) + { + throw new ArgumentNullException(nameof(componentPath)); + } + if (dtId == null) + { + throw new ArgumentNullException(nameof(dtId)); + } + if (telemetry == null) + { + throw new ArgumentNullException(nameof(telemetry)); + } + + using var message = CreateSendComponentTelemetryRequest(id, componentPath, dtId, telemetry, dtTimestamp); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateGetComponentRequest(string id, string componentPath) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/components/", false); + uri.AppendPath(componentPath, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + return message; + } + + internal HttpMessage CreateUpdateComponentRequest(string id, string componentPath, string ifMatch, IEnumerable patchDocument) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Patch; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/digitaltwins/", false); + uri.AppendPath(id, true); + uri.AppendPath("/components/", false); + uri.AppendPath(componentPath, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + if (ifMatch != null) + { + request.Headers.Add("If-Match", ifMatch); + } + request.Headers.Add("Content-Type", "application/json-patch+json"); + if (patchDocument != null) + { + using var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteStartArray(); + foreach (var item in patchDocument) + { + content.JsonWriter.WriteObjectValue(item); + } + content.JsonWriter.WriteEndArray(); + request.Content = content; + } + return message; + } + + internal HttpMessage CreateListRelationshipsNextPageRequest(string nextLink, string id, string relationshipName) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendRawNextLink(nextLink, false); + request.Uri = uri; + return message; + } + + /// + /// Retrieves the relationships from a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The URL to the next page of results. + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The name of the relationship. + /// The cancellation token to use. + public async Task> ListRelationshipsNextPageAsync(string nextLink, string id, string relationshipName = null, CancellationToken cancellationToken = default) + { + if (nextLink == null) + { + throw new ArgumentNullException(nameof(nextLink)); + } + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateListRelationshipsNextPageRequest(nextLink, id, relationshipName); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + RelationshipCollection value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = RelationshipCollection.DeserializeRelationshipCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves the relationships from a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The URL to the next page of results. + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The name of the relationship. + /// The cancellation token to use. + public Response ListRelationshipsNextPage(string nextLink, string id, string relationshipName = null, CancellationToken cancellationToken = default) + { + if (nextLink == null) + { + throw new ArgumentNullException(nameof(nextLink)); + } + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateListRelationshipsNextPageRequest(nextLink, id, relationshipName); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + RelationshipCollection value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = RelationshipCollection.DeserializeRelationshipCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateListIncomingRelationshipsNextPageRequest(string nextLink, string id) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendRawNextLink(nextLink, false); + request.Uri = uri; + return message; + } + + /// + /// Retrieves all incoming relationship for a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The URL to the next page of results. + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The cancellation token to use. + public async Task> ListIncomingRelationshipsNextPageAsync(string nextLink, string id, CancellationToken cancellationToken = default) + { + if (nextLink == null) + { + throw new ArgumentNullException(nameof(nextLink)); + } + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateListIncomingRelationshipsNextPageRequest(nextLink, id); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + IncomingRelationshipCollection value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = IncomingRelationshipCollection.DeserializeIncomingRelationshipCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves all incoming relationship for a digital twin. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// 404 (Not Found): There is no digital twin with the provided id. + /// + /// The URL to the next page of results. + /// The id of the digital twin. The id is unique within the service and case sensitive. + /// The cancellation token to use. + public Response ListIncomingRelationshipsNextPage(string nextLink, string id, CancellationToken cancellationToken = default) + { + if (nextLink == null) + { + throw new ArgumentNullException(nameof(nextLink)); + } + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateListIncomingRelationshipsNextPageRequest(nextLink, id); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + IncomingRelationshipCollection value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = IncomingRelationshipCollection.DeserializeIncomingRelationshipCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/EventRoutesRestClient.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/EventRoutesRestClient.cs new file mode 100644 index 0000000000000..abb5d0777e430 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/EventRoutesRestClient.cs @@ -0,0 +1,454 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.DigitalTwins.Core.Models; + +namespace Azure.DigitalTwins.Core +{ + internal partial class EventRoutesRestClient + { + private Uri endpoint; + private string apiVersion; + private ClientDiagnostics _clientDiagnostics; + private HttpPipeline _pipeline; + + /// Initializes a new instance of EventRoutesRestClient. + /// The handler for diagnostic messaging in the client. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// server parameter. + /// Api Version. + /// This occurs when one of the required arguments is null. + public EventRoutesRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Uri endpoint = null, string apiVersion = "2020-05-31-preview") + { + endpoint ??= new Uri("https://digitaltwins-name.digitaltwins.azure.net"); + if (apiVersion == null) + { + throw new ArgumentNullException(nameof(apiVersion)); + } + + this.endpoint = endpoint; + this.apiVersion = apiVersion; + _clientDiagnostics = clientDiagnostics; + _pipeline = pipeline; + } + + internal HttpMessage CreateListRequest(EventRoutesListOptions eventRoutesListOptions) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/eventroutes", false); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + if (eventRoutesListOptions?.MaxItemCount != null) + { + request.Headers.Add("x-ms-max-item-count", eventRoutesListOptions.MaxItemCount.Value); + } + return message; + } + + /// + /// Retrieves all event routes. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// Parameter group. + /// The cancellation token to use. + public async Task> ListAsync(EventRoutesListOptions eventRoutesListOptions = null, CancellationToken cancellationToken = default) + { + using var message = CreateListRequest(eventRoutesListOptions); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + EventRouteCollection value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = EventRouteCollection.DeserializeEventRouteCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves all event routes. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// Parameter group. + /// The cancellation token to use. + public Response List(EventRoutesListOptions eventRoutesListOptions = null, CancellationToken cancellationToken = default) + { + using var message = CreateListRequest(eventRoutesListOptions); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + EventRouteCollection value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = EventRouteCollection.DeserializeEventRouteCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateGetByIdRequest(string id) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/eventroutes/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + return message; + } + + /// + /// Retrieves an event route. + /// Status codes: + /// 200 (OK): Success. + /// 404 (Not Found): There is no event route with the provided id. + /// + /// The id for an event route. The id is unique within event routes and case sensitive. + /// The cancellation token to use. + public async Task> GetByIdAsync(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateGetByIdRequest(id); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + EventRoute value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = EventRoute.DeserializeEventRoute(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves an event route. + /// Status codes: + /// 200 (OK): Success. + /// 404 (Not Found): There is no event route with the provided id. + /// + /// The id for an event route. The id is unique within event routes and case sensitive. + /// The cancellation token to use. + public Response GetById(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateGetByIdRequest(id); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + EventRoute value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = EventRoute.DeserializeEventRoute(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateAddRequest(string id, EventRoute eventRoute) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Put; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/eventroutes/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json"); + if (eventRoute != null) + { + using var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(eventRoute); + request.Content = content; + } + return message; + } + + /// + /// Adds or replaces an event route. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The id for an event route. The id is unique within event routes and case sensitive. + /// The event route data. + /// The cancellation token to use. + public async Task AddAsync(string id, EventRoute eventRoute = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateAddRequest(id, eventRoute); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Adds or replaces an event route. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The id for an event route. The id is unique within event routes and case sensitive. + /// The event route data. + /// The cancellation token to use. + public Response Add(string id, EventRoute eventRoute = null, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateAddRequest(id, eventRoute); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateDeleteRequest(string id) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Delete; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/eventroutes/", false); + uri.AppendPath(id, true); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + return message; + } + + /// + /// Deletes an event route. + /// Status codes: + /// 200 (OK): Success. + /// 404 (Not Found): There is no event route with the provided id. + /// + /// The id for an event route. The id is unique within event routes and case sensitive. + /// The cancellation token to use. + public async Task DeleteAsync(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateDeleteRequest(id); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Deletes an event route. + /// Status codes: + /// 200 (OK): Success. + /// 404 (Not Found): There is no event route with the provided id. + /// + /// The id for an event route. The id is unique within event routes and case sensitive. + /// The cancellation token to use. + public Response Delete(string id, CancellationToken cancellationToken = default) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + using var message = CreateDeleteRequest(id); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 204: + return message.Response; + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + + internal HttpMessage CreateListNextPageRequest(string nextLink, EventRoutesListOptions eventRoutesListOptions) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Get; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendRawNextLink(nextLink, false); + request.Uri = uri; + if (eventRoutesListOptions?.MaxItemCount != null) + { + request.Headers.Add("x-ms-max-item-count", eventRoutesListOptions.MaxItemCount.Value); + } + return message; + } + + /// + /// Retrieves all event routes. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The URL to the next page of results. + /// Parameter group. + /// The cancellation token to use. + public async Task> ListNextPageAsync(string nextLink, EventRoutesListOptions eventRoutesListOptions = null, CancellationToken cancellationToken = default) + { + if (nextLink == null) + { + throw new ArgumentNullException(nameof(nextLink)); + } + + using var message = CreateListNextPageRequest(nextLink, eventRoutesListOptions); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + switch (message.Response.Status) + { + case 200: + { + EventRouteCollection value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = EventRouteCollection.DeserializeEventRouteCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Retrieves all event routes. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The URL to the next page of results. + /// Parameter group. + /// The cancellation token to use. + public Response ListNextPage(string nextLink, EventRoutesListOptions eventRoutesListOptions = null, CancellationToken cancellationToken = default) + { + if (nextLink == null) + { + throw new ArgumentNullException(nameof(nextLink)); + } + + using var message = CreateListNextPageRequest(nextLink, eventRoutesListOptions); + _pipeline.Send(message, cancellationToken); + switch (message.Response.Status) + { + case 200: + { + EventRouteCollection value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = EventRouteCollection.DeserializeEventRouteCollection(document.RootElement); + } + return Response.FromValue(value, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/Error.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/Error.Serialization.cs new file mode 100644 index 0000000000000..ac70b94e1e8b9 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/Error.Serialization.cs @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class Error + { + internal static Error DeserializeError(JsonElement element) + { + string code = default; + string message = default; + IReadOnlyList details = default; + InnerError innererror = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("code")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + code = property.Value.GetString(); + continue; + } + if (property.NameEquals("message")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + message = property.Value.GetString(); + continue; + } + if (property.NameEquals("details")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + if (item.ValueKind == JsonValueKind.Null) + { + array.Add(null); + } + else + { + array.Add(DeserializeError(item)); + } + } + details = array; + continue; + } + if (property.NameEquals("innererror")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + innererror = InnerError.DeserializeInnerError(property.Value); + continue; + } + } + return new Error(code, message, details, innererror); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/Error.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/Error.cs new file mode 100644 index 0000000000000..e33c997cd8bd3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/Error.cs @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + /// Error definition. + internal partial class Error + { + /// Initializes a new instance of Error. + internal Error() + { + } + + /// Initializes a new instance of Error. + /// Service specific error code which serves as the substatus for the HTTP error code. + /// A human-readable representation of the error. + /// Internal error details. + /// An object containing more specific information than the current object about the error. + internal Error(string code, string message, IReadOnlyList details, InnerError innererror) + { + Code = code; + Message = message; + Details = details; + Innererror = innererror; + } + + /// Service specific error code which serves as the substatus for the HTTP error code. + public string Code { get; } + /// A human-readable representation of the error. + public string Message { get; } + /// Internal error details. + public IReadOnlyList Details { get; } + /// An object containing more specific information than the current object about the error. + public InnerError Innererror { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ErrorResponse.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ErrorResponse.Serialization.cs new file mode 100644 index 0000000000000..f930ce12d8a9e --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ErrorResponse.Serialization.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class ErrorResponse + { + internal static ErrorResponse DeserializeErrorResponse(JsonElement element) + { + Error error = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("error")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + error = Error.DeserializeError(property.Value); + continue; + } + } + return new ErrorResponse(error); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ErrorResponse.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ErrorResponse.cs new file mode 100644 index 0000000000000..67469a89e4357 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ErrorResponse.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +namespace Azure.DigitalTwins.Core.Models +{ + /// Error response. + internal partial class ErrorResponse + { + /// Initializes a new instance of ErrorResponse. + internal ErrorResponse() + { + } + + /// Initializes a new instance of ErrorResponse. + /// The error details. + internal ErrorResponse(Error error) + { + Error = error; + } + + /// The error details. + public Error Error { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoute.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoute.Serialization.cs new file mode 100644 index 0000000000000..d18888d7478da --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoute.Serialization.cs @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + public partial class EventRoute : IUtf8JsonSerializable + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) + { + writer.WriteStartObject(); + if (Id != null) + { + writer.WritePropertyName("id"); + writer.WriteStringValue(Id); + } + writer.WritePropertyName("endpointName"); + writer.WriteStringValue(EndpointName); + if (Filter != null) + { + writer.WritePropertyName("filter"); + writer.WriteStringValue(Filter); + } + writer.WriteEndObject(); + } + + internal static EventRoute DeserializeEventRoute(JsonElement element) + { + string id = default; + string endpointName = default; + string filter = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("id")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + id = property.Value.GetString(); + continue; + } + if (property.NameEquals("endpointName")) + { + endpointName = property.Value.GetString(); + continue; + } + if (property.NameEquals("filter")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + filter = property.Value.GetString(); + continue; + } + } + return new EventRoute(id, endpointName, filter); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoute.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoute.cs new file mode 100644 index 0000000000000..9f3c196c09d0f --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoute.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; + +namespace Azure.DigitalTwins.Core.Models +{ + /// A route which directs notification and telemetry events to an endpoint. Endpoints are a destination outside of Azure Digital Twins such as an EventHub. + public partial class EventRoute + { + /// Initializes a new instance of EventRoute. + /// The name of the endpoint this event route is bound to. + public EventRoute(string endpointName) + { + if (endpointName == null) + { + throw new ArgumentNullException(nameof(endpointName)); + } + + EndpointName = endpointName; + } + + /// Initializes a new instance of EventRoute. + /// The id of the event route. + /// The name of the endpoint this event route is bound to. + /// An expression which describes the events which are routed to the endpoint. + internal EventRoute(string id, string endpointName, string filter) + { + Id = id; + EndpointName = endpointName; + Filter = filter; + } + + /// The id of the event route. + public string Id { get; } + /// The name of the endpoint this event route is bound to. + public string EndpointName { get; set; } + /// An expression which describes the events which are routed to the endpoint. + public string Filter { get; set; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRouteCollection.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRouteCollection.Serialization.cs new file mode 100644 index 0000000000000..d38d7503c482e --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRouteCollection.Serialization.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class EventRouteCollection + { + internal static EventRouteCollection DeserializeEventRouteCollection(JsonElement element) + { + IReadOnlyList value = default; + string nextLink = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("value")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + if (item.ValueKind == JsonValueKind.Null) + { + array.Add(null); + } + else + { + array.Add(EventRoute.DeserializeEventRoute(item)); + } + } + value = array; + continue; + } + if (property.NameEquals("nextLink")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + nextLink = property.Value.GetString(); + continue; + } + } + return new EventRouteCollection(value, nextLink); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRouteCollection.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRouteCollection.cs new file mode 100644 index 0000000000000..88967a7934cb1 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRouteCollection.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + /// A collection of EventRoute objects. + internal partial class EventRouteCollection + { + /// Initializes a new instance of EventRouteCollection. + internal EventRouteCollection() + { + } + + /// Initializes a new instance of EventRouteCollection. + /// The EventRoute objects. + /// A URI to retrieve the next page of results. + internal EventRouteCollection(IReadOnlyList value, string nextLink) + { + Value = value; + NextLink = nextLink; + } + + /// The EventRoute objects. + public IReadOnlyList Value { get; } + /// A URI to retrieve the next page of results. + public string NextLink { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoutesListOptions.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoutesListOptions.cs new file mode 100644 index 0000000000000..0b3037cd0379b --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/EventRoutesListOptions.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +namespace Azure.DigitalTwins.Core.Models +{ + /// Parameter group. + public partial class EventRoutesListOptions + { + /// Initializes a new instance of EventRoutesListOptions. + public EventRoutesListOptions() + { + } + + /// Initializes a new instance of EventRoutesListOptions. + /// The maximum number of items to retrieve per request. The server may choose to return less than the requested max. + internal EventRoutesListOptions(int? maxItemCount) + { + MaxItemCount = maxItemCount; + } + + /// The maximum number of items to retrieve per request. The server may choose to return less than the requested max. + public int? MaxItemCount { get; set; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/GetModelsOptions.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/GetModelsOptions.cs new file mode 100644 index 0000000000000..576f05440fe23 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/GetModelsOptions.cs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +namespace Azure.DigitalTwins.Core.Models +{ + /// Parameter group. + public partial class GetModelsOptions + { + /// Initializes a new instance of GetModelsOptions. + public GetModelsOptions() + { + } + + /// Initializes a new instance of GetModelsOptions. + /// The maximum number of items to retrieve per request. The server may choose to return less than the requested max. + internal GetModelsOptions(int? maxItemCount) + { + MaxItemCount = maxItemCount; + } + + /// The maximum number of items to retrieve per request. The server may choose to return less than the requested max. + public int? MaxItemCount { get; set; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationship.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationship.Serialization.cs new file mode 100644 index 0000000000000..aac73bb2fee93 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationship.Serialization.cs @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + public partial class IncomingRelationship + { + internal static IncomingRelationship DeserializeIncomingRelationship(JsonElement element) + { + string relationshipId = default; + string sourceId = default; + string relationshipName = default; + string relationshipLink = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("$relationshipId")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + relationshipId = property.Value.GetString(); + continue; + } + if (property.NameEquals("$sourceId")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + sourceId = property.Value.GetString(); + continue; + } + if (property.NameEquals("$relationshipName")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + relationshipName = property.Value.GetString(); + continue; + } + if (property.NameEquals("$relationshipLink")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + relationshipLink = property.Value.GetString(); + continue; + } + } + return new IncomingRelationship(relationshipId, sourceId, relationshipName, relationshipLink); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationship.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationship.cs new file mode 100644 index 0000000000000..338303f46f10a --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationship.cs @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +namespace Azure.DigitalTwins.Core.Models +{ + /// An incoming relationship. + public partial class IncomingRelationship + { + /// Initializes a new instance of IncomingRelationship. + internal IncomingRelationship() + { + } + + /// Initializes a new instance of IncomingRelationship. + /// A user-provided string representing the id of this relationship, unique in the context of the source digital twin, i.e. sourceId + relationshipId is unique in the context of the service. + /// The id of the source digital twin. + /// The name of the relationship. + /// Link to the relationship, to be used for deletion. + internal IncomingRelationship(string relationshipId, string sourceId, string relationshipName, string relationshipLink) + { + RelationshipId = relationshipId; + SourceId = sourceId; + RelationshipName = relationshipName; + RelationshipLink = relationshipLink; + } + + /// A user-provided string representing the id of this relationship, unique in the context of the source digital twin, i.e. sourceId + relationshipId is unique in the context of the service. + public string RelationshipId { get; } + /// The id of the source digital twin. + public string SourceId { get; } + /// The name of the relationship. + public string RelationshipName { get; } + /// Link to the relationship, to be used for deletion. + public string RelationshipLink { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationshipCollection.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationshipCollection.Serialization.cs new file mode 100644 index 0000000000000..c859de4729da8 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationshipCollection.Serialization.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class IncomingRelationshipCollection + { + internal static IncomingRelationshipCollection DeserializeIncomingRelationshipCollection(JsonElement element) + { + IReadOnlyList value = default; + string nextLink = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("value")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + if (item.ValueKind == JsonValueKind.Null) + { + array.Add(null); + } + else + { + array.Add(IncomingRelationship.DeserializeIncomingRelationship(item)); + } + } + value = array; + continue; + } + if (property.NameEquals("nextLink")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + nextLink = property.Value.GetString(); + continue; + } + } + return new IncomingRelationshipCollection(value, nextLink); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationshipCollection.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationshipCollection.cs new file mode 100644 index 0000000000000..592d619782d80 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/IncomingRelationshipCollection.cs @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + /// A collection of incoming relationships which relate digital twins together. + internal partial class IncomingRelationshipCollection + { + /// Initializes a new instance of IncomingRelationshipCollection. + internal IncomingRelationshipCollection() + { + } + + /// Initializes a new instance of IncomingRelationshipCollection. + /// . + /// A URI to retrieve the next page of objects. + internal IncomingRelationshipCollection(IReadOnlyList value, string nextLink) + { + Value = value; + NextLink = nextLink; + } + + public IReadOnlyList Value { get; } + /// A URI to retrieve the next page of objects. + public string NextLink { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/InnerError.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/InnerError.Serialization.cs new file mode 100644 index 0000000000000..715e6f5a8ad97 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/InnerError.Serialization.cs @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class InnerError + { + internal static InnerError DeserializeInnerError(JsonElement element) + { + string code = default; + InnerError innererror = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("code")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + code = property.Value.GetString(); + continue; + } + if (property.NameEquals("innererror")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + innererror = DeserializeInnerError(property.Value); + continue; + } + } + return new InnerError(code, innererror); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/InnerError.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/InnerError.cs new file mode 100644 index 0000000000000..3184345a45db3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/InnerError.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +namespace Azure.DigitalTwins.Core.Models +{ + /// A more specific error description than was provided by the containing error. + internal partial class InnerError + { + /// Initializes a new instance of InnerError. + internal InnerError() + { + } + + /// Initializes a new instance of InnerError. + /// A more specific error code than was provided by the containing error. + /// An object containing more specific information than the current object about the error. + internal InnerError(string code, InnerError innererror) + { + Code = code; + Innererror = innererror; + } + + /// A more specific error code than was provided by the containing error. + public string Code { get; } + /// An object containing more specific information than the current object about the error. + public InnerError Innererror { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ModelData.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ModelData.Serialization.cs new file mode 100644 index 0000000000000..2e2ac43391bac --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ModelData.Serialization.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + public partial class ModelData + { + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ModelData.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ModelData.cs new file mode 100644 index 0000000000000..9cdafe0425379 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/ModelData.cs @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + /// A model definition and metadata for that model. + public partial class ModelData + { + /// The id of the model as specified in the model definition. + public string Id { get; } + /// The time the model was uploaded to the service. + public DateTimeOffset? UploadTime { get; } + /// Indicates if the model is decommissioned. Decommissioned models cannot be referenced by newly created digital twins. + public bool? Decommissioned { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/PagedModelDataCollection.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/PagedModelDataCollection.Serialization.cs new file mode 100644 index 0000000000000..4e4a03143cd19 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/PagedModelDataCollection.Serialization.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class PagedModelDataCollection + { + internal static PagedModelDataCollection DeserializePagedModelDataCollection(JsonElement element) + { + IReadOnlyList value = default; + string nextLink = default; + foreach (var property in element.EnumerateObject()) + { + if (property.NameEquals("value")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + List array = new List(); + foreach (var item in property.Value.EnumerateArray()) + { + if (item.ValueKind == JsonValueKind.Null) + { + array.Add(null); + } + else + { + array.Add(ModelData.DeserializeModelData(item)); + } + } + value = array; + continue; + } + if (property.NameEquals("nextLink")) + { + if (property.Value.ValueKind == JsonValueKind.Null) + { + continue; + } + nextLink = property.Value.GetString(); + continue; + } + } + return new PagedModelDataCollection(value, nextLink); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/PagedModelDataCollection.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/PagedModelDataCollection.cs new file mode 100644 index 0000000000000..0b6b818447e61 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/PagedModelDataCollection.cs @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + /// A collection of ModelData objects. + internal partial class PagedModelDataCollection + { + /// Initializes a new instance of PagedModelDataCollection. + internal PagedModelDataCollection() + { + } + + /// Initializes a new instance of PagedModelDataCollection. + /// The ModelData objects. + /// A URI to retrieve the next page of objects. + internal PagedModelDataCollection(IReadOnlyList value, string nextLink) + { + Value = value; + NextLink = nextLink; + } + + /// The ModelData objects. + public IReadOnlyList Value { get; } + /// A URI to retrieve the next page of objects. + public string NextLink { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QueryResult.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QueryResult.Serialization.cs new file mode 100644 index 0000000000000..6b81451cec5a3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QueryResult.Serialization.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class QueryResult + { + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QueryResult.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QueryResult.cs new file mode 100644 index 0000000000000..c4adb7a2fe2fe --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QueryResult.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + /// The results of a query operation and an optional continuation token. + internal partial class QueryResult + { + /// Initializes a new instance of QueryResult. + internal QueryResult() + { + } + + /// Initializes a new instance of QueryResult. + /// The query results. + /// A token which can be used to construct a new QuerySpecification to retrieve the next set of results. + internal QueryResult(IReadOnlyList items, string continuationToken) + { + Items = items; + ContinuationToken = continuationToken; + } + /// A token which can be used to construct a new QuerySpecification to retrieve the next set of results. + public string ContinuationToken { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QuerySpecification.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QuerySpecification.Serialization.cs new file mode 100644 index 0000000000000..e2be6af84d785 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QuerySpecification.Serialization.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class QuerySpecification : IUtf8JsonSerializable + { + void IUtf8JsonSerializable.Write(Utf8JsonWriter writer) + { + writer.WriteStartObject(); + if (Query != null) + { + writer.WritePropertyName("query"); + writer.WriteStringValue(Query); + } + if (ContinuationToken != null) + { + writer.WritePropertyName("continuationToken"); + writer.WriteStringValue(ContinuationToken); + } + writer.WriteEndObject(); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QuerySpecification.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QuerySpecification.cs new file mode 100644 index 0000000000000..0d3a0ade8ae31 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/QuerySpecification.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +namespace Azure.DigitalTwins.Core.Models +{ + /// A query specification containing either a query statement or a continuation token from a previous query result. + internal partial class QuerySpecification + { + /// Initializes a new instance of QuerySpecification. + public QuerySpecification() + { + } + + /// Initializes a new instance of QuerySpecification. + /// The query to execute. This value is ignored if a continuation token is provided. + /// A token which is used to retrieve the next set of results from a previous query. + internal QuerySpecification(string query, string continuationToken) + { + Query = query; + ContinuationToken = continuationToken; + } + + /// The query to execute. This value is ignored if a continuation token is provided. + public string Query { get; set; } + /// A token which is used to retrieve the next set of results from a previous query. + public string ContinuationToken { get; set; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/RelationshipCollection.Serialization.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/RelationshipCollection.Serialization.cs new file mode 100644 index 0000000000000..fd683e9f21c4d --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/RelationshipCollection.Serialization.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; +using System.Text.Json; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Models +{ + internal partial class RelationshipCollection + { + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/RelationshipCollection.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/RelationshipCollection.cs new file mode 100644 index 0000000000000..7879051b519d8 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/Models/RelationshipCollection.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + /// A collection of relationships which relate digital twins together. + internal partial class RelationshipCollection + { + /// Initializes a new instance of RelationshipCollection. + internal RelationshipCollection() + { + } + + /// Initializes a new instance of RelationshipCollection. + /// The relationship objects. + /// A URI to retrieve the next page of objects. + internal RelationshipCollection(IReadOnlyList value, string nextLink) + { + Value = value; + NextLink = nextLink; + } + /// A URI to retrieve the next page of objects. + public string NextLink { get; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/QueryQueryTwinsHeaders.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/QueryQueryTwinsHeaders.cs new file mode 100644 index 0000000000000..e8286fe588ba7 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/QueryQueryTwinsHeaders.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using Azure; +using Azure.Core; + +namespace Azure.DigitalTwins.Core +{ + internal class QueryQueryTwinsHeaders + { + private readonly Response _response; + public QueryQueryTwinsHeaders(Response response) + { + _response = response; + } + public float? QueryCharge => _response.Headers.TryGetValue("query-charge", out float? value) ? value : null; + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/QueryRestClient.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/QueryRestClient.cs new file mode 100644 index 0000000000000..04a41f0ed5aee --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/QueryRestClient.cs @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +// + +#nullable disable + +using System; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; +using Azure.Core.Pipeline; +using Azure.DigitalTwins.Core.Models; + +namespace Azure.DigitalTwins.Core +{ + internal partial class QueryRestClient + { + private Uri endpoint; + private string apiVersion; + private ClientDiagnostics _clientDiagnostics; + private HttpPipeline _pipeline; + + /// Initializes a new instance of QueryRestClient. + /// The handler for diagnostic messaging in the client. + /// The HTTP pipeline for sending and receiving REST requests and responses. + /// server parameter. + /// Api Version. + /// This occurs when one of the required arguments is null. + public QueryRestClient(ClientDiagnostics clientDiagnostics, HttpPipeline pipeline, Uri endpoint = null, string apiVersion = "2020-05-31-preview") + { + endpoint ??= new Uri("https://digitaltwins-name.digitaltwins.azure.net"); + if (apiVersion == null) + { + throw new ArgumentNullException(nameof(apiVersion)); + } + + this.endpoint = endpoint; + this.apiVersion = apiVersion; + _clientDiagnostics = clientDiagnostics; + _pipeline = pipeline; + } + + internal HttpMessage CreateQueryTwinsRequest(QuerySpecification querySpecification) + { + var message = _pipeline.CreateMessage(); + var request = message.Request; + request.Method = RequestMethod.Post; + var uri = new RawRequestUriBuilder(); + uri.Reset(endpoint); + uri.AppendPath("/query", false); + uri.AppendQuery("api-version", apiVersion, true); + request.Uri = uri; + request.Headers.Add("Content-Type", "application/json"); + using var content = new Utf8JsonRequestContent(); + content.JsonWriter.WriteObjectValue(querySpecification); + request.Content = content; + return message; + } + + /// + /// Executes a query that allows traversing relationships and filtering by property values. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The query specification to execute. + /// The cancellation token to use. + public async Task> QueryTwinsAsync(QuerySpecification querySpecification, CancellationToken cancellationToken = default) + { + if (querySpecification == null) + { + throw new ArgumentNullException(nameof(querySpecification)); + } + + using var message = CreateQueryTwinsRequest(querySpecification); + await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false); + var headers = new QueryQueryTwinsHeaders(message.Response); + switch (message.Response.Status) + { + case 200: + { + QueryResult value = default; + using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = QueryResult.DeserializeQueryResult(document.RootElement); + } + return ResponseWithHeaders.FromValue(value, headers, message.Response); + } + default: + throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false); + } + } + + /// + /// Executes a query that allows traversing relationships and filtering by property values. + /// Status codes: + /// 200 (OK): Success. + /// 400 (Bad Request): The request is invalid. + /// + /// The query specification to execute. + /// The cancellation token to use. + public ResponseWithHeaders QueryTwins(QuerySpecification querySpecification, CancellationToken cancellationToken = default) + { + if (querySpecification == null) + { + throw new ArgumentNullException(nameof(querySpecification)); + } + + using var message = CreateQueryTwinsRequest(querySpecification); + _pipeline.Send(message, cancellationToken); + var headers = new QueryQueryTwinsHeaders(message.Response); + switch (message.Response.Status) + { + case 200: + { + QueryResult value = default; + using var document = JsonDocument.Parse(message.Response.ContentStream); + if (document.RootElement.ValueKind == JsonValueKind.Null) + { + value = null; + } + else + { + value = QueryResult.DeserializeQueryResult(document.RootElement); + } + return ResponseWithHeaders.FromValue(value, headers, message.Response); + } + default: + throw _clientDiagnostics.CreateRequestFailedException(message.Response); + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Models/ModelsConstants.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Models/ModelsConstants.cs new file mode 100644 index 0000000000000..478a46b1def5a --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Models/ModelsConstants.cs @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; + +namespace Azure.DigitalTwins.Core.Models +{ + /// + /// Constants useful for use with the digital twins client. + /// + internal static class ModelsConstants + { + /// + /// The application/json-patch+json operation to decommission a model. + /// + internal static readonly IEnumerable DecommissionModelOperationList = new[] { @"{ ""op"": ""replace"", ""path"": ""/decommissioned"", ""value"": true }" }; + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Models/TelemetryOptions.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Models/TelemetryOptions.cs new file mode 100644 index 0000000000000..9f5fed471bbe1 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Models/TelemetryOptions.cs @@ -0,0 +1,24 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; + +namespace Azure.DigitalTwins.Core.Models +{ + /// + /// The additional information to be used when processing a telemetry request. + /// + public class TelemetryOptions + { + /// + /// A unique message identifier (within the scope of the digital twin id) that is commonly used for de-duplicating messages. + /// Defaults to a random guid. + /// + public string MessageId { get; set; } = Guid.NewGuid().ToString(); + + /// + /// An RFC 3339 timestamp that identifies the time the telemetry was measured. It defaults to the current date/time UTC. + /// + public DateTimeOffset TimeStamp { get; set; } = DateTimeOffset.UtcNow; + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Properties/AssemblyInfo.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000..298d86178008d --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Properties/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Azure.DigitalTwins.Core.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100d15ddcb29688295338af4b7686603fe614abd555e09efba8fb88ee09e1f7b1ccaeed2e8f823fa9eef3fdd60217fc012ea67d2479751a0b8c087a4185541b851bd8b16f8d91b840e51b1cb0ba6fe647997e57429265e85ef62d565db50a69ae1647d54d7bd855e4db3d8a91510e5bcbd0edfbbecaa20a7bd9ae74593daa7b11b4")] diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Queries/QueryChargeHelper.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Queries/QueryChargeHelper.cs new file mode 100644 index 0000000000000..3981b4d1bf1c3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Queries/QueryChargeHelper.cs @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Queries +{ + /// + /// A helper class for working with the query APIs for digital twins. + /// + public static class QueryChargeHelper + { + /// + /// A constant that is used to as the query-charge header field in the query page response. + /// + private const string QueryChargeHeader = "query-charge"; + + /// + /// Extract the query-charge field from a page header. + /// + /// The page that contains the query-charge header. + /// The query charge extracted from the header. + /// True if the header contains a query-charge field, otherwise false. + /// + /// // This code snippet demonstrates how you could extract the query charges incurred when calling + /// // the query API. It iterates over the response pages first to access to the query-charge header, + /// // and then the digital twin results within each page. + /// + /// AsyncPageable<string> asyncPageableResponseWithCharge = DigitalTwinsClient.QueryAsync("SELECT * FROM digitaltwins"); + /// int pageNum = 0; + /// + /// // The "await" keyword here is required as a call is made when fetching a new page. + /// await foreach (Page<string> page in asyncPageableResponseWithCharge.AsPages()) + /// { + /// Console.WriteLine($"Page {++pageNum} results:"); + /// + /// // Extract the query-charge header from the page + /// if (QueryChargeHelper.TryGetQueryCharge(page, out float queryCharge)) + /// { + /// Console.WriteLine($"Query charge was: {queryCharge}"); + /// } + /// + /// // Iterate over the twin instances. + /// // The "await" keyword is not required here as the paged response is local. + /// foreach (string response in page.Values) + /// { + /// BasicDigitalTwin twin = JsonSerializer.Deserialize<BasicDigitalTwin>(response); + /// Console.WriteLine($"Found digital twin: {twin.Id}"); + /// } + /// } + /// + public static bool TryGetQueryCharge(Page page, out float queryCharge) + { + Argument.AssertNotNull(page, nameof(page)); + + if (!page.GetRawResponse().Headers.TryGetValue(QueryChargeHeader, out string queryChargeHeaderValue)) + { + queryCharge = 0f; + return false; + } + + return float.TryParse(queryChargeHeaderValue, out queryCharge); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/RequestOptions.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/RequestOptions.cs new file mode 100644 index 0000000000000..93ad0b04fee33 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/RequestOptions.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Azure.DigitalTwins.Core +{ + /// + /// General request options that are applicable, but optional, for many APIs. + /// + public class RequestOptions + { + /// + /// A string representing a weak ETag for the entity that this request performs an operation against, as per RFC7232. The request's operation is performed + /// only if this ETag matches the value maintained by the server, indicating that the entity has not been modified since it was last retrieved. + /// To force the operation to execute only if the entity exists, set the ETag to the wildcard character '*'. To force the operation to execute unconditionally, leave this value null. + /// + public string IfMatchEtag { get; set; } = null; + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicDigitalTwin.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicDigitalTwin.cs new file mode 100644 index 0000000000000..e6150410131b3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicDigitalTwin.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Azure.DigitalTwins.Core.Serialization +{ + /// + /// An optional, helper class for deserializing a digital twin. + /// + public class BasicDigitalTwin + { + /// + /// The unique Id of the digital twin in a digital twins instance. This field is present on every digital twin. + /// + [JsonPropertyName("$dtId")] + public string Id { get; set; } + + /// + /// Information about the model a digital twin conforms to. This field is present on every digital twin. + /// + [JsonPropertyName("$metadata")] + public DigitalTwinMetadata Metadata { get; set; } + + /// + /// Additional properties of the digital twin. This field will contain any properties of the digital twin that are not already defined by the other strong types of this class. + /// + [JsonExtensionData] + public IDictionary CustomProperties { get; set; } = new Dictionary(); + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicRelationship.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicRelationship.cs new file mode 100644 index 0000000000000..7bfa3226396fe --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/BasicRelationship.cs @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Azure.DigitalTwins.Core.Serialization +{ + /// + /// Although relationships have a user-defined schema, these properties should exist on every instance. This is + /// useful to use as a base class to ensure your custom relationships have the necessary properties. + /// + public class BasicRelationship + { + /// + /// The unique Id of the relationship. This field is present on every relationship. + /// + [JsonPropertyName("$relationshipId")] + public string Id { get; set; } + + /// + /// The unique Id of the target digital twin. This field is present on every relationship. + /// + [JsonPropertyName("$targetId")] + public string TargetId { get; set; } + + /// + /// The unique Id of the source digital twin. This field is present on every relationship. + /// + [JsonPropertyName("$sourceId")] + public string SourceId { get; set; } + + /// + /// The name of the relationship, which defines the type of link (e.g. Contains). This field is present on every relationship. + /// + [JsonPropertyName("$relationshipName")] + public string Name { get; set; } + + /// + /// Additional properties defined in the model. This field will contain any properties of the relationship that are not already defined by the other strong types of this class. + /// + [JsonExtensionData] + public IDictionary CustomProperties { get; set; } = new Dictionary(); + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/DigitalTwinMetadata.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/DigitalTwinMetadata.cs new file mode 100644 index 0000000000000..1a7464e4f7445 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/DigitalTwinMetadata.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Azure.DigitalTwins.Core.Serialization +{ + /// + /// An optional, helper class for deserializing a digital twin. + /// The $metadata class on a . + /// + public class DigitalTwinMetadata + { + /// + /// The Id of the model that this digital twin is modeled by. + /// + [JsonPropertyName("$model")] + public string ModelId { get; set; } + + /// + /// Additional, model-defined properties. + /// + [JsonExtensionData] + public IDictionary ModelProperties { get; set; } = new Dictionary(); + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/PayloadHelper.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/PayloadHelper.cs new file mode 100644 index 0000000000000..fa536a01a6258 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/PayloadHelper.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Serialization +{ + internal static class PayloadHelper + { + /// + /// Adds the specified unescaped json entities into a json array. + /// + /// The entities to add + /// A json array + internal static string BuildArrayPayload(IEnumerable entities) + { + Argument.AssertNotNull(entities, nameof(entities)); + return $"[{string.Join(",", entities)}]"; + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/UpdateOperationsUtility.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/UpdateOperationsUtility.cs new file mode 100644 index 0000000000000..2109fb680f5b3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/UpdateOperationsUtility.cs @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Collections.Generic; +using System.Text.Json; + +namespace Azure.DigitalTwins.Core.Serialization +{ + /// + /// A utility to create the application/json-patch+json operations payload required for update operations. + /// + public class UpdateOperationsUtility + { + private const string Op = "op"; + private const string Add = "add"; + private const string Replace = "replace"; + private const string Remove = "remove"; + private const string Path = "path"; + private const string Value = "value"; + + private readonly List> _ops = new List>(); + + /// + /// Include an add operation. + /// + /// The path to the property to be added. + /// The value to update to. + public void AppendAddOp(string path, object value) + { + var op = new Dictionary + { + { Op, Add }, + { Path, path }, + { Value, value }, + }; + _ops.Add(op); + } + + /// + /// Include a replace operation. + /// + /// The path to the property to be updated. + /// The value to update to. + public void AppendReplaceOp(string path, object value) + { + var op = new Dictionary + { + { Op, Replace }, + { Path, path }, + { Value, value }, + }; + _ops.Add(op); + } + + /// + /// Include a remove operation. + /// + /// The path to the property to be added. + public void AppendRemoveOp(string path) + { + var op = new Dictionary + { + { Op, Remove }, + { Path, path }, + }; + _ops.Add(op); + } + + /// + /// Serialize the constructed payload as json. + /// + /// A string of the json payload. + public string Serialize() + { + return JsonSerializer.Serialize(_ops); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/WritableProperty.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/WritableProperty.cs new file mode 100644 index 0000000000000..0aa16611b39a3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Serialization/WritableProperty.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Text.Json.Serialization; + +namespace Azure.DigitalTwins.Core.Serialization +{ + /// + /// An optional, helper class for deserializing a digital twin. + /// The ModelProperties dictionary on . + /// + /// + /// A writable property is one that the service may request a change for from the device. + /// + public class WritableProperty + { + /// + /// The desired value. + /// + [JsonPropertyName("desiredValue")] + public object DesiredValue { get; set; } + + /// + /// The version of the property with the specified desired value. + /// + [JsonPropertyName("desiredVersion")] + public int DesiredVersion { get; set; } + + /// + /// The version of the reported property value. + /// + [JsonPropertyName("ackVersion")] + public int AckVersion { get; set; } + + /// + /// The response code of the property update request, usually an HTTP Status Code (e.g. 200). + /// + [JsonPropertyName("ackCode")] + public int AckCode { get; set; } + + /// + /// The message response of the property update request. + /// + [JsonPropertyName("ackDescription")] + public string AckDescription { get; set; } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/autorest.md b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/autorest.md new file mode 100644 index 0000000000000..f779ef216dc12 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/autorest.md @@ -0,0 +1,10 @@ +# Azure.DigitalTwins.Core + +Run `generate.ps1` in this directory to generate the code. + +### AutoRest Configuration +> see https://aka.ms/autorest + +``` yaml +input-file: $(this-folder)/swagger/digitaltwins.json +``` diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/generate.ps1 b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/generate.ps1 new file mode 100644 index 0000000000000..e4a4b03e95aa9 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/generate.ps1 @@ -0,0 +1 @@ +dotnet msbuild /t:GenerateCode diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/digitaltwins.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/digitaltwins.json new file mode 100644 index 0000000000000..4ae53fdc16d4d --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/digitaltwins.json @@ -0,0 +1,1491 @@ +{ + "swagger": "2.0", + "info": { + "version": "2020-05-31-preview", + "title": "Azure Digital Twins API", + "description": "A service for managing and querying digital twins and digital twin models." + }, + "host": "digitaltwins-name.digitaltwins.azure.net", + "schemes": [ + "https" + ], + "produces": [ + "application/json" + ], + "consumes": [ + "application/json" + ], + "paths": { + "/models": { + "post": { + "tags": [ + "Models" + ], + "description": "Uploads one or more models. When any error occurs, no models are uploaded.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n409 (Conflict): One or more of the provided models already exist.", + "operationId": "DigitalTwinModels_Add", + "x-ms-examples": { + "ModelAdd": { + "$ref": "./examples/ModelAdd.json" + } + }, + "parameters": [ + { + "name": "models", + "in": "body", + "description": "An array of models to add.", + "required": false, + "schema": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "object" + } + } + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/NonPagedModelDataCollection" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "get": { + "tags": [ + "Models" + ], + "description": "Retrieves model metadata and, optionally, model definitions.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", + "x-ms-pageable": { + "nextLinkName": "nextLink" + }, + "operationId": "DigitalTwinModels_List", + "x-ms-examples": { + "ModelsGet": { + "$ref": "./examples/ModelsGet.json" + }, + "ModelsGetWithContextAndIncludeModelDefinition": { + "$ref": "./examples/ModelsGetWithDependenciesAndIncludeModelDefinition.json" + } + }, + "parameters": [ + { + "name": "dependenciesFor", + "in": "query", + "description": "The set of the models which will have their dependencies retrieved. If omitted, all models are retrieved.", + "required": false, + "type": "array", + "collectionFormat": "multi", + "items": { + "type": "string" + } + }, + { + "$ref": "#/parameters/includeModelDefinition" + }, + { + "$ref": "#/parameters/max-item-count" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/PagedModelDataCollection" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/models/{id}": { + "get": { + "tags": [ + "Models" + ], + "description": "Retrieves model metadata and optionally the model definition.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no model with the provided id.", + "operationId": "DigitalTwinModels_GetById", + "x-ms-examples": { + "ModelGetById": { + "$ref": "./examples/ModelGetById.json" + }, + "ModelGetByIdWithIncludeModelDefinition": { + "$ref": "./examples/ModelGetByIdWithIncludeModelDefinition.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/modelId" + }, + { + "$ref": "#/parameters/includeModelDefinition" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/ModelData" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "patch": { + "tags": [ + "Models" + ], + "description": "Updates the metadata for a model.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no model with the provided id.", + "operationId": "DigitalTwinModels_Update", + "consumes": [ + "application/json-patch+json" + ], + "x-ms-examples": { + "ModelUpdateDecommissioned": { + "$ref": "./examples/ModelUpdateDecommissioned.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/modelId" + }, + { + "name": "updateModel", + "description": "An update specification described by JSON Patch. Only the decommissioned property can be replaced.", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "object" + } + } + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "tags": [ + "Models" + ], + "operationId": "DigitalTwinModels_Delete", + "description": "Deletes a model. A model can only be deleted if no other models reference it.\nStatus codes:\n204 (No Content): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no model with the provided id.\n409 (Conflict): There are dependencies on the model that prevent it from being deleted.", + "x-ms-examples": { + "DeleteModel": { + "$ref": "./examples/DeleteModel.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/modelId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/query": { + "post": { + "tags": [ + "Query" + ], + "operationId": "Query_QueryTwins", + "description": "Executes a query that allows traversing relationships and filtering by property values.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", + "x-ms-examples": { + "QueryFirstPage": { + "$ref": "./examples/QueryFirstPage.json" + }, + "QueryNextPage": { + "$ref": "./examples/QueryNextPage.json" + }, + "QueryJoin": { + "$ref": "./examples/QueryJoin.json" + } + }, + "parameters": [ + { + "name": "querySpecification", + "in": "body", + "description": "The query specification to execute.", + "required": true, + "schema": { + "$ref": "#/definitions/QuerySpecification" + } + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/QueryResult" + }, + "headers": { + "query-charge": { + "description": "The query charge.", + "type": "number" + } + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_GetById", + "description": "Retrieves a digital twin.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-examples": { + "GetTwin": { + "$ref": "./examples/GetTwin.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + }, + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_Add", + "description": "Adds or replaces a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n412 (Precondition Failed): The model is decommissioned or the digital twin already exists (when using If-None-Match: *).", + "x-ms-examples": { + "PutTwinBasicExample": { + "$ref": "./examples/PutTwinBasicExample.json" + }, + "PutTwinAdvancedExample": { + "$ref": "./examples/PutTwinAdvancedExample.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "name": "twin", + "description": "The digital twin instance being added. If provided, the $dtId property is ignored.", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + }, + { + "$ref": "#/parameters/if-none-match-star" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + }, + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "202": { + "description": "Asynchronous Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_Delete", + "description": "Deletes a digital twin. All relationships referencing the digital twin must already be deleted.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-examples": { + "DeleteTwin": { + "$ref": "./examples/DeleteTwin.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "patch": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_Update", + "description": "Updates a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "consumes": [ + "application/json-patch+json" + ], + "x-ms-examples": { + "PatchTwinBasicExample": { + "$ref": "./examples/PatchTwinBasicExample.json" + }, + "PatchTwinAdvancedExample": { + "$ref": "./examples/PatchTwinAdvancedExample.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "name": "patchDocument", + "description": "An update specification described by JSON Patch. Updates to property values and $model elements may happen in the same request. Operations are limited to add, replace and remove.", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "object" + } + } + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success", + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "202": { + "description": "Asynchronous Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}/relationships/{relationshipId}": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_GetRelationshipById", + "description": "Retrieves a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is either no digital twin or relationship with the provided id.", + "x-ms-examples": { + "GetRelationshipById": { + "$ref": "./examples/GetRelationshipById.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/relationshipId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + }, + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_AddRelationship", + "description": "Adds a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin, target digital twin, or relationship with the provided id.\n409 (Conflict): A relationship with the provided id already exists.", + "x-ms-examples": { + "CreateRelationshipBasicExample": { + "$ref": "./examples/CreateRelationshipBasicExample.json" + }, + "CreateRelationshipAdvancedExample": { + "$ref": "./examples/CreateRelationshipAdvancedExample.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/relationshipId" + }, + { + "name": "relationship", + "in": "body", + "description": "The data for the relationship.", + "required": false, + "schema": { + "type": "object" + } + }, + { + "$ref": "#/parameters/if-none-match-star" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + }, + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_DeleteRelationship", + "description": "Deletes a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is either no digital twin or relationship with the provided id.", + "x-ms-examples": { + "DeleteRelationship": { + "$ref": "./examples/DeleteRelationship.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/relationshipId" + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "patch": { + "tags": [ + "Twins" + ], + "consumes": [ + "application/json-patch+json" + ], + "operationId": "DigitalTwins_UpdateRelationship", + "description": "Updates the properties on a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin or relationship with the provided id.", + "x-ms-examples": { + "PatchRelationshipBasicExample": { + "$ref": "./examples/PatchRelationshipBasicExample.json" + }, + "PatchRelationshipAdvancedExample": { + "$ref": "./examples/PatchRelationshipAdvancedExample.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/relationshipId" + }, + { + "name": "patchDocument", + "description": "JSON Patch description of the update to the relationship properties.", + "in": "body", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "object" + } + } + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success", + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}/relationships": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_ListRelationships", + "description": "Retrieves the relationships from a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-pageable": { + "nextLinkName": "nextLink" + }, + "x-ms-examples": { + "GetRelationship": { + "$ref": "./examples/GetRelationship.json" + }, + "GetRelationshipByName": { + "$ref": "./examples/GetRelationshipByRelationshipName.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "name": "relationshipName", + "description": "The name of the relationship.", + "in": "query", + "required": false, + "type": "string" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/RelationshipCollection" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}/incomingrelationships": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_ListIncomingRelationships", + "description": "Retrieves all incoming relationship for a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-pageable": { + "nextLinkName": "nextLink" + }, + "x-ms-examples": { + "GetIncomingRelationship": { + "$ref": "./examples/GetIncomingRelationship.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/IncomingRelationshipCollection" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}/telemetry": { + "post": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_SendTelemetry", + "description": "Sends telemetry on behalf of a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-examples": { + "SendTelemetry": { + "$ref": "./examples/SendTelemetry.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "name": "telemetry", + "in": "body", + "description": "The telemetry measurements to send from the digital twin.", + "required": true, + "schema": { + "type": "object" + } + }, + { + "name": "dt-id", + "in": "header", + "description": "A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages.", + "required": true, + "type": "string" + }, + { + "name": "dt-timestamp", + "in": "header", + "description": "An RFC 3339 timestamp that identifies the time the telemetry was measured.", + "required": false, + "type": "string" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}/components/{componentPath}/telemetry": { + "post": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_SendComponentTelemetry", + "description": "Sends telemetry on behalf of a component in a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin with the provided id or the component path is invalid.", + "x-ms-examples": { + "SendTelemetry": { + "$ref": "./examples/SendTelemetryFromComponent.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/componentPath" + }, + { + "name": "telemetry", + "in": "body", + "description": "The telemetry measurements to send from the digital twin's component.", + "required": true, + "schema": { + "type": "object" + } + }, + { + "name": "dt-id", + "in": "header", + "description": "A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages.", + "required": true, + "type": "string" + }, + { + "name": "dt-timestamp", + "in": "header", + "description": "An RFC 3339 timestamp that identifies the time the telemetry was measured.", + "required": false, + "type": "string" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}/components/{componentPath}": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_GetComponent", + "description": "Retrieves a component from a digital twin.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is either no digital twin with the provided id or the component path is invalid.", + "x-ms-examples": { + "GetComponent": { + "$ref": "./examples/GetComponent.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/componentPath" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + }, + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "patch": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_UpdateComponent", + "description": "Updates a component on a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin with the provided id or the component path is invalid.", + "x-ms-examples": { + "PatchComponentBasicExample": { + "$ref": "./examples/PatchComponentBasicExample.json" + }, + "PatchComponentAdvancedExample": { + "$ref": "./examples/PatchComponentAdvancedExample.json" + } + }, + "consumes": [ + "application/json-patch+json" + ], + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/componentPath" + }, + { + "name": "patchDocument", + "description": "An update specification described by JSON Patch. Updates to property values and $model elements may happen in the same request. Operations are limited to add, replace and remove.", + "in": "body", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "object" + } + } + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success", + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "202": { + "description": "Asynchronous Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/eventroutes": { + "get": { + "tags": [ + "EventRoutes" + ], + "description": "Retrieves all event routes.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", + "operationId": "EventRoutes_List", + "x-ms-examples": { + "EventRoutesList": { + "$ref": "./examples/EventRoutesList.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/max-item-count" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/EventRouteCollection" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/eventroutes/{id}": { + "get": { + "tags": [ + "EventRoutes" + ], + "description": "Retrieves an event route.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no event route with the provided id.", + "operationId": "EventRoutes_GetById", + "x-ms-examples": { + "EventRouteGet": { + "$ref": "./examples/EventRouteGet.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/eventRouteId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/EventRoute" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "put": { + "tags": [ + "EventRoutes" + ], + "description": "Adds or replaces an event route.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", + "operationId": "EventRoutes_Add", + "x-ms-examples": { + "EventRoutePut": { + "$ref": "./examples/EventRoutePut.json" + }, + "EventRouteWithFilter": { + "$ref": "./examples/EventRoutePutWithFilter.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/eventRouteId" + }, + { + "name": "eventRoute", + "description": "The event route data", + "in": "body", + "schema": { + "$ref": "#/definitions/EventRoute" + } + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "tags": [ + "EventRoutes" + ], + "description": "Deletes an event route.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no event route with the provided id.", + "operationId": "EventRoutes_Delete", + "x-ms-examples": { + "EventRouteDelete": { + "$ref": "./examples/EventRouteDelete.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/eventRouteId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + } + }, + "definitions": { + "EventRoute": { + "description": "A route which directs notification and telemetry events to an endpoint. Endpoints are a destination outside of Azure Digital Twins such as an EventHub.", + "type": "object", + "required": [ + "endpointName" + ], + "properties": { + "id": { + "description": "The id of the event route.", + "type": "string", + "readOnly": true + }, + "endpointName": { + "description": "The name of the endpoint this event route is bound to.", + "type": "string" + }, + "filter": { + "description": "An expression which describes the events which are routed to the endpoint.", + "type": "string" + } + } + }, + "EventRouteCollection": { + "description": "A collection of EventRoute objects.", + "type": "object", + "properties": { + "value": { + "description": "The EventRoute objects.", + "type": "array", + "items": { + "$ref": "#/definitions/EventRoute" + } + }, + "nextLink": { + "description": "A URI to retrieve the next page of results.", + "type": "string" + } + } + }, + "NonPagedModelDataCollection": { + "description": "A collection of ModelData objects.", + "type": "array", + "items": { + "$ref": "#/definitions/ModelData" + } + }, + "PagedModelDataCollection": { + "description": "A collection of ModelData objects.", + "type": "object", + "properties": { + "value": { + "description": "The ModelData objects.", + "type": "array", + "items": { + "$ref": "#/definitions/ModelData" + } + }, + "nextLink": { + "description": "A URI to retrieve the next page of objects.", + "type": "string" + } + } + }, + "ModelData": { + "description": "A model definition and metadata for that model.", + "required": [ + "id" + ], + "type": "object", + "properties": { + "displayName": { + "description": "A language map that contains the localized display names as specified in the model definition.", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "description": { + "description": "A language map that contains the localized descriptions as specified in the model definition.", + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "id": { + "description": "The id of the model as specified in the model definition.", + "type": "string" + }, + "uploadTime": { + "description": "The time the model was uploaded to the service.", + "format": "date-time", + "type": "string" + }, + "decommissioned": { + "description": "Indicates if the model is decommissioned. Decommissioned models cannot be referenced by newly created digital twins.", + "type": "boolean", + "default": false + }, + "model": { + "description": "The model definition.", + "type": "object" + } + } + }, + "RelationshipCollection": { + "description": "A collection of relationships which relate digital twins together.", + "type": "object", + "properties": { + "value": { + "description": "The relationship objects.", + "type": "array", + "items": { + "description": "The relationship JSON document.", + "type": "object" + } + }, + "nextLink": { + "description": "A URI to retrieve the next page of objects.", + "type": "string" + } + } + }, + "IncomingRelationshipCollection": { + "description": "A collection of incoming relationships which relate digital twins together.", + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/IncomingRelationship" + } + }, + "nextLink": { + "type": "string", + "description": "A URI to retrieve the next page of objects." + } + } + }, + "IncomingRelationship": { + "type": "object", + "description": "An incoming relationship.", + "properties": { + "$relationshipId": { + "type": "string", + "description": "A user-provided string representing the id of this relationship, unique in the context of the source digital twin, i.e. sourceId + relationshipId is unique in the context of the service." + }, + "$sourceId": { + "type": "string", + "description": "The id of the source digital twin." + }, + "$relationshipName": { + "type": "string", + "description": "The name of the relationship." + }, + "$relationshipLink": { + "type": "string", + "description": "Link to the relationship, to be used for deletion." + } + } + }, + "QuerySpecification": { + "description": "A query specification containing either a query statement or a continuation token from a previous query result.", + "type": "object", + "properties": { + "query": { + "description": "The query to execute. This value is ignored if a continuation token is provided.", + "type": "string" + }, + "continuationToken": { + "description": "A token which is used to retrieve the next set of results from a previous query.", + "type": "string" + } + } + }, + "QueryResult": { + "description": "The results of a query operation and an optional continuation token.", + "type": "object", + "properties": { + "items": { + "description": "The query results.", + "type": "array", + "items": { + "type": "object" + } + }, + "continuationToken": { + "description": "A token which can be used to construct a new QuerySpecification to retrieve the next set of results.", + "type": "string" + } + } + }, + "ErrorResponse": { + "description": "Error response.", + "properties": { + "error": { + "$ref": "#/definitions/Error", + "description": "The error details." + } + } + }, + "Error": { + "description": "Error definition.", + "properties": { + "code": { + "description": "Service specific error code which serves as the substatus for the HTTP error code.", + "type": "string", + "readOnly": true + }, + "message": { + "description": "A human-readable representation of the error.", + "type": "string", + "readOnly": true + }, + "details": { + "description": "Internal error details.", + "type": "array", + "items": { + "$ref": "#/definitions/Error" + }, + "readOnly": true + }, + "innererror": { + "description": "An object containing more specific information than the current object about the error.", + "$ref": "#/definitions/InnerError" + } + } + }, + "InnerError": { + "description": "A more specific error description than was provided by the containing error.", + "properties": { + "code": { + "description": "A more specific error code than was provided by the containing error.", + "type": "string" + }, + "innererror": { + "description": "An object containing more specific information than the current object about the error.", + "$ref": "#/definitions/InnerError" + } + } + } + }, + "securityDefinitions": { + "oauth2": { + "flow": "implicit", + "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize?resource=0b07f429-9f4b-4714-9392-cc5e8e80c8b0", + "type": "oauth2" + } + }, + "parameters": { + "eventRouteId": { + "name": "id", + "in": "path", + "required": true, + "type": "string", + "description": "The id for an event route. The id is unique within event routes and case sensitive.", + "x-ms-parameter-location": "method" + }, + "includeModelDefinition": { + "name": "includeModelDefinition", + "description": "When true the model definition will be returned as part of the result.", + "in": "query", + "required": false, + "type": "boolean", + "default": false, + "x-ms-parameter-location": "method" + }, + "digitalTwinId": { + "name": "id", + "in": "path", + "description": "The id of the digital twin. The id is unique within the service and case sensitive.", + "type": "string", + "required": true, + "x-ms-parameter-location": "method" + }, + "modelId": { + "name": "id", + "in": "path", + "description": "The id for the model. The id is globally unique and case sensitive.", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "relationshipId": { + "name": "relationshipId", + "description": "The id of the relationship. The id is unique within the digital twin and case sensitive.", + "in": "path", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "componentPath": { + "name": "componentPath", + "in": "path", + "description": "The name of the DTDL component.", + "type": "string", + "required": true, + "x-ms-parameter-location": "method" + }, + "api-version": { + "name": "api-version", + "in": "query", + "description": "The requested API version.", + "required": true, + "type": "string", + "enum": [ + "2020-05-31-preview" + ] + }, + "max-item-count": { + "name": "x-ms-max-item-count", + "in": "header", + "description": "The maximum number of items to retrieve per request. The server may choose to return less than the requested max.", + "required": false, + "type": "integer", + "default": -1, + "x-ms-client-name": "MaxItemCount", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "postfix": "Options" + } + }, + "if-none-match-star": { + "name": "If-None-Match", + "in": "header", + "description": "Only perform the operation if the entity does not already exist.", + "required": false, + "type": "string", + "enum": [ + "*" + ], + "x-ms-parameter-location": "method" + }, + "if-match": { + "name": "If-Match", + "in": "header", + "description": "Only perform the operation if the entity's etag matches one of the etags provided or * is provided.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + } + }, + "security": [ + { + "oauth2": [] + } + ] +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/CreateRelationshipAdvancedExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/CreateRelationshipAdvancedExample.json new file mode 100644 index 0000000000000..1f6ec28e906cf --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/CreateRelationshipAdvancedExample.json @@ -0,0 +1,25 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "mySourceTwin", + "relationshipId": "myRelationshipId", + "relationship": { + "$targetId": "myTargetTwin", + "$relationshipName": "myRelationship", + "relationshipProperty1": 1, + "relationshipProperty2": "some value" + } + }, + "responses": { + "200": { + "body": { + "$relationshipId": "myRelationshipId", + "$sourceId": "mySourceTwin", + "$targetId": "myTargetTwin", + "$relationshipName": "myRelationship", + "relationshipProperty1": 1, + "relationshipProperty2": "some value" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/CreateRelationshipBasicExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/CreateRelationshipBasicExample.json new file mode 100644 index 0000000000000..5ab5127bfb369 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/CreateRelationshipBasicExample.json @@ -0,0 +1,21 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "mySourceTwin", + "relationshipId": "myRelationshipId", + "relationship": { + "$targetId": "myTargetTwin", + "$relationshipName": "myRelationship" + } + }, + "responses": { + "200": { + "body": { + "$relationshipId": "myRelationshipId", + "$sourceId": "mySourceTwin", + "$targetId": "myTargetTwin", + "$relationshipName": "myRelationship" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteModel.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteModel.json new file mode 100644 index 0000000000000..4a0428b03fb46 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteModel.json @@ -0,0 +1,9 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "dtmi:com:example:Sample;1" + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteRelationship.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteRelationship.json new file mode 100644 index 0000000000000..d9acb6cc90a89 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteRelationship.json @@ -0,0 +1,10 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId", + "relationshipId": "myRelationshipId" + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteTwin.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteTwin.json new file mode 100644 index 0000000000000..bb55048e32c3d --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/DeleteTwin.json @@ -0,0 +1,9 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId" + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRouteDelete.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRouteDelete.json new file mode 100644 index 0000000000000..2ca8cfd3f8245 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRouteDelete.json @@ -0,0 +1,9 @@ +{ + "parameters": { + "id": "eventroute-001", + "api-version": "2020-05-31-preview" + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRouteGet.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRouteGet.json new file mode 100644 index 0000000000000..be0dc040a8508 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRouteGet.json @@ -0,0 +1,15 @@ +{ + "parameters": { + "id": "eventroute-001", + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": { + "id": "eventroute-001", + "endpointName": "endpoint-001", + "filter": "type = 'Microsoft.DigitalTwins.Twin.Create'" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutePut.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutePut.json new file mode 100644 index 0000000000000..b652891c1b31e --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutePut.json @@ -0,0 +1,13 @@ +{ + "parameters": { + "id": "eventroute-001", + "eventRoute": { + "endpointName": "endpoint-001", + "filter": "true" + }, + "api-version": "2020-05-31-preview" + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutePutWithFilter.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutePutWithFilter.json new file mode 100644 index 0000000000000..21f265e6ca924 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutePutWithFilter.json @@ -0,0 +1,13 @@ +{ + "parameters": { + "id": "eventroute-001", + "eventRoute": { + "endpointName": "endpoint-001", + "filter": "type = 'Microsoft.DigitalTwins.Twin.Create'" + }, + "api-version": "2020-05-31-preview" + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutesList.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutesList.json new file mode 100644 index 0000000000000..44c31910f3945 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/EventRoutesList.json @@ -0,0 +1,24 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": { + "value": [ + { + "id": "eventroute-001", + "endpointName": "endpoint-001", + "filter": "type = 'Microsoft.DigitalTwins.Twin.Create'" + }, + { + "id": "eventroute-002", + "endpointName": "endpoint-002", + "filter": "type = 'Microsoft.DigitalTwins.Twin.Create' OR type = 'microsoft.iot.telemetry'" + } + ], + "nextLink": "url-to-next-page" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetComponent.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetComponent.json new file mode 100644 index 0000000000000..655246856feba --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetComponent.json @@ -0,0 +1,53 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId", + "componentPath": "myComponent" + }, + "responses": { + "200": { + "body": { + "$metadata": { + "$model": "dtmi:com:example:interfaces:interfaceName;1", + "property1": { + "desiredValue": 1, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "description", + "lastUpdateTime": "2020-05-23T21:44:02Z" + }, + "property2": { + "desiredValue": { + "subProperty1": "some value", + "subProperty2": "some other value" + }, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "description", + "lastUpdateTime": "2020-05-23T21:44:02Z" + } + }, + "property1": 1, + "property2": { + "subProperty1": "some value", + "subProperty2": "some other value" + }, + "component1": { + "$metadata": { + "$model": "dtmi:com:example:interfaces:subInterfaceName;1", + "componentProperty": { + "desiredValue": "some value", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "description", + "lastUpdateTime": "2020-05-23T21:44:02Z" + } + } + } + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetIncomingRelationship.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetIncomingRelationship.json new file mode 100644 index 0000000000000..a50ceb94c6752 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetIncomingRelationship.json @@ -0,0 +1,27 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "mySourceTwin" + }, + "responses": { + "200": { + "body": { + "value": [ + { + "$sourceId": "mySourceTwin", + "$relationshipId": "firstRelationshipId", + "$relationshipName": "myRelationship", + "$relationshipLink": "/digitaltwins/mySourceTwin/relationships/myRelationship/firstRelationshipId" + }, + { + "$sourceId": "mySourceTwin", + "$relationshipId": "secondRelationshipId", + "$relationshipName": "myRelationship", + "$relationshipLink": "/digitaltwins/mySourceTwin/relationships/myRelationship/secondRelationshipId" + } + ], + "nextLink": "url-to-next-page" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationship.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationship.json new file mode 100644 index 0000000000000..259950edf17de --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationship.json @@ -0,0 +1,29 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "mySourceTwin" + }, + "responses": { + "200": { + "body": { + "value": [ + { + "$sourceId": "mySourceTwin", + "$relationshipId": "firstRelationshipId", + "$targetId": "targetTwinId", + "$relationshipName": "myRelationship", + "property": "value" + }, + { + "$sourceId": "mySourceTwin", + "$relationshipId": "secondRelationshipId", + "$targetId": "targetTwinId", + "$relationshipName": "myRelationship", + "property": "value" + } + ], + "nextLink": "url-to-next-page" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationshipById.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationshipById.json new file mode 100644 index 0000000000000..28a5a08c9784d --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationshipById.json @@ -0,0 +1,18 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "mySourceTwin", + "relationshipId": "myRelationshipId" + }, + "responses": { + "200": { + "body": { + "$relationshipId": "myRelationshipId", + "$sourceId": "mySourceTwin", + "$targetId": "myTargetTwin", + "$relationshipName": "myRelationship", + "relationshipProperty": "some value" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationshipByRelationshipName.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationshipByRelationshipName.json new file mode 100644 index 0000000000000..591dc7ae4b711 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetRelationshipByRelationshipName.json @@ -0,0 +1,30 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "mySourceTwin", + "relationshipName": "myRelationship" + }, + "responses": { + "200": { + "body": { + "value": [ + { + "$sourceId": "mySourceTwin", + "$relationshipId": "firstRelationshipId", + "$targetId": "targetTwinId", + "$relationshipName": "myRelationship", + "property": "value" + }, + { + "$sourceId": "mySourceTwin", + "$relationshipId": "secondRelationshipId", + "$targetId": "targetTwinId", + "$relationshipName": "myRelationship", + "property": "value" + } + ], + "nextLink": "url-to-next-page" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetTwin.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetTwin.json new file mode 100644 index 0000000000000..7dce0f94a6e87 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/GetTwin.json @@ -0,0 +1,53 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId" + }, + "responses": { + "200": { + "body": { + "$dtId": "myTwinId", + "$metadata": { + "$model": "dtmi:com:example:interfaces:interfaceName;1", + "property1": { + "desiredValue": 1, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "description", + "lastUpdateTime": "2020-05-23T21:44:02Z" + }, + "property2": { + "desiredValue": { + "subProperty1": "some value", + "subProperty2": "some other value" + }, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "description", + "lastUpdateTime": "2020-05-23T21:44:02Z" + } + }, + "property1": 1, + "property2": { + "subProperty1": "some value", + "subProperty2": "some other value" + }, + "component1": { + "$metadata": { + "$model": "dtmi:com:example:interfaces:subInterfaceName;1", + "componentProperty": { + "desiredValue": "some value", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "description", + "lastUpdateTime": "2020-05-23T21:44:02Z" + } + } + } + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelAdd.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelAdd.json new file mode 100644 index 0000000000000..b376ddb148608 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelAdd.json @@ -0,0 +1,47 @@ +{ + "parameters": { + "models": [ + { + "@id": "dtmi:com:example:Sample;1", + "@type": "Interface", + "displayName": "Sample Interface", + "contents": [ + { + "@type": "Property", + "name": "name", + "displayName": "Sample instance name", + "schema": "string" + }, + { + "@type": "Property", + "name": "temp", + "displayName": "Sample instance temperature", + "schema": "integer" + }, + { + "@type": "Property", + "name": "comfortIndex", + "displayName": "Sample instance comfort index", + "schema": "integer" + } + ], + "@context": "dtmi:dtdl:context;2" + } + ], + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": [ + { + "id": "dtmi:com:example:Sample;1", + "displayName": { + "en": "Sample Interface" + }, + "uploadTime": "2020-03-01T17:32:28Z", + "decommissioned": false + } + ] + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelGetById.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelGetById.json new file mode 100644 index 0000000000000..6de5d0f71a6e6 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelGetById.json @@ -0,0 +1,15 @@ +{ + "parameters": { + "id": "dtmi:com:example:Sample;1", + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": { + "id": "dtmi:com:example:Sample;1", + "uploadTime": "2020-03-01T17:32:28Z", + "decommissioned": false + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelGetByIdWithIncludeModelDefinition.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelGetByIdWithIncludeModelDefinition.json new file mode 100644 index 0000000000000..da0330cc52889 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelGetByIdWithIncludeModelDefinition.json @@ -0,0 +1,41 @@ +{ + "parameters": { + "id": "dtmi:com:example:Sample;1", + "includeModelDefinition": true, + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": { + "id": "dtmi:com:example:Sample;1", + "uploadTime": "2020-03-01T17:32:28Z", + "decommissioned": false, + "model": { + "@id": "dtmi:com:example:Sample;1", + "@type": "Interface", + "contents": [ + { + "@type": "Property", + "name": "name", + "displayName": "Sample instance name", + "schema": "string" + }, + { + "@type": "Property", + "name": "temp", + "displayName": "Sample instance temperature", + "schema": "integer" + }, + { + "@type": "Property", + "name": "comfortIndex", + "displayName": "Sample instance comfort index", + "schema": "integer" + } + ], + "@context": "dtmi:dtdl:context;2" + } + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelUpdateDecommissioned.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelUpdateDecommissioned.json new file mode 100644 index 0000000000000..513e272d1f546 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelUpdateDecommissioned.json @@ -0,0 +1,16 @@ +{ + "parameters": { + "id": "dtmi:com:example:Sample;1", + "updateModel": [ + { + "op": "replace", + "path": "/decommissioned", + "value": true + } + ], + "api-version": "2020-05-31-preview" + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelsGet.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelsGet.json new file mode 100644 index 0000000000000..e4fd22da2eec4 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelsGet.json @@ -0,0 +1,35 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": { + "value": [ + { + "id": "dtmi:com:example:Sample;1", + "uploadTime": "2020-03-01T17:32:28Z", + "decommissioned": false + }, + { + "id": "dtmi:com:example:SampleDeviceModel;1", + "displayName": { + "en": "My Device Model" + }, + "uploadTime": "2020-05-01T17:32:28Z", + "decommissioned": false + }, + { + "id": "dtmi:com:example:AnotherSample;1", + "displayName": { + "en": "My Sample" + }, + "uploadTime": "2020-03-01T17:32:28Z", + "decommissioned": false + } + ], + "nextLink": "url-to-next-page" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelsGetWithDependenciesAndIncludeModelDefinition.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelsGetWithDependenciesAndIncludeModelDefinition.json new file mode 100644 index 0000000000000..72f41ae288cd3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/ModelsGetWithDependenciesAndIncludeModelDefinition.json @@ -0,0 +1,70 @@ +{ + "parameters": { + "includeModelDefinition": true, + "dependenciesFor": [ + "dtmi:com:example:SampleDeviceModel;1" + ], + "x-ms-max-item-count": 20, + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": { + "value": [ + { + "id": "dtmi:com:example:Sample;1", + "uploadTime": "2020-03-01T17:32:28Z", + "decommissioned": false, + "model": { + "@id": "dtmi:com:example:Sample;1", + "@type": "Interface", + "contents": [ + { + "@type": "Property", + "name": "name", + "displayName": "Sample instance name", + "schema": "string" + }, + { + "@type": "Property", + "name": "temp", + "displayName": "Sample instance temperature", + "schema": "integer" + }, + { + "@type": "Property", + "name": "comfortIndex", + "displayName": "Sample instance comfort index", + "schema": "integer" + } + ], + "@context": "dtmi:dtdl:context;2" + } + }, + { + "id": "dtmi:com:example:SampleDeviceModel;1", + "displayName": { + "en": "My Device Model" + }, + "uploadTime": "2020-03-01T17:32:28Z", + "decommissioned": false, + "model": { + "@id": "dtmi:com:example:SampleDeviceModel;1", + "@type": "Interface", + "displayName": "My Device Model", + "contents": [ + { + "@type": "Component", + "name": "Sample", + "schema": "dtmi:com:example:Sample;1" + } + ], + "@context": "dtmi:dtdl:context;2" + } + } + ], + "nextLink": "url-to-next-page" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchComponentAdvancedExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchComponentAdvancedExample.json new file mode 100644 index 0000000000000..195387a5d378c --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchComponentAdvancedExample.json @@ -0,0 +1,27 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId", + "componentPath": "myComponent", + "patchDocument": [ + { + "op": "add", + "path": "/property1", + "value": 1 + }, + { + "op": "remove", + "path": "/property2" + }, + { + "op": "replace", + "path": "/property3/subProperty1", + "value": "new value" + } + ] + }, + "responses": { + "202": {}, + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchComponentBasicExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchComponentBasicExample.json new file mode 100644 index 0000000000000..c2a0624b8c358 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchComponentBasicExample.json @@ -0,0 +1,18 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId", + "componentPath": "myComponent", + "patchDocument": [ + { + "op": "add", + "path": "/property", + "value": 1 + } + ] + }, + "responses": { + "202": {}, + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchRelationshipAdvancedExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchRelationshipAdvancedExample.json new file mode 100644 index 0000000000000..59e6110920810 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchRelationshipAdvancedExample.json @@ -0,0 +1,26 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId", + "relationshipId": "myRelationshipId", + "patchDocument": [ + { + "op": "add", + "path": "/property1", + "value": 1 + }, + { + "op": "remove", + "path": "/property2" + }, + { + "op": "replace", + "path": "/property3/subProperty1", + "value": "new value" + } + ] + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchRelationshipBasicExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchRelationshipBasicExample.json new file mode 100644 index 0000000000000..f5294ae496de9 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchRelationshipBasicExample.json @@ -0,0 +1,17 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId", + "relationshipId": "myRelationshipId", + "patchDocument": [ + { + "op": "add", + "path": "/property", + "value": 1 + } + ] + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchTwinAdvancedExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchTwinAdvancedExample.json new file mode 100644 index 0000000000000..3a33baa321bb6 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchTwinAdvancedExample.json @@ -0,0 +1,26 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myNewTwinId", + "patchDocument": [ + { + "op": "replace", + "path": "/property1", + "value": 1 + }, + { + "op": "add", + "path": "/property2/subProperty1", + "value": 1 + }, + { + "op": "remove", + "path": "/property3" + } + ] + }, + "responses": { + "202": {}, + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchTwinBasicExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchTwinBasicExample.json new file mode 100644 index 0000000000000..477251dce7835 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PatchTwinBasicExample.json @@ -0,0 +1,17 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myNewTwinId", + "patchDocument": [ + { + "op": "replace", + "path": "/property1", + "value": 1 + } + ] + }, + "responses": { + "202": {}, + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PutTwinAdvancedExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PutTwinAdvancedExample.json new file mode 100644 index 0000000000000..7639f575e1dc4 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PutTwinAdvancedExample.json @@ -0,0 +1,71 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myNewTwinId", + "If-None-Match": "*", + "twin": { + "$metadata": { + "$model": "dtmi:com:example:interfaces:interfaceName;1" + }, + "property1": 1, + "property2": { + "subProperty1": "some value", + "subProperty2": "some other value" + }, + "component1": { + "$metadata": { + "$model": "dtmi:com:example:interfaces:subInterfaceName;1" + }, + "componentProperty": "some value" + } + } + }, + "responses": { + "200": { + "body": { + "$dtId": "myNewTwinId", + "$metadata": { + "$model": "dtmi:com:example:interfaces:interfaceName;1", + "property1": { + "desiredValue": 1, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "description", + "lastUpdateTime": "2020-05-23T21:44:02Z" + }, + "property2": { + "desiredValue": { + "subProperty1": "some value", + "subProperty2": "some other value" + }, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "description", + "lastUpdateTime": "2020-05-23T21:44:02Z" + } + }, + "property1": 1, + "property2": { + "subProperty1": "some value", + "subProperty2": "some other value" + }, + "component1": { + "$metadata": { + "$model": "dtmi:com:example:interfaces:subInterfaceName;1", + "componentProperty": { + "desiredValue": "some value", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "description", + "lastUpdateTime": "2020-05-23T21:44:02Z" + } + } + } + } + }, + "202": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PutTwinBasicExample.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PutTwinBasicExample.json new file mode 100644 index 0000000000000..b1ee99c8ecfc8 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/PutTwinBasicExample.json @@ -0,0 +1,22 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myNewTwinId", + "twin": { + "$metadata": { + "$model": "dtmi:com:example:interfaces:interfaceName;1" + } + } + }, + "responses": { + "200": { + "body": { + "$dtId": "myNewTwinId", + "$metadata": { + "$model": "dtmi:com:example:interfaces:interfaceName;1" + } + } + }, + "202": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryFirstPage.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryFirstPage.json new file mode 100644 index 0000000000000..fe1106c5608b3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryFirstPage.json @@ -0,0 +1,44 @@ +{ + "parameters": { + "querySpecification": { + "query": "SELECT * FROM DIGITALTWINS WHERE temp = 79" + }, + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": { + "items": [ + { + "$dtId": "Twin-01", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample01", + "temp": 79, + "comfortIndex": 50 + }, + { + "$dtId": "Twin-02", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample02", + "temp": 79, + "comfortIndex": 50 + }, + { + "$dtId": "Twin-03", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample03", + "temp": 79, + "comfortIndex": 50 + } + ], + "continuationToken": "" + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryJoin.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryJoin.json new file mode 100644 index 0000000000000..d40910417c06a --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryJoin.json @@ -0,0 +1,56 @@ +{ + "parameters": { + "querySpecification": { + "query": "SELECT Widget, Gadget FROM DIGITALTWINS Widget JOIN Gadget RELATED Widget.Contains WHERE Widget.$dtId = 'Twin-01'" + }, + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": { + "items": [ + { + "Widget": { + "$dtId": "Twin-01", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample01", + "temp": 79, + "comfortIndex": 50 + }, + "Gadget": { + "$dtId": "Twin-02", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample02", + "temp": 79, + "comfortIndex": 50 + } + }, + { + "Widget": { + "$dtId": "Twin-01", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample01", + "temp": 79, + "comfortIndex": 50 + }, + "Gadget": { + "$dtId": "Twin-10", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample10", + "temp": 79, + "comfortIndex": 50 + } + } + ] + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryNextPage.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryNextPage.json new file mode 100644 index 0000000000000..d7ecc8ad39c68 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/QueryNextPage.json @@ -0,0 +1,43 @@ +{ + "parameters": { + "querySpecification": { + "continuationToken": "" + }, + "api-version": "2020-05-31-preview" + }, + "responses": { + "200": { + "body": { + "items": [ + { + "$dtId": "Twin-04", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample04", + "temp": 79, + "comfortIndex": 50 + }, + { + "$dtId": "Twin-05", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample05", + "temp": 79, + "comfortIndex": 50 + }, + { + "$dtId": "Twin-06", + "$metadata": { + "$model": "dtmi:com:example:Sample;1" + }, + "name": "Sample06", + "temp": 79, + "comfortIndex": 50 + } + ] + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/SendTelemetry.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/SendTelemetry.json new file mode 100644 index 0000000000000..941a77beffa32 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/SendTelemetry.json @@ -0,0 +1,14 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId", + "dt-id": "e5ca50dd-ca31-4fae-8d84-3af5a72b10c5", + "dt-timestamp": "1985-04-12T23:20:50.52Z", + "telemetry": { + "temperature": 1 + } + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/SendTelemetryFromComponent.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/SendTelemetryFromComponent.json new file mode 100644 index 0000000000000..dfec5fa532735 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/examples/SendTelemetryFromComponent.json @@ -0,0 +1,15 @@ +{ + "parameters": { + "api-version": "2020-05-31-preview", + "id": "myTwinId", + "componentPath": "myComponent", + "dt-id": "e5ca50dd-ca31-4fae-8d84-3af5a72b10c5", + "dt-timestamp": "1985-04-12T23:20:50.52Z", + "telemetry": { + "temperature": 1 + } + }, + "responses": { + "204": {} + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/Azure.DigitalTwins.Core.Tests.csproj b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/Azure.DigitalTwins.Core.Tests.csproj new file mode 100644 index 0000000000000..a976111bbb8b8 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/Azure.DigitalTwins.Core.Tests.csproj @@ -0,0 +1,47 @@ + + + $(RequiredTargetFrameworks) + $(DefineConstants);TESTFRAMEWORK + true + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + + + True + True + TestAssets.resx + + + ResXFileCodeGenerator + TestAssets.Designer.cs + PreserveNewest + + + + + + + + + + diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/BasicRelationshipUnitTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/BasicRelationshipUnitTests.cs new file mode 100644 index 0000000000000..edcfdf1e2c8be --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/BasicRelationshipUnitTests.cs @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Text.Json; +using Azure.DigitalTwins.Core.Serialization; +using FluentAssertions; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + [Category("Unit")] + [Parallelizable(ParallelScope.All)] + public class BasicRelationshipUnitTests + { + [Test] + public void BasicRelationship_DeseralizesAllProps() + { + // arrange + + const string expectedRelationshipId = "relationshipId123"; + const string expectedRelationship = "relationship123"; + const string expectedSourceId = "sourceId123"; + const string expectedTargetId = "targetId123"; + const string expectedCustomPropKey = "customPropKey123"; + const string expectedCustomPropVal = "customPropVal123"; + + string relationshipJson = "{" + + $"\"$relationshipId\": \"{expectedRelationshipId}\"," + + $"\"$relationshipName\": \"{expectedRelationship}\"," + + $"\"$sourceId\": \"{expectedSourceId}\"," + + $"\"$targetId\": \"{expectedTargetId}\"," + + $"\"{expectedCustomPropKey}\": \"{expectedCustomPropVal}\"" + + "}"; + + // act + BasicRelationship actual = JsonSerializer.Deserialize(relationshipJson); + + // assert + + actual.Id.Should().Be(expectedRelationshipId); + actual.Name.Should().Be(expectedRelationship); + actual.SourceId.Should().Be(expectedSourceId); + actual.TargetId.Should().Be(expectedTargetId); + actual.CustomProperties[expectedCustomPropKey].ToString().Should().Be(expectedCustomPropVal); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/ComponentTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/ComponentTests.cs new file mode 100644 index 0000000000000..d457a9bfe4da3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/ComponentTests.cs @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using FluentAssertions; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + public class ComponentTests : E2eTestBase + { + public ComponentTests(bool isAsync) + : base(isAsync) + { + } + + [Test] + 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 { roomWithWifiModel, wifiModel }).ConfigureAwait(false); + + // create room digital twin + string roomWithWifiTwin = TestAssetsHelper.GetRoomWithWifiTwinPayload(roomWithWifiModelId, wifiModelId, wifiComponentName); + + await client.CreateDigitalTwinAsync(roomWithWifiTwinId, roomWithWifiTwin); + + // Get the component + Response 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 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}"); + } + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinClientTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinClientTests.cs new file mode 100644 index 0000000000000..fdefa8e189660 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinClientTests.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Linq; +using FluentAssertions; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + [Category("Unit")] + [Parallelizable(ParallelScope.All)] + public class DigitalTwinClientTests + { + private const string PublicCloudScope = "https://digitaltwins.azure.net/.default"; + + [Test] + public void DigitalTwinClient_GetScopes_PpeValid() + { + Uri adtInstanceEndpoint = new Uri("https://testinstance.api.scus.pp.azuredigitaltwins-ppe.net"); + string[] scopes = DigitalTwinsClient.GetAuthorizationScopes(adtInstanceEndpoint); + scopes.Length.Should().Be(1, "There must be only 1 scope in the list"); + scopes.First().Should().Be(PublicCloudScope, "Invalid scope was generated"); + } + + [Test] + public void DigitalTwinClient_GetScopes_PublicCloudValid() + { + Uri adtInstanceEndpoint = new Uri("https://testInstance.api.scus.azuredigitaltwins.azure.net"); + string[] scopes = DigitalTwinsClient.GetAuthorizationScopes(adtInstanceEndpoint); + scopes.Length.Should().Be(1, "There must be only 1 scope in the list"); + scopes.First().Should().Be(PublicCloudScope, "Invalid scope was generated"); + } + + [Test] + public void DigitalTwinClient_GetScopes_InvalidEndpoint() + { + Uri adtInstanceEndpoint = new Uri("https://testInstance.api.scus.azuredigitaltwins.fairfax.gov"); + + // act + Func act = () => + { + return DigitalTwinsClient.GetAuthorizationScopes(adtInstanceEndpoint); + }; + + // assert + act.Should().Throw(); + } + + [Test] + public void DigitalTwinClient_GetScopes_NullOrEmptyEndpointThrows() + { + // act + Func act = () => + { + return DigitalTwinsClient.GetAuthorizationScopes(null); + }; + + // assert + act.Should().Throw() + .And.ParamName.Should().Be("endpoint"); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinRelationshipTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinRelationshipTests.cs new file mode 100644 index 0000000000000..fd284dd7ac861 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinRelationshipTests.cs @@ -0,0 +1,248 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using Azure.DigitalTwins.Core.Models; +using FluentAssertions; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + public class DigitalTwinRelationshipTests : E2eTestBase + { + private const string ContainsRelationship = "contains"; + private const string ContainedInRelationship = "containedIn"; + private const string CoolsRelationship = "cools"; + private const string CooledByRelationship = "cooledBy"; + + public DigitalTwinRelationshipTests(bool isAsync) + : base(isAsync) + { + } + + [Test] + 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, TestAssetSettings.FloorModelIdPrefix).ConfigureAwait(false); + string roomModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.RoomModelIdPrefix).ConfigureAwait(false); + string hvacModelId = await GetUniqueTwinIdAsync(client, TestAssetSettings.HvacModelIdPrefix).ConfigureAwait(false); + + string floorTwinId = await GetUniqueTwinIdAsync(client, TestAssetSettings.FloorTwinIdPrefix).ConfigureAwait(false); + string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetSettings.RoomTwinIdPrefix).ConfigureAwait(false); + string hvacTwinId = await GetUniqueTwinIdAsync(client, TestAssetSettings.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 { floorModel, roomModel, hvacModel }).ConfigureAwait(false); + + // create floor twin + string floorTwin = TestAssetsHelper.GetFloorTwinPayload(floorModelId); + await client.CreateDigitalTwinAsync(floorTwinId, floorTwin).ConfigureAwait(false); + + // Create room twin + string roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId); + await client.CreateDigitalTwinAsync(roomTwinId, roomTwin).ConfigureAwait(false); + + // create hvac twin + string hvacTwin = TestAssetsHelper.GetHvacTwinPayload(hvacModelId); + await client.CreateDigitalTwinAsync(hvacTwinId, hvacTwin).ConfigureAwait(false); + + string floorContainsRoomPayload = TestAssetsHelper.GetRelationshipWithPropertyPayload(roomTwinId, ContainsRelationship, "isAccessRestricted", true); + string floorTwinCoolsRelationshipPayload = TestAssetsHelper.GetRelationshipPayload(floorTwinId, CoolsRelationship); + string floorTwinContainedInRelationshipPayload = TestAssetsHelper.GetRelationshipPayload(floorTwinId, ContainedInRelationship); + string floorCooledByHvacPayload = TestAssetsHelper.GetRelationshipPayload(hvacTwinId, CooledByRelationship); + string floorContainsRoomUpdatePayload = TestAssetsHelper.GetRelationshipUpdatePayload("isAccessRestricted", false); + + // CREATE relationships + + // create Relationship from Floor -> Room + await client + .CreateRelationshipAsync( + floorTwinId, + floorContainsRoomRelationshipId, + floorContainsRoomPayload) + .ConfigureAwait(false); + + // create Relationship from Floor -> Hvac + await client + .CreateRelationshipAsync( + floorTwinId, + floorCooledByHvacRelationshipId, + floorCooledByHvacPayload) + .ConfigureAwait(false); + + // create Relationship from Hvac -> Floor + await client + .CreateRelationshipAsync( + hvacTwinId, + hvacCoolsFloorRelationshipId, + floorTwinCoolsRelationshipPayload) + .ConfigureAwait(false); + + // create Relationship from Room -> Floor + await client + .CreateRelationshipAsync( + roomTwinId, + roomContainedInFloorRelationshipId, + floorTwinContainedInRelationshipPayload) + .ConfigureAwait(false); + + // UPDATE relationships + + // create Relationship from Floor -> Room + await client + .UpdateRelationshipAsync( + floorTwinId, + floorContainsRoomRelationshipId, + floorContainsRoomUpdatePayload) + .ConfigureAwait(false); + + // GET relationship + Response containsRelationshipId = await client + .GetRelationshipAsync( + floorTwinId, + floorContainsRoomRelationshipId) + .ConfigureAwait(false); + + // LIST incoming relationships + AsyncPageable 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 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 roomTwinRelationships = client + .GetRelationshipsAsync( + roomTwinId, + ContainedInRelationship); + containsRelationshipId.Value.Should().Contain(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 act = async () => + { + await client + .GetRelationshipAsync( + floorTwinId, + floorContainsRoomRelationshipId) + .ConfigureAwait(false); + }; + act.Should().Throw() + .And.Status.Should().Be((int)HttpStatusCode.NotFound); + + act = async () => + { + await client + .GetRelationshipAsync( + roomTwinId, + roomContainedInFloorRelationshipId) + .ConfigureAwait(false); + }; + act.Should().Throw(). + And.Status.Should().Be((int)HttpStatusCode.NotFound); + + act = async () => + { + await client + .GetRelationshipAsync( + floorTwinId, + floorCooledByHvacRelationshipId) + .ConfigureAwait(false); + }; + act.Should().Throw(). + And.Status.Should().Be((int)HttpStatusCode.NotFound); + + act = async () => + { + await client + .GetRelationshipAsync( + hvacTwinId, + hvacCoolsFloorRelationshipId) + .ConfigureAwait(false); + }; + act.Should().Throw() + .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}"); + } + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinTests.cs new file mode 100644 index 0000000000000..c72e99f1a3573 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinTests.cs @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Net; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using FluentAssertions; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + /// + /// Tests for DigitalTwinServiceClient methods dealing with Digital Twin operations. + /// + public class DigitalTwinTests : E2eTestBase + { + public DigitalTwinTests(bool isAsync) + : base(isAsync) + { + } + + [Test] + public async Task DigitalTwins_Lifecycle() + { + DigitalTwinsClient client = GetClient(); + + string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetSettings.RoomTwinIdPrefix).ConfigureAwait(false); + string floorModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.FloorModelIdPrefix).ConfigureAwait(false); + string roomModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.RoomModelIdPrefix).ConfigureAwait(false); + + try + { + // arrange + + // create room model + string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId); + await client.CreateModelsAsync(new List { roomModel }).ConfigureAwait(false); + + // act + + // create room twin + string roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId); + await client.CreateDigitalTwinAsync(roomTwinId, roomTwin).ConfigureAwait(false); + + // get twin + await client.GetDigitalTwinAsync(roomTwinId).ConfigureAwait(false); + + // update twin + string updateTwin = TestAssetsHelper.GetRoomTwinUpdatePayload(); + await client.UpdateDigitalTwinAsync(roomTwinId, updateTwin).ConfigureAwait(false); + + // delete a twin + await client.DeleteDigitalTwinAsync(roomTwinId).ConfigureAwait(false); + + // assert + Func act = async () => + { + await client.GetDigitalTwinAsync(roomTwinId).ConfigureAwait(false); + }; + act.Should().Throw() + .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}"); + } + } + } + + [Test] + public void DigitalTwins_IncorrectCredentials_ThrowsUnauthorizedException() + { + // arrange + DigitalTwinsClient unauthorizedClient = GetFakeClient(); + + // act + Func act = async () => + { + await unauthorizedClient.GetDigitalTwinAsync("someNonExistantTwin").ConfigureAwait(false); + }; + + // assert + act.Should().Throw() + .And.Status.Should().Be((int)HttpStatusCode.Unauthorized); + } + + [Test] + public void DigitalTwins_TwinNotExist_ThrowsNotFoundException() + { + // arrange + DigitalTwinsClient client = GetClient(); + + // act + Func act = async () => + { + await client.GetDigitalTwinAsync("someNonExistantTwin").ConfigureAwait(false); + }; + + // assert + act.Should().Throw() + .And.Status.Should().Be((int)HttpStatusCode.NotFound); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwins/updateTwin.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwins/updateTwin.json new file mode 100644 index 0000000000000..c34017594a55a --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwins/updateTwin.json @@ -0,0 +1,16 @@ +[ + { + "op": "add", + "path": "/Humidity", + "value": 30 + }, + { + "op": "replace", + "path": "/Temperature", + "value": 70 + }, + { + "op": "remove", + "path": "/EmployeeId" + } +] diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinsTestEnvironment.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinsTestEnvironment.cs new file mode 100644 index 0000000000000..c5d50c3c03c3c --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/DigitalTwinsTestEnvironment.cs @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.Core.TestFramework; + +namespace Azure.DigitalTwins.Core.Tests +{ + public class DigitalTwinsTestEnvironment : TestEnvironment + { + public DigitalTwinsTestEnvironment() + : base(TestSettings.AdtEnvironmentVariablesPrefix) + { + } + + public string DigitalTwinHostname => GetRecordedVariable("DIGITALTWINS_URL"); + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/E2eTestBase.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/E2eTestBase.cs new file mode 100644 index 0000000000000..f03f689f8b301 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/E2eTestBase.cs @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Net; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + /// + /// This class will initialize all the settings and create and instance of the Digital twins client. + /// + [Parallelizable(ParallelScope.Self)] + [Category("Live")] // This category indicates the tests hit a "live" service: https://github.com/Azure/azure-sdk-for-net/blob/master/CONTRIBUTING.md#to-test-1 + public abstract class E2eTestBase : RecordedTestBase + { + protected static readonly int MaxTries = 10; + + // Based on testing, the max length of models can be 27 only and works well for other resources as well. This can be updated when required. + protected static readonly int MaxIdLength = 27; + + public E2eTestBase(bool isAsync) + : base(isAsync, TestSettings.Instance.TestMode) + { + } + + public E2eTestBase(bool isAsync, RecordedTestMode testMode) + : base(isAsync, testMode) + { + } + + [SetUp] + public virtual void SetupE2eTestBase() + { + TestDiagnostics = false; + + // TODO: set via client options and pipeline instead + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; + } + + protected DigitalTwinsClient GetClient() + { + return InstrumentClient( + new DigitalTwinsClient( + new Uri(TestEnvironment.DigitalTwinHostname), + TestEnvironment.Credential, + Recording.InstrumentClientOptions(new DigitalTwinsClientOptions()))); + } + + protected DigitalTwinsClient GetFakeClient() + { + return InstrumentClient( + new DigitalTwinsClient( + new Uri(TestEnvironment.DigitalTwinHostname), + new FakeTokenCredential(), + Recording.InstrumentClientOptions(new DigitalTwinsClientOptions()))); + } + + public async Task GetUniqueModelIdAsync(DigitalTwinsClient dtClient, string baseName) + { + return await GetUniqueIdAsync(baseName, (modelId) => dtClient.GetModelAsync(modelId)).ConfigureAwait(false); + } + + public async Task GetUniqueTwinIdAsync(DigitalTwinsClient dtClient, string baseName) + { + return await GetUniqueIdAsync(baseName, (twinId) => dtClient.GetDigitalTwinAsync(twinId)).ConfigureAwait(false); + } + + private async Task GetUniqueIdAsync(string baseName, Func getResource) + { + var id = Recording.GenerateId(baseName, MaxIdLength); + + for (int i = 0; i < MaxTries; ++i) + { + try + { + await getResource(id).ConfigureAwait(false); + } + catch (RequestFailedException ex) when (ex.Status == (int)HttpStatusCode.NotFound) + { + return id; + } + id = Recording.GenerateId(baseName, MaxIdLength); + } + + throw new Exception($"Unique Id could not be found with base {baseName}"); + } + + protected string GetRandom() + { + return Recording.GenerateId(); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/EventRouteTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/EventRouteTests.cs new file mode 100644 index 0000000000000..117057cc5055b --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/EventRouteTests.cs @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Net; +using System.Threading.Tasks; +using FluentAssertions; +using Azure.DigitalTwins.Core.Models; +using System; +using NUnit.Framework; +using Azure.Core.TestFramework; + +namespace Azure.DigitalTwins.Core.Tests +{ + /// + /// Tests for DigitalTwinServiceClient methods dealing with Digital Twin operations + /// + public class EventRouteTests : E2eTestBase + { + public EventRouteTests(bool isAsync) + : base(isAsync) + { + } + + // Infrastructure setup script uses this hardcoded value when linking the test eventhub to the test digital twins instance + private const string EndpointName = "someEventHubEndpoint"; + + [Test] + public async Task EventRoutes_Lifecycle() + { + // arrange + + DigitalTwinsClient client = GetClient(); + + // Ensure unique eventRouteId and endpointName + string eventRouteId = $"someEventRouteId-{GetRandom()}"; + string filter = "$eventType = 'DigitalTwinTelemetryMessages' or $eventType = 'DigitalTwinLifecycleNotification'"; + var eventRoute = new EventRoute(EndpointName) + { + Filter = filter + }; + + // Test CreateEventRoute + Response createEventRouteResponse = await client.CreateEventRouteAsync(eventRouteId, eventRoute).ConfigureAwait(false); + createEventRouteResponse.Status.Should().Be((int)HttpStatusCode.NoContent); + + // Test GetEventRoute + EventRoute getEventRouteResult = await client.GetEventRouteAsync(eventRouteId); + eventRoute.EndpointName.Should().Be(getEventRouteResult.EndpointName); + eventRoute.Filter.Should().Be(getEventRouteResult.Filter); + eventRouteId.Should().Be(getEventRouteResult.Id); + + // Test GetEventRoutes + var eventRoutesListOptions = new EventRoutesListOptions(); + AsyncPageable eventRouteList = client.GetEventRoutesAsync(eventRoutesListOptions); + bool eventRouteFoundInList = false; + await foreach (EventRoute eventRouteListEntry in eventRouteList) + { + if (StringComparer.Ordinal.Equals(eventRouteListEntry.Id, eventRouteId)) + { + eventRouteFoundInList = true; + eventRoute.EndpointName.Should().Be(getEventRouteResult.EndpointName); + eventRoute.Filter.Should().Be(getEventRouteResult.Filter); + break; + } + } + + eventRouteFoundInList.Should().BeTrue("Newly created event route should have been present when listing all event routes"); + + // Test DeleteEventRoute + Response deleteEventRouteResponse = await client.DeleteEventRouteAsync(eventRouteId).ConfigureAwait(false); + deleteEventRouteResponse.Status.Should().Be((int)HttpStatusCode.NoContent); + + // Verify event route was deleted by trying to get it again + + // act + Func act = async () => await client.GetEventRouteAsync(eventRouteId).ConfigureAwait(false); + + // assert + act.Should().Throw() + .And.Status.Should().Be((int)HttpStatusCode.NotFound); + } + + [Test] + public void EventRoutes_EventRouteNotExist_ThrowsNotFoundException() + { + // arrange + DigitalTwinsClient client = GetClient(); + + // act + Func act = async () => await client.GetEventRouteAsync("someNonExistantEventRoute").ConfigureAwait(false); + + // assert + act.Should().Throw() + .And.Status.Should().Be((int)HttpStatusCode.NotFound); + } + + [Test] + public void EventRoutes_MalformedEventRouteFilter_ThrowsBadRequestException() + { + // arrange + + DigitalTwinsClient client = GetClient(); + + // Ensure unique eventRouteId and endpointName + string eventRouteId = $"someEventRouteId-{GetRandom()}"; + string filter = "this is not a valid filter string"; + var eventRoute = new EventRoute(EndpointName) + { + Filter = filter + }; + + // Test CreateEventRoute + Func act = async () => await client.CreateEventRouteAsync(eventRouteId, eventRoute).ConfigureAwait(false); + act.Should().Throw() + .And.Status.Should().Be((int)HttpStatusCode.BadRequest); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/FakeTokenCredential.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/FakeTokenCredential.cs new file mode 100644 index 0000000000000..1ca07dfce6cf1 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/FakeTokenCredential.cs @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Azure.Core; + +namespace Azure.DigitalTwins.Core.Tests +{ + /// + /// This class is used for providing incorrect credentials to the service when making requests. + /// + public class FakeTokenCredential : TokenCredential + { + public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken) + { + return new AccessToken("someFakeAccessToken", DateTimeOffset.MaxValue); + } + + public override ValueTask GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken) + { + return new ValueTask(new AccessToken("someFakeAccessToken", DateTimeOffset.MaxValue)); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/Models/wifi.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/Models/wifi.json new file mode 100644 index 0000000000000..a8ddc135c92b7 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/Models/wifi.json @@ -0,0 +1,18 @@ +{ + "@id": "dtmi:example:Wifi;1", + "@type": "Interface", + "@context": "dtmi:dtdl:context;2", + "displayName": "Wifi", + "contents": [ + { + "@type": "Property", + "name": "RouterName", + "schema": "string" + }, + { + "@type": "Property", + "name": "Network", + "schema": "string" + } + ] +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/ModelsTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/ModelsTests.cs new file mode 100644 index 0000000000000..daec99422cf32 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/ModelsTests.cs @@ -0,0 +1,158 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using Azure.DigitalTwins.Core.Models; +using FluentAssertions; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + /// + /// Tests for DigitalTwinServiceClient methods dealing with Digital Twin operations. + /// + public class ModelsTests : E2eTestBase + { + public ModelsTests(bool isAsync) + : base(isAsync) + { + } + + [Test] + public async Task Models_Lifecycle() + { + DigitalTwinsClient client = GetClient(); + + string buildingModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.Instance.BuildingModelId).ConfigureAwait(false); + string floorModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.Instance.FloorModelId).ConfigureAwait(false); + string hvacModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.Instance.HvacModelId).ConfigureAwait(false); + string wardModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.Instance.WardModelId).ConfigureAwait(false); + + try + { + string modelBuilding = TestAssetsHelper.GetBuildingModelPayload(buildingModelId, hvacModelId, floorModelId); + string modelHvac = TestAssetsHelper.GetHvacModelPayload(hvacModelId, floorModelId); + string modelWard = TestAssetsHelper.GetWardModelPayload(wardModelId); + + // CREATE models + var modelsList = new List { modelBuilding, modelHvac, modelWard }; + await client.CreateModelsAsync(modelsList).ConfigureAwait(false); + + // GET one created model + Response buildingModel = await client.GetModelAsync(buildingModelId).ConfigureAwait(false); + Console.WriteLine($"Got {buildingModelId} as {buildingModel.Value.Model}"); + + // LIST all models + AsyncPageable models = client.GetModelsAsync(); + await foreach (ModelData model in models) + { + Console.WriteLine($"{model.Id}"); + } + + // DECOMMISSION a model + await client.DecommissionModelAsync(buildingModelId).ConfigureAwait(false); + } + finally + { + // Test DELETE all models. + try + { + await client.DeleteModelAsync(buildingModelId).ConfigureAwait(false); + await client.DeleteModelAsync(hvacModelId).ConfigureAwait(false); + await client.DeleteModelAsync(wardModelId).ConfigureAwait(false); + } + catch (Exception ex) + { + Assert.Fail($"Test clean up failed: {ex.Message}"); + } + } + } + + /// + /// Swagger defines ModelData as an object, but expected to be "a language map that contains the localized" values. + /// A model definition may specify a single string value, and the service will turn that into a dictionary. + /// This test validates that potentially non-conforming data format (string) properly gets translated into a map + /// on the service, and can be properly deserialized into a ModelData instance in the SDK. + /// + [Test] + public async Task ModelData_DisplayNameAndDescription_Deserializes() + { + // arrange + + DigitalTwinsClient client = GetClient(); + + string wardModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.Instance.WardModelId).ConfigureAwait(false); + + // add a model with a single value for displayName and for description, neither of which were defined as a map + string modelWard = TestAssetsHelper.GetWardModelPayload(wardModelId); + + await client.CreateModelsAsync(new[] { modelWard }).ConfigureAwait(false); + + // act + // should not throw on deserialization + Response wardModel = await client.GetModelAsync(wardModelId).ConfigureAwait(false); + + // assert + + wardModel.Value.DisplayName.Count.Should().Be(1, "Should have 1 entry for display name"); + wardModel.Value.DisplayName.Keys.First().Should().Be("en"); + } + + [Test] + public void Models_ModelNotExists_ThrowsNotFoundException() + { + // arrange + DigitalTwinsClient client = GetClient(); + + // act + Func act = async () => await client.GetModelAsync("urn:doesnotexist:fakemodel:1000").ConfigureAwait(false); + + // assert + act.Should().Throw() + .And.Status.Should().Be((int)HttpStatusCode.NotFound); + } + + [Test] + public void Models_MalformedModelId_ThrowsBadRequestException() + { + // arrange + DigitalTwinsClient client = GetClient(); + + // act + Func act = async () => await client.GetModelAsync("thisIsNotAValidModelId").ConfigureAwait(false); + + // assert + act.Should().Throw() + .And.Status.Should().Be((int)HttpStatusCode.BadRequest); + } + + [Test] + public async Task Models_ModelAlreadyExists_ThrowsConflictException() + { + // arrange + + DigitalTwinsClient client = GetClient(); + + string wardModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.Instance.WardModelId).ConfigureAwait(false); + + string modelWard = TestAssetsHelper.GetWardModelPayload(wardModelId); + + var modelsList = new List { modelWard }; + + // Create model once + await client.CreateModelsAsync(modelsList).ConfigureAwait(false); + + // act + Func act = async () => await client.CreateModelsAsync(modelsList).ConfigureAwait(false); + + // assert + act.Should().Throw() + .And.Status.Should().Be((int)HttpStatusCode.Conflict); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/PayloadHelperUnitTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/PayloadHelperUnitTests.cs new file mode 100644 index 0000000000000..0d43759e3fa97 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/PayloadHelperUnitTests.cs @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text.Json; +using Azure.DigitalTwins.Core.Serialization; +using FluentAssertions; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + [Category("Unit")] + [Parallelizable(ParallelScope.All)] + public class PayloadHelperUnitTests + { + [Test] + public void PayloadHelper_BuildArrayPayload_ValidateArray() + { + // arrange + string floorJson = TestAssetsHelper.GetFloorModelPayload( + TestAssetSettings.Instance.FloorModelId, + TestAssetSettings.Instance.RoomModelId, + TestAssetSettings.Instance.HvacModelId); + string roomJson = TestAssetsHelper.GetRoomModelPayload(TestAssetSettings.Instance.RoomModelId, TestAssetSettings.Instance.FloorModelId); + var models = new List { floorJson, roomJson }; + + // act + string creationPayload = PayloadHelper.BuildArrayPayload(models); + + // assert + creationPayload.Should().NotBeNullOrEmpty(); + JsonDocument parsedJson = JsonDocument.Parse(creationPayload); + parsedJson.RootElement.ValueKind.Should().Be(JsonValueKind.Array); + parsedJson.RootElement.GetArrayLength().Should().Be(models.Count); + parsedJson.RootElement[0].ToString().Should().Be(floorJson); + parsedJson.RootElement[1].ToString().Should().Be(roomJson); + } + + [Test] + public void PayloadHelper_BuildArrayPayload_NullParam() + { + Action act = () => PayloadHelper.BuildArrayPayload(null); + + act.Should().Throw() + .And.ParamName.Should().Be("entities"); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/QueryTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/QueryTests.cs new file mode 100644 index 0000000000000..7d79a48c085c2 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/QueryTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text.Json; +using System.Threading.Tasks; +using Azure.Core.TestFramework; +using FluentAssertions; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + public class QueryTests : E2eTestBase + { + public QueryTests(bool isAsync) + : base(isAsync) + { + } + + [Test] + public async Task Query_ValidQuery_Success() + { + DigitalTwinsClient client = GetClient(); + + string floorModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.FloorModelIdPrefix).ConfigureAwait(false); + string roomModelId = await GetUniqueModelIdAsync(client, TestAssetSettings.RoomModelIdPrefix).ConfigureAwait(false); + + try + { + // arrange + + // Create room model + string roomModel = TestAssetsHelper.GetRoomModelPayload(roomModelId, floorModelId); + await client.CreateModelsAsync(new List { roomModel }).ConfigureAwait(false); + + // Create a room twin, with property "IsOccupied": true + string roomTwinId = await GetUniqueTwinIdAsync(client, TestAssetSettings.RoomTwinIdPrefix).ConfigureAwait(false); + string roomTwin = TestAssetsHelper.GetRoomTwinPayload(roomModelId); + await client.CreateDigitalTwinAsync(roomTwinId, roomTwin).ConfigureAwait(false); + + string queryString = "SELECT * FROM digitaltwins where IsOccupied = true"; + + // act + AsyncPageable asyncPageableResponse = client.QueryAsync(queryString); + + // assert + await foreach (string response in asyncPageableResponse) + { + JsonElement jsonElement = JsonSerializer.Deserialize(response); + JsonElement isOccupied = jsonElement.GetProperty("IsOccupied"); + isOccupied.GetRawText().Should().Be("true"); + } + } + 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}"); + } + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ComponentTests/Component_Lifecycle.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ComponentTests/Component_Lifecycle.json new file mode 100644 index 0000000000000..446e07cbed9f3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ComponentTests/Component_Lifecycle.json @@ -0,0 +1,395 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Awifi%3B116048137?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6a04cf4edbf3d89c8aa2c9a4af0c55a3", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:wifi;116048137. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Awifiroom%3B11001?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "47bf6645e4e84c2fd430a7c0d86cfd5b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:wifiroom;11001. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1919300301?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "29e32fc8dc7542bc2b33f5f75e898212", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "279", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomWithWifiTwin1919300301. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "1237", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "8e185f086547d4eb1e1eabf418b136cb", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:wifiroom;11001\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022RoomWithWifi\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Temperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Humidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022IsOccupied\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022EmployeeId\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Component\u0022,\r\n", + " \u0022name\u0022: \u0022wifiAccessPoint\u0022,\r\n", + " \u0022schema\u0022: \u0022dtmi:example:wifi;116048137\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:wifi;116048137\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022,\r\n", + " \u0022displayName\u0022: \u0022Wifi\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022RouterName\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Network\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " }\r\n", + " ]\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "317", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:wifiroom;11001\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022RoomWithWifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.1324844\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifi;116048137\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022Wifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.1326473\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1919300301?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "348", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "2643e1488bbf8ad00204bdb03a5476a6", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:wifiroom;11001\u0022\r\n", + " },\r\n", + " \u0022Temperature\u0022: 80,\r\n", + " \u0022Humidity\u0022: 25,\r\n", + " \u0022IsOccupied\u0022: true,\r\n", + " \u0022EmployeeId\u0022: \u0022Employee1\u0022,\r\n", + " \u0022wifiAccessPoint\u0022: {\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:wifi;116048137\u0022\r\n", + " },\r\n", + " \u0022RouterName\u0022: \u0022Cisco1\u0022,\r\n", + " \u0022Network\u0022: \u0022Room1\u0022\r\n", + " }\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "1003", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u00222a3d36aa-d6a5-407d-bc59-7aaa8042ee6a\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomWithWifiTwin1919300301", + "$etag": "2a3d36aa-d6a5-407d-bc59-7aaa8042ee6a", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "wifiAccessPoint": { + "RouterName": "Cisco1", + "Network": "Room1", + "$metadata": { + "$model": "dtmi:example:wifi;116048137", + "RouterName": { + "desiredValue": "Cisco1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Network": { + "desiredValue": "Room1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + }, + "$metadata": { + "$model": "dtmi:example:wifiroom;11001", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1919300301/components/wifiAccessPoint?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0cd0ad25cde56286440e0b5630c82a79", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "322", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u00222a3d36aa-d6a5-407d-bc59-7aaa8042ee6a\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "RouterName": "Cisco1", + "Network": "Room1", + "$metadata": { + "$model": "dtmi:example:wifi;116048137", + "RouterName": { + "desiredValue": "Cisco1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Network": { + "desiredValue": "Room1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1919300301/components/wifiAccessPoint?api-version=2020-05-31-preview", + "RequestMethod": "PATCH", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "58", + "Content-Type": "application/json-patch\u002Bjson; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "7cae29fc5c457c528f8d8b43a73a9ac9", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{\u0022op\u0022:\u0022replace\u0022,\u0022path\u0022:\u0022/Network\u0022,\u0022value\u0022:\u0022New Network\u0022}]", + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u0022d17d6c8c-132e-492a-a7e8-0726934728a3\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1919300301?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6acf04a829e17be65be1e1b17f7a5a3a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Awifiroom%3B11001?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "10b344d9faa6c8615b537d574142bb09", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Awifi%3B116048137?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "2cae4273c0f8d398433221647ba1fd14", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "975366982" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ComponentTests/Component_LifecycleAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ComponentTests/Component_LifecycleAsync.json new file mode 100644 index 0000000000000..cdd627613dcbb --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ComponentTests/Component_LifecycleAsync.json @@ -0,0 +1,395 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Awifi%3B118382803?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "e27076bfefb5fe8dec7da3880213b707", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:wifi;118382803. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Awifiroom%3B19137?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "1270d29123047704a389ecc8bf053a2f", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:wifiroom;19137. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1728255304?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "b747af127265d357c1d6db0bb0164c7e", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "279", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomWithWifiTwin1728255304. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "1237", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "e9a7e26aba7b6c536a1266a1352d7768", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:wifiroom;19137\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022RoomWithWifi\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Temperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Humidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022IsOccupied\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022EmployeeId\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Component\u0022,\r\n", + " \u0022name\u0022: \u0022wifiAccessPoint\u0022,\r\n", + " \u0022schema\u0022: \u0022dtmi:example:wifi;118382803\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:wifi;118382803\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022,\r\n", + " \u0022displayName\u0022: \u0022Wifi\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022RouterName\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Network\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " }\r\n", + " ]\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "317", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:wifiroom;19137\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022RoomWithWifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.0336167\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifi;118382803\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022Wifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.0337603\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1728255304?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "348", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0701b95845bf602b193f434c296cf272", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:wifiroom;19137\u0022\r\n", + " },\r\n", + " \u0022Temperature\u0022: 80,\r\n", + " \u0022Humidity\u0022: 25,\r\n", + " \u0022IsOccupied\u0022: true,\r\n", + " \u0022EmployeeId\u0022: \u0022Employee1\u0022,\r\n", + " \u0022wifiAccessPoint\u0022: {\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:wifi;118382803\u0022\r\n", + " },\r\n", + " \u0022RouterName\u0022: \u0022Cisco1\u0022,\r\n", + " \u0022Network\u0022: \u0022Room1\u0022\r\n", + " }\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "1003", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u00223343d230-ab3d-49f6-a941-04e04d7de990\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomWithWifiTwin1728255304", + "$etag": "3343d230-ab3d-49f6-a941-04e04d7de990", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "wifiAccessPoint": { + "RouterName": "Cisco1", + "Network": "Room1", + "$metadata": { + "$model": "dtmi:example:wifi;118382803", + "RouterName": { + "desiredValue": "Cisco1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Network": { + "desiredValue": "Room1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + }, + "$metadata": { + "$model": "dtmi:example:wifiroom;19137", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1728255304/components/wifiAccessPoint?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "2354499f459258cc5cdb4d520cb59d94", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "322", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u00223343d230-ab3d-49f6-a941-04e04d7de990\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "RouterName": "Cisco1", + "Network": "Room1", + "$metadata": { + "$model": "dtmi:example:wifi;118382803", + "RouterName": { + "desiredValue": "Cisco1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Network": { + "desiredValue": "Room1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1728255304/components/wifiAccessPoint?api-version=2020-05-31-preview", + "RequestMethod": "PATCH", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "58", + "Content-Type": "application/json-patch\u002Bjson; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "f6b2725e451525bfb647d03c770642fe", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{\u0022op\u0022:\u0022replace\u0022,\u0022path\u0022:\u0022/Network\u0022,\u0022value\u0022:\u0022New Network\u0022}]", + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u00225d3eb7f4-ea2c-41ba-8f10-e5681fb83c69\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomWithWifiTwin1728255304?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "ec02f32054d813d5eda9abe3f8d85463", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Awifiroom%3B19137?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "b7edaea1fbb95a5c8a2f6c4b7490e056", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Awifi%3B118382803?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "18324f99b1b30abb9c9f096c99dc2cde", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1042416616" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinRelationshipTests/Relationships_Lifecycle.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinRelationshipTests/Relationships_Lifecycle.json new file mode 100644 index 0000000000000..38effef3d7a63 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinRelationshipTests/Relationships_Lifecycle.json @@ -0,0 +1,1091 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Afloor%3B11806305?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a07786dbb4e986bba48f725e7ff71cb8", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:floor;11806305. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B117517802?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "eff5ca509a4a3912f3ee0672eb75abd3", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:room;117517802. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/dtmi%3Aexample%3Ahvac%3B165750186?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a76ec5d354201125aa775a4ae59cc463", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "280", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID dtmi:example:hvac;165750186. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "ad905314ec906764f5c5b513b819c78a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "272", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID floorTwin1623788387. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin117216468?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "24495624752fded09f22b8ef0e52420e", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "270", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomTwin117216468. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin1855785351?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "fd435861d84240092b8e6ffdf15d92bf", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "271", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID hvacTwin1855785351. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "2492", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "196d7811e43fbfddcff1c9ac77e67373", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:floor;11806305\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022,\r\n", + " \u0022displayName\u0022: \u0022Floor\u0022,\r\n", + " \u0022description\u0022: \u0022A building story.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022contains\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:room;117517802\u0022,\r\n", + " \u0022properties\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022isAccessRestricted\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " }\r\n", + " ]\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022cooledBy\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:hvac;165750186\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022AverageTemperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " }\r\n", + " ]\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:room;117517802\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Room\u0022,\r\n", + " \u0022description\u0022: \u0022An enclosure inside a building.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022containedIn\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:floor;11806305\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Temperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Humidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022IsOccupied\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022EmployeeId\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:hvac;165750186\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022HVAC\u0022,\r\n", + " \u0022description\u0022: \u0022A heating, ventilation, and air conditioning unit.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Efficiency\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022TargetTemperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022TargetHumidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022cools\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:floor;11806305\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "583", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:floor;11806305\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A building story.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Floor\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.6169748\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:room;117517802\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022An enclosure inside a building.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Room\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.6171277\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:hvac;165750186\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A heating, ventilation, and air conditioning unit.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022HVAC\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.6172607\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "101", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6fb83005d6467de140e404e761e1adc5", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:floor;11806305\u0022\r\n", + " },\r\n", + " \u0022AverageTemperature\u0022: 75\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "273", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "ETag": "W/\u002280d157b0-a677-47aa-95ab-33aeabd8fdd8\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "floorTwin1623788387", + "$etag": "80d157b0-a677-47aa-95ab-33aeabd8fdd8", + "AverageTemperature": 75, + "$metadata": { + "$model": "dtmi:example:floor;11806305", + "AverageTemperature": { + "desiredValue": 75, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin117216468?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "166", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "d9fd2f25f4d57c487a842e510f5dc845", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:room;117517802\u0022\r\n", + " },\r\n", + " \u0022Temperature\u0022: 80,\r\n", + " \u0022Humidity\u0022: 25,\r\n", + " \u0022IsOccupied\u0022: true,\r\n", + " \u0022EmployeeId\u0022: \u0022Employee1\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "653", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "ETag": "W/\u00223ba42e39-3be6-47fb-8bca-c7e38e8379b0\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin117216468", + "$etag": "3ba42e39-3be6-47fb-8bca-c7e38e8379b0", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;117517802", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin1855785351?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "125", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "c0f7fc1b23a43a7896efd95be0f65eed", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:hvac;165750186\u0022\r\n", + " },\r\n", + " \u0022TargetTemperature\u0022: 80,\r\n", + " \u0022TargetHumidity\u0022: 25\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "404", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "ETag": "W/\u0022720f3142-2b67-4af5-bbd7-302b54e3c466\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "hvacTwin1855785351", + "$etag": "720f3142-2b67-4af5-bbd7-302b54e3c466", + "TargetTemperature": 80, + "TargetHumidity": 25, + "$metadata": { + "$model": "dtmi:example:hvac;165750186", + "TargetTemperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "TargetHumidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "116", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "4786044399e9109ee83cf4c2a8906ee3", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$targetId\u0022: \u0022roomTwin117216468\u0022,\r\n", + " \u0022$relationshipName\u0022: \u0022contains\u0022,\r\n", + " \u0022isAccessRestricted\u0022: true\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "215", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "ETag": "W/\u0022744c1ca5-87a4-4abd-a2ba-4486102182c1\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "FloorToRoomRelationship", + "$etag": "744c1ca5-87a4-4abd-a2ba-4486102182c1", + "$sourceId": "floorTwin1623788387", + "$relationshipName": "contains", + "$targetId": "roomTwin117216468", + "isAccessRestricted": true + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/relationships/FloorToHvacRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "83", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "64cbbf1bede90220b7c243e51bed9c84", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$targetId\u0022: \u0022hvacTwin1855785351\u0022,\r\n", + " \u0022$relationshipName\u0022: \u0022cooledBy\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "190", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "ETag": "W/\u0022ec6f45bb-42cd-4414-a408-cb20a8fb9a2f\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "FloorToHvacRelationship", + "$etag": "ec6f45bb-42cd-4414-a408-cb20a8fb9a2f", + "$sourceId": "floorTwin1623788387", + "$relationshipName": "cooledBy", + "$targetId": "hvacTwin1855785351" + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin1855785351/relationships/HvacToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "81", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0a0e402580d7825b5ee6d8682fb59105", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$targetId\u0022: \u0022floorTwin1623788387\u0022,\r\n", + " \u0022$relationshipName\u0022: \u0022cools\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "187", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "ETag": "W/\u00221973da68-7244-4fb4-bcc4-fb92a64fa93d\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "HvacToFloorRelationship", + "$etag": "1973da68-7244-4fb4-bcc4-fb92a64fa93d", + "$sourceId": "hvacTwin1855785351", + "$relationshipName": "cools", + "$targetId": "floorTwin1623788387" + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin117216468/relationships/RoomToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "87", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "213ff580f92a5604e383902655b8f5fb", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$targetId\u0022: \u0022floorTwin1623788387\u0022,\r\n", + " \u0022$relationshipName\u0022: \u0022containedIn\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "192", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "ETag": "W/\u00224899386a-2f5a-44b8-a68b-4880e0bdf949\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "RoomToFloorRelationship", + "$etag": "4899386a-2f5a-44b8-a68b-4880e0bdf949", + "$sourceId": "roomTwin117216468", + "$relationshipName": "containedIn", + "$targetId": "floorTwin1623788387" + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PATCH", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "60", + "Content-Type": "application/json-patch\u002Bjson; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "689c709f64829b0c6349060214b8d301", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{\u0022op\u0022:\u0022replace\u0022,\u0022path\u0022:\u0022isAccessRestricted\u0022,\u0022value\u0022:false}]", + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "ETag": "W/\u00224ffd7fce-7650-4829-83e4-91abacc3e4e2\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "25653d307bad2b593cb72653f0342ca5", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "216", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "ETag": "W/\u00224ffd7fce-7650-4829-83e4-91abacc3e4e2\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "FloorToRoomRelationship", + "$etag": "4ffd7fce-7650-4829-83e4-91abacc3e4e2", + "$sourceId": "floorTwin1623788387", + "$relationshipName": "contains", + "$targetId": "roomTwin117216468", + "isAccessRestricted": false + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/incomingrelationships?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "bec8dcf129191b82e9a4bde1f301412b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "493", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "nextLink": null, + "value": [ + { + "$relationshipId": "HvacToFloorRelationship", + "$sourceId": "hvacTwin1855785351", + "$relationshipName": "cools", + "$relationshipLink": "/digitaltwins/hvacTwin1855785351/relationships/HvacToFloorRelationship?api-version=2020-05-31-preview" + }, + { + "$relationshipId": "RoomToFloorRelationship", + "$sourceId": "roomTwin117216468", + "$relationshipName": "containedIn", + "$relationshipLink": "/digitaltwins/roomTwin117216468/relationships/RoomToFloorRelationship?api-version=2020-05-31-preview" + } + ] + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/relationships?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "18f68fb0d053244d17702cca3db9aa2e", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "435", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "nextLink": null, + "value": [ + { + "$relationshipId": "FloorToHvacRelationship", + "$etag": "ec6f45bb-42cd-4414-a408-cb20a8fb9a2f", + "$sourceId": "floorTwin1623788387", + "$relationshipName": "cooledBy", + "$targetId": "hvacTwin1855785351" + }, + { + "$relationshipId": "FloorToRoomRelationship", + "$etag": "4ffd7fce-7650-4829-83e4-91abacc3e4e2", + "$sourceId": "floorTwin1623788387", + "$relationshipName": "contains", + "$targetId": "roomTwin117216468", + "isAccessRestricted": false + } + ] + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin117216468/relationships?relationshipName=containedIn\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "3711611c14ef07e8ba493b08bd77383a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "220", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "nextLink": null, + "value": [ + { + "$relationshipId": "RoomToFloorRelationship", + "$etag": "4899386a-2f5a-44b8-a68b-4880e0bdf949", + "$sourceId": "roomTwin117216468", + "$relationshipName": "containedIn", + "$targetId": "floorTwin1623788387" + } + ] + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "61a2fb76143e20528ea3a7a8fdb8de30", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin117216468/relationships/RoomToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "92c48ff909ef9c3ba6ef5d099445679f", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/relationships/FloorToHvacRelationship?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "4154f138491608f00ef1a84b6c400a02", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin1855785351/relationships/HvacToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "2e0f0b6ba6b26c4bc006ba4fb6488b49", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0b70083c9c63b0199ebc83fe60ef2f66", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "310", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "RelationshipNotFound", + "message": "Relationship FloorToRoomRelationship not found on twin floorTwin1623788387. Please verify that the relationship id is valid and ensure that the relationship is not deleted. See section on listing relationships in the documentation http://aka.ms/adtv2twins." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin117216468/relationships/RoomToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "899e5ae4383691eca5e781108fa051c5", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "308", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "RelationshipNotFound", + "message": "Relationship RoomToFloorRelationship not found on twin roomTwin117216468. Please verify that the relationship id is valid and ensure that the relationship is not deleted. See section on listing relationships in the documentation http://aka.ms/adtv2twins." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387/relationships/FloorToHvacRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "640f5f65fecfce9ff15e8ff6234d0bd0", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "310", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "RelationshipNotFound", + "message": "Relationship FloorToHvacRelationship not found on twin floorTwin1623788387. Please verify that the relationship id is valid and ensure that the relationship is not deleted. See section on listing relationships in the documentation http://aka.ms/adtv2twins." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin1855785351/relationships/HvacToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "5c6a53d601aa03131bde657c1b0920fe", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "309", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "RelationshipNotFound", + "message": "Relationship HvacToFloorRelationship not found on twin hvacTwin1855785351. Please verify that the relationship id is valid and ensure that the relationship is not deleted. See section on listing relationships in the documentation http://aka.ms/adtv2twins." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1623788387?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0198bd6acbe0e696bbd098d7a9f66e58", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin117216468?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "3b39b0dbf436631b4b0b49f09823b2e7", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin1855785351?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "658c913e0ab50bf0bc84a1da693c5a24", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Ahvac%3B165750186?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6ba00d70e4cf75c8a234b6d482a54d97", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:05 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Afloor%3B11806305?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "1898b01d086ad1a2bf2e7fb15341fa0f", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:05 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B117517802?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "8b8024b147825918c916c380541c8916", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:05 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "214608102" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinRelationshipTests/Relationships_LifecycleAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinRelationshipTests/Relationships_LifecycleAsync.json new file mode 100644 index 0000000000000..29efc55d58847 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinRelationshipTests/Relationships_LifecycleAsync.json @@ -0,0 +1,1091 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Afloor%3B11482285?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a9d570772c2c6e5ecbf24132555affea", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:floor;11482285. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B147749854?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "b184c41cdbf5633d053f3170418f7210", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:room;147749854. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/dtmi%3Aexample%3Ahvac%3B193418897?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "62b8dd9a4ddcf4c29cf56e881a807c76", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "280", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID dtmi:example:hvac;193418897. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "1a79b0ef9481469726ec2dfd8963cf21", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "272", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID floorTwin1499886993. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin561001639?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "513121bf773fbdc258e6cedaebbfb4fa", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "270", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomTwin561001639. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin637620656?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "9396c1a048181c21b66094f713929f66", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "270", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID hvacTwin637620656. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "2492", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "445bc073af40b7395d29aec86b3b2d79", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:floor;11482285\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022,\r\n", + " \u0022displayName\u0022: \u0022Floor\u0022,\r\n", + " \u0022description\u0022: \u0022A building story.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022contains\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:room;147749854\u0022,\r\n", + " \u0022properties\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022isAccessRestricted\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " }\r\n", + " ]\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022cooledBy\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:hvac;193418897\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022AverageTemperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " }\r\n", + " ]\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:room;147749854\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Room\u0022,\r\n", + " \u0022description\u0022: \u0022An enclosure inside a building.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022containedIn\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:floor;11482285\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Temperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Humidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022IsOccupied\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022EmployeeId\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:hvac;193418897\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022HVAC\u0022,\r\n", + " \u0022description\u0022: \u0022A heating, ventilation, and air conditioning unit.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Efficiency\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022TargetTemperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022TargetHumidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022cools\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:floor;11482285\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "581", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:floor;11482285\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A building story.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Floor\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.2095615\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:room;147749854\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022An enclosure inside a building.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Room\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.2097091\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:hvac;193418897\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A heating, ventilation, and air conditioning unit.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022HVAC\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.20983\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "101", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0dc2d902138ad8a7103589162dc54553", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:floor;11482285\u0022\r\n", + " },\r\n", + " \u0022AverageTemperature\u0022: 75\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "273", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u00223a71b335-cd4d-418d-9f96-3bca6ec660e6\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "floorTwin1499886993", + "$etag": "3a71b335-cd4d-418d-9f96-3bca6ec660e6", + "AverageTemperature": 75, + "$metadata": { + "$model": "dtmi:example:floor;11482285", + "AverageTemperature": { + "desiredValue": 75, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin561001639?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "166", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "ff78742fb659f17087df35ee9a58b07b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:room;147749854\u0022\r\n", + " },\r\n", + " \u0022Temperature\u0022: 80,\r\n", + " \u0022Humidity\u0022: 25,\r\n", + " \u0022IsOccupied\u0022: true,\r\n", + " \u0022EmployeeId\u0022: \u0022Employee1\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "653", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "ETag": "W/\u002242146cc2-2194-443d-8d46-8a2164f8277a\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin561001639", + "$etag": "42146cc2-2194-443d-8d46-8a2164f8277a", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;147749854", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin637620656?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "125", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "39f41a3392cf5fdb1882340a25238998", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:hvac;193418897\u0022\r\n", + " },\r\n", + " \u0022TargetTemperature\u0022: 80,\r\n", + " \u0022TargetHumidity\u0022: 25\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "403", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "ETag": "W/\u00221b260301-bdea-44fd-aa35-7d3319ac2825\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "hvacTwin637620656", + "$etag": "1b260301-bdea-44fd-aa35-7d3319ac2825", + "TargetTemperature": 80, + "TargetHumidity": 25, + "$metadata": { + "$model": "dtmi:example:hvac;193418897", + "TargetTemperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "TargetHumidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "116", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "f7995ae42ec24c2069d185abdeb83eb8", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$targetId\u0022: \u0022roomTwin561001639\u0022,\r\n", + " \u0022$relationshipName\u0022: \u0022contains\u0022,\r\n", + " \u0022isAccessRestricted\u0022: true\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "215", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "ETag": "W/\u00223210d196-780b-46d4-946e-f870fa30b9f5\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "FloorToRoomRelationship", + "$etag": "3210d196-780b-46d4-946e-f870fa30b9f5", + "$sourceId": "floorTwin1499886993", + "$relationshipName": "contains", + "$targetId": "roomTwin561001639", + "isAccessRestricted": true + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/relationships/FloorToHvacRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "82", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "12e30e840bd19c839819e6d68265cb64", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$targetId\u0022: \u0022hvacTwin637620656\u0022,\r\n", + " \u0022$relationshipName\u0022: \u0022cooledBy\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "189", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "ETag": "W/\u0022165d5cad-01f0-4a26-9da1-1a2dd84efece\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "FloorToHvacRelationship", + "$etag": "165d5cad-01f0-4a26-9da1-1a2dd84efece", + "$sourceId": "floorTwin1499886993", + "$relationshipName": "cooledBy", + "$targetId": "hvacTwin637620656" + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin637620656/relationships/HvacToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "81", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "3f0a9d55b9be05b8faa7d0fe0c2f8060", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$targetId\u0022: \u0022floorTwin1499886993\u0022,\r\n", + " \u0022$relationshipName\u0022: \u0022cools\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "186", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "ETag": "W/\u0022220fa867-fa1f-4a80-91ce-e4226b527d82\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "HvacToFloorRelationship", + "$etag": "220fa867-fa1f-4a80-91ce-e4226b527d82", + "$sourceId": "hvacTwin637620656", + "$relationshipName": "cools", + "$targetId": "floorTwin1499886993" + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin561001639/relationships/RoomToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "87", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "16867b43763fd8c6d6fc5ea94749ca04", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$targetId\u0022: \u0022floorTwin1499886993\u0022,\r\n", + " \u0022$relationshipName\u0022: \u0022containedIn\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "192", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "ETag": "W/\u00220631d09e-5618-48a8-9818-16becc442aa1\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "RoomToFloorRelationship", + "$etag": "0631d09e-5618-48a8-9818-16becc442aa1", + "$sourceId": "roomTwin561001639", + "$relationshipName": "containedIn", + "$targetId": "floorTwin1499886993" + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "PATCH", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "60", + "Content-Type": "application/json-patch\u002Bjson; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "40562106feadcbf956dd182a3b859068", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{\u0022op\u0022:\u0022replace\u0022,\u0022path\u0022:\u0022isAccessRestricted\u0022,\u0022value\u0022:false}]", + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "ETag": "W/\u002278008e4d-b15d-48f4-a528-c020ed354195\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "06938598b5dede24d73269c15a0ebdb1", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "216", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "ETag": "W/\u002278008e4d-b15d-48f4-a528-c020ed354195\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$relationshipId": "FloorToRoomRelationship", + "$etag": "78008e4d-b15d-48f4-a528-c020ed354195", + "$sourceId": "floorTwin1499886993", + "$relationshipName": "contains", + "$targetId": "roomTwin561001639", + "isAccessRestricted": false + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/incomingrelationships?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "eaf7cbdc3fd945b282babf625e9b9c51", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "491", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "nextLink": null, + "value": [ + { + "$relationshipId": "HvacToFloorRelationship", + "$sourceId": "hvacTwin637620656", + "$relationshipName": "cools", + "$relationshipLink": "/digitaltwins/hvacTwin637620656/relationships/HvacToFloorRelationship?api-version=2020-05-31-preview" + }, + { + "$relationshipId": "RoomToFloorRelationship", + "$sourceId": "roomTwin561001639", + "$relationshipName": "containedIn", + "$relationshipLink": "/digitaltwins/roomTwin561001639/relationships/RoomToFloorRelationship?api-version=2020-05-31-preview" + } + ] + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/relationships?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "c111f56cc4b65025fc77697b95387047", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "434", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "nextLink": null, + "value": [ + { + "$relationshipId": "FloorToHvacRelationship", + "$etag": "165d5cad-01f0-4a26-9da1-1a2dd84efece", + "$sourceId": "floorTwin1499886993", + "$relationshipName": "cooledBy", + "$targetId": "hvacTwin637620656" + }, + { + "$relationshipId": "FloorToRoomRelationship", + "$etag": "78008e4d-b15d-48f4-a528-c020ed354195", + "$sourceId": "floorTwin1499886993", + "$relationshipName": "contains", + "$targetId": "roomTwin561001639", + "isAccessRestricted": false + } + ] + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin561001639/relationships?relationshipName=containedIn\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6f4e6720a58d588fd24d8424f5c2803b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "220", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "nextLink": null, + "value": [ + { + "$relationshipId": "RoomToFloorRelationship", + "$etag": "0631d09e-5618-48a8-9818-16becc442aa1", + "$sourceId": "roomTwin561001639", + "$relationshipName": "containedIn", + "$targetId": "floorTwin1499886993" + } + ] + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "65551795fbfd17faa6a7ee62d637af49", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin561001639/relationships/RoomToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "f741784a2d4dc6c366b8ef6840015b39", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/relationships/FloorToHvacRelationship?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "7de62ef60be224496c36c9e6b72c829b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin637620656/relationships/HvacToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "7cda3a9d898067ed548ffe450c92d7a5", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/relationships/FloorToRoomRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a86bb44b32513e672e1d8a1764dc0e3a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "310", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "RelationshipNotFound", + "message": "Relationship FloorToRoomRelationship not found on twin floorTwin1499886993. Please verify that the relationship id is valid and ensure that the relationship is not deleted. See section on listing relationships in the documentation http://aka.ms/adtv2twins." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin561001639/relationships/RoomToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "06ca5336de276db8407e28530c0417d9", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "308", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "RelationshipNotFound", + "message": "Relationship RoomToFloorRelationship not found on twin roomTwin561001639. Please verify that the relationship id is valid and ensure that the relationship is not deleted. See section on listing relationships in the documentation http://aka.ms/adtv2twins." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993/relationships/FloorToHvacRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "029b235ed9c06b49d39b4e63fed60378", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "310", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "RelationshipNotFound", + "message": "Relationship FloorToHvacRelationship not found on twin floorTwin1499886993. Please verify that the relationship id is valid and ensure that the relationship is not deleted. See section on listing relationships in the documentation http://aka.ms/adtv2twins." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin637620656/relationships/HvacToFloorRelationship?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "b80ec480d1c76c7efbfe68d30914322a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "308", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "RelationshipNotFound", + "message": "Relationship HvacToFloorRelationship not found on twin hvacTwin637620656. Please verify that the relationship id is valid and ensure that the relationship is not deleted. See section on listing relationships in the documentation http://aka.ms/adtv2twins." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/floorTwin1499886993?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "40b8b0050c405c79095f338c90556e69", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin561001639?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "47d2b07a5ef58d12a52f06c1717661bf", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/hvacTwin637620656?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "4d5e2368c31d74374ab2af689ef2dba6", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B147749854?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "73326053081d7e7deeb8aef227256e92", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Ahvac%3B193418897?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "5958fe8fea41a6349e2b9b1105b8ea93", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Afloor%3B11482285?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6c2374fd21f6b74b785efd42afa9efb3", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "683343334" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_IncorrectCredentials_ThrowsUnauthorizedException.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_IncorrectCredentials_ThrowsUnauthorizedException.json new file mode 100644 index 0000000000000..d7c70b90deebd --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_IncorrectCredentials_ThrowsUnauthorizedException.json @@ -0,0 +1,29 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/someNonExistantTwin?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "e4372e3f473b4caa28d4cf53148eff97", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 401, + "ResponseHeaders": { + "Content-Length": "48", + "Content-Type": "application/json", + "Date": "Fri, 29 May 2020 22:26:56 GMT" + }, + "ResponseBody": "{ \u0022statusCode\u0022: 401, \u0022message\u0022: \u0022Unauthorized\u0022 }" + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1966632250" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_IncorrectCredentials_ThrowsUnauthorizedExceptionAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_IncorrectCredentials_ThrowsUnauthorizedExceptionAsync.json new file mode 100644 index 0000000000000..9b759b7c1e94f --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_IncorrectCredentials_ThrowsUnauthorizedExceptionAsync.json @@ -0,0 +1,29 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/someNonExistantTwin?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a7b06336ce18468364aa2a2b9c7de619", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 401, + "ResponseHeaders": { + "Content-Length": "48", + "Content-Type": "application/json", + "Date": "Fri, 29 May 2020 22:26:57 GMT" + }, + "ResponseBody": "{ \u0022statusCode\u0022: 401, \u0022message\u0022: \u0022Unauthorized\u0022 }" + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1650273333" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_Lifecycle.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_Lifecycle.json new file mode 100644 index 0000000000000..2bc24f656ebc7 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_Lifecycle.json @@ -0,0 +1,375 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin1292386624?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "cc833d55fdc242f202819c53e328694a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "271", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomTwin1292386624. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Afloor%3B11991704?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "77d2c6eff1fe123f19b9f5b3df8788da", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:floor;11991704. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B115359225?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6f6dcaaf8a593513285ccb4d45da3cd5", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:room;115359225. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "870", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "19d1e09c56c9444bbaa943fd8f22fa14", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:room;115359225\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Room\u0022,\r\n", + " \u0022description\u0022: \u0022An enclosure inside a building.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022containedIn\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:floor;11991704\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Temperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Humidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022IsOccupied\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022EmployeeId\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "193", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:room;115359225\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022An enclosure inside a building.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Room\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.2985446\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin1292386624?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "166", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "9e787c78f7dd3b96bf41d59574c5d4de", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:room;115359225\u0022\r\n", + " },\r\n", + " \u0022Temperature\u0022: 80,\r\n", + " \u0022Humidity\u0022: 25,\r\n", + " \u0022IsOccupied\u0022: true,\r\n", + " \u0022EmployeeId\u0022: \u0022Employee1\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "654", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u0022a2e78aa3-3592-4893-b226-f519fa6ad025\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin1292386624", + "$etag": "a2e78aa3-3592-4893-b226-f519fa6ad025", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;115359225", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin1292386624?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a743deb8c1b7589e7e29b5b04716a505", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "654", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u0022a2e78aa3-3592-4893-b226-f519fa6ad025\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin1292386624", + "$etag": "a2e78aa3-3592-4893-b226-f519fa6ad025", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;115359225", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin1292386624?api-version=2020-05-31-preview", + "RequestMethod": "PATCH", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "131", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "c9d4b6619e62a5f74a95598780b6cff5", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{\u0022op\u0022:\u0022add\u0022,\u0022path\u0022:\u0022/Humidity\u0022,\u0022value\u0022:30},{\u0022op\u0022:\u0022replace\u0022,\u0022path\u0022:\u0022/Temperature\u0022,\u0022value\u0022:70},{\u0022op\u0022:\u0022remove\u0022,\u0022path\u0022:\u0022/EmployeeId\u0022}]", + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u00224aa468b0-06e2-4954-94b3-c1714be1d70b\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin1292386624?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "b14464d552dfb75ddd201fb441e6f4a9", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin1292386624?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "bd33d09b0bf0197ce69d5d216816d7c8", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "271", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomTwin1292386624. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B115359225?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "e2dac059f4d10f25591deb417f426364", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "972541820" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_LifecycleAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_LifecycleAsync.json new file mode 100644 index 0000000000000..35e1c679dd74d --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_LifecycleAsync.json @@ -0,0 +1,375 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin516462851?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "f5024f49bbc56e357098d6637c6de54e", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "270", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomTwin516462851. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Afloor%3B15382106?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "35a5ebe86527dd37f6d3e6de0d0c414a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:floor;15382106. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B115537104?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "df9b835336eadaae55a8dd2ecb0b0d19", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:room;115537104. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "870", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "7071111d22cdcaea17cfe74f90628c95", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:room;115537104\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Room\u0022,\r\n", + " \u0022description\u0022: \u0022An enclosure inside a building.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022containedIn\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:floor;15382106\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Temperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Humidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022IsOccupied\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022EmployeeId\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "193", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:room;115537104\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022An enclosure inside a building.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Room\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:26:59.9587367\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin516462851?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "166", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "621a10188cb2b5fef75ad1bc59af2ac8", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:room;115537104\u0022\r\n", + " },\r\n", + " \u0022Temperature\u0022: 80,\r\n", + " \u0022Humidity\u0022: 25,\r\n", + " \u0022IsOccupied\u0022: true,\r\n", + " \u0022EmployeeId\u0022: \u0022Employee1\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "653", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u0022249a1232-0005-41c6-bf37-b295e3ff46cd\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin516462851", + "$etag": "249a1232-0005-41c6-bf37-b295e3ff46cd", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;115537104", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin516462851?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "faefc4d9dad0319e99d1c81b4e5f4af2", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "653", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "ETag": "W/\u0022249a1232-0005-41c6-bf37-b295e3ff46cd\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin516462851", + "$etag": "249a1232-0005-41c6-bf37-b295e3ff46cd", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;115537104", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin516462851?api-version=2020-05-31-preview", + "RequestMethod": "PATCH", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "131", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "bb15481babf0906713bb7973502e7168", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{\u0022op\u0022:\u0022add\u0022,\u0022path\u0022:\u0022/Humidity\u0022,\u0022value\u0022:30},{\u0022op\u0022:\u0022replace\u0022,\u0022path\u0022:\u0022/Temperature\u0022,\u0022value\u0022:70},{\u0022op\u0022:\u0022remove\u0022,\u0022path\u0022:\u0022/EmployeeId\u0022}]", + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "ETag": "W/\u002201eef92f-537a-4090-95df-3de6e4542be4\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin516462851?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "cb761fa491723ec471e8c8e1c4e36697", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin516462851?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "11a0de106f992dd75d5fe714612be06b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "270", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomTwin516462851. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B115537104?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "2f765f5f7ee88a8083d74a08e285cc30", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "934257658" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_TwinNotExist_ThrowsNotFoundException.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_TwinNotExist_ThrowsNotFoundException.json new file mode 100644 index 0000000000000..f394de3f0e923 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_TwinNotExist_ThrowsNotFoundException.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/someNonExistantTwin?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "3c9f99ca5ab7bbcd1d7859b690c85db7", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "272", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID someNonExistantTwin. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1567953324" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_TwinNotExist_ThrowsNotFoundExceptionAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_TwinNotExist_ThrowsNotFoundExceptionAsync.json new file mode 100644 index 0000000000000..37dd650c9e745 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/DigitalTwinTests/DigitalTwins_TwinNotExist_ThrowsNotFoundExceptionAsync.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/someNonExistantTwin?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "fad80ca47d17c1fc7b50b1bdd349b138", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "272", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID someNonExistantTwin. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "221072636" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_EventRouteNotExist_ThrowsNotFoundException.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_EventRouteNotExist_ThrowsNotFoundException.json new file mode 100644 index 0000000000000..a68192028b97b --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_EventRouteNotExist_ThrowsNotFoundException.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someNonExistantEventRoute?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "03feab0861073c6fff6f7166ccba0ea0", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "222", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "EventRouteNotFound", + "message": "There is no route available that matches the provided input. Check for all valid event routes by calling EventRoute_List. See Swagger example (http://aka.ms/RouteSwSmpl)." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "52822797" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_EventRouteNotExist_ThrowsNotFoundExceptionAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_EventRouteNotExist_ThrowsNotFoundExceptionAsync.json new file mode 100644 index 0000000000000..1a4da98a7ffb2 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_EventRouteNotExist_ThrowsNotFoundExceptionAsync.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someNonExistantEventRoute?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "2bb1ad49af3bf3452b2bab08d20cb0cf", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "222", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "EventRouteNotFound", + "message": "There is no route available that matches the provided input. Check for all valid event routes by calling EventRoute_List. See Swagger example (http://aka.ms/RouteSwSmpl)." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "358412986" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_Lifecycle.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_Lifecycle.json new file mode 100644 index 0000000000000..fab4cdf4ca8eb --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_Lifecycle.json @@ -0,0 +1,126 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-797503071?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "165", + "Content-Type": "application/json", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "16abfcbe11b5f66e17c9bbad777fcf8b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "endpointName": "someEventHubEndpoint", + "filter": "$eventType = \u0027DigitalTwinTelemetryMessages\u0027 or $eventType = \u0027DigitalTwinLifecycleNotification\u0027" + }, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-797503071?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "4f6af9db0d558bcc747be7b654f7ca15", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "179", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:58 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022someEventRouteId-797503071\u0022,\u0022endpointName\u0022:\u0022someEventHubEndpoint\u0022,\u0022filter\u0022:\u0022$eventType = \u0027DigitalTwinTelemetryMessages\u0027 or $eventType = \u0027DigitalTwinLifecycleNotification\u0027\u0022}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "99cdb3651444fc00a97aab5dfd54577b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "388", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022value\u0022:[{\u0022id\u0022:\u0022someEventRouteId-2078359908\u0022,\u0022endpointName\u0022:\u0022someEventHubEndpoint\u0022,\u0022filter\u0022:\u0022$eventType = \u0027DigitalTwinTelemetryMessages\u0027 or $eventType = \u0027DigitalTwinLifecycleNotification\u0027\u0022},{\u0022id\u0022:\u0022someEventRouteId-797503071\u0022,\u0022endpointName\u0022:\u0022someEventHubEndpoint\u0022,\u0022filter\u0022:\u0022$eventType = \u0027DigitalTwinTelemetryMessages\u0027 or $eventType = \u0027DigitalTwinLifecycleNotification\u0027\u0022}],\u0022nextLink\u0022:null}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-797503071?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "96268a9f8244b0092f20a1392ab8a11f", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-797503071?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "c448a6fe36b1c747f96da5db626f8d20", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "222", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "EventRouteNotFound", + "message": "There is no route available that matches the provided input. Check for all valid event routes by calling EventRoute_List. See Swagger example (http://aka.ms/RouteSwSmpl)." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1558673174" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_LifecycleAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_LifecycleAsync.json new file mode 100644 index 0000000000000..704cccf749d60 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_LifecycleAsync.json @@ -0,0 +1,126 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-2078359908?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "165", + "Content-Type": "application/json", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "f6ae5985dcc767c36d7da5d5bb3b8f24", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "endpointName": "someEventHubEndpoint", + "filter": "$eventType = \u0027DigitalTwinTelemetryMessages\u0027 or $eventType = \u0027DigitalTwinLifecycleNotification\u0027" + }, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-2078359908?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "67dc5fcd49815502e6d29aa01226a45c", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "180", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022someEventRouteId-2078359908\u0022,\u0022endpointName\u0022:\u0022someEventHubEndpoint\u0022,\u0022filter\u0022:\u0022$eventType = \u0027DigitalTwinTelemetryMessages\u0027 or $eventType = \u0027DigitalTwinLifecycleNotification\u0027\u0022}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "ca6a29db55187c288ee32ecc4047cbf1", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "388", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022value\u0022:[{\u0022id\u0022:\u0022someEventRouteId-2078359908\u0022,\u0022endpointName\u0022:\u0022someEventHubEndpoint\u0022,\u0022filter\u0022:\u0022$eventType = \u0027DigitalTwinTelemetryMessages\u0027 or $eventType = \u0027DigitalTwinLifecycleNotification\u0027\u0022},{\u0022id\u0022:\u0022someEventRouteId-797503071\u0022,\u0022endpointName\u0022:\u0022someEventHubEndpoint\u0022,\u0022filter\u0022:\u0022$eventType = \u0027DigitalTwinTelemetryMessages\u0027 or $eventType = \u0027DigitalTwinLifecycleNotification\u0027\u0022}],\u0022nextLink\u0022:null}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-2078359908?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "681ac71482a73be3565810f441235546", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-2078359908?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "92fa48d9c4d1780c3760d89d1b36149e", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "222", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "EventRouteNotFound", + "message": "There is no route available that matches the provided input. Check for all valid event routes by calling EventRoute_List. See Swagger example (http://aka.ms/RouteSwSmpl)." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "654054905" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_MalformedEventRouteFilter_ThrowsBadRequestException.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_MalformedEventRouteFilter_ThrowsBadRequestException.json new file mode 100644 index 0000000000000..6831a71cb29bc --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_MalformedEventRouteFilter_ThrowsBadRequestException.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-700335504?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "84", + "Content-Type": "application/json", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "b15051a55a24abe28928345ba9759220", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "endpointName": "someEventHubEndpoint", + "filter": "this is not a valid filter string" + }, + "StatusCode": 400, + "ResponseHeaders": { + "Content-Length": "248", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:26:59 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022error\u0022:{\u0022code\u0022:\u0022EventRouteFilterInvalid\u0022,\u0022message\u0022:\u0022The provided filter is invalid. Parsing error, Line=1, Position=6, Message=Unexpected input \u0027is\u0027. See event route documentation for supported values and structure (http://aka.ms/ADTv2Routes).\u0022}}" + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "763916860" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_MalformedEventRouteFilter_ThrowsBadRequestExceptionAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_MalformedEventRouteFilter_ThrowsBadRequestExceptionAsync.json new file mode 100644 index 0000000000000..84fd8db29bac1 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/EventRouteTests/EventRoutes_MalformedEventRouteFilter_ThrowsBadRequestExceptionAsync.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/eventroutes/someEventRouteId-1181382281?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "84", + "Content-Type": "application/json", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "2cf662d2a2836cccc5d62af5555f1c9a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "endpointName": "someEventHubEndpoint", + "filter": "this is not a valid filter string" + }, + "StatusCode": 400, + "ResponseHeaders": { + "Content-Length": "248", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022error\u0022:{\u0022code\u0022:\u0022EventRouteFilterInvalid\u0022,\u0022message\u0022:\u0022The provided filter is invalid. Parsing error, Line=1, Position=6, Message=Unexpected input \u0027is\u0027. See event route documentation for supported values and structure (http://aka.ms/ADTv2Routes).\u0022}}" + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "347938930" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/ModelData_DisplayNameAndDescription_Deserializes.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/ModelData_DisplayNameAndDescription_Deserializes.json new file mode 100644 index 0000000000000..d79dd724b38e3 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/ModelData_DisplayNameAndDescription_Deserializes.json @@ -0,0 +1,127 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B121159740?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6afbb5a6dd38e3ced7b27b7ce22995a6", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "613", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022dtmi:example:Ward;121159740\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:42.8709519\u002B00:00\u0022,\u0022model\u0022:{\u0022@id\u0022:\u0022dtmi:example:Ward;121159740\u0022,\u0022@type\u0022:\u0022Interface\u0022,\u0022displayName\u0022:\u0022Ward\u0022,\u0022description\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022,\u0022contents\u0022:[{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022VisitorCount\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022HandWashPercentage\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022managedRooms\u0022}],\u0022@context\u0022:[\u0022dtmi:dtdl:context;2\u0022]}}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B120708472?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6ca626f90e2eb40042884b1a05a8839a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Ward;120708472. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "611", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "4d1baca31740cb0a30ead3d258103c27", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Ward;120708472\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Ward\u0022,\r\n", + " \u0022description\u0022: \u0022A separate partition in a building, made of rooms and hallways.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022VisitorCount\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022HandWashPercentage\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022managedRooms\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "225", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:Ward;120708472\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:02.0693692\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B120708472?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "61f82e2718eda777fab6f65483c9d20a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "613", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022dtmi:example:Ward;120708472\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:02.0693692\u002B00:00\u0022,\u0022model\u0022:{\u0022@id\u0022:\u0022dtmi:example:Ward;120708472\u0022,\u0022@type\u0022:\u0022Interface\u0022,\u0022displayName\u0022:\u0022Ward\u0022,\u0022description\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022,\u0022contents\u0022:[{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022VisitorCount\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022HandWashPercentage\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022managedRooms\u0022}],\u0022@context\u0022:[\u0022dtmi:dtdl:context;2\u0022]}}" + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "2057834569" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/ModelData_DisplayNameAndDescription_DeserializesAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/ModelData_DisplayNameAndDescription_DeserializesAsync.json new file mode 100644 index 0000000000000..fdd6c939704b9 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/ModelData_DisplayNameAndDescription_DeserializesAsync.json @@ -0,0 +1,127 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B121200167?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "ba8204258dd5c07823fc1a1051132fa1", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "613", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022dtmi:example:Ward;121200167\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:42.8841701\u002B00:00\u0022,\u0022model\u0022:{\u0022@id\u0022:\u0022dtmi:example:Ward;121200167\u0022,\u0022@type\u0022:\u0022Interface\u0022,\u0022displayName\u0022:\u0022Ward\u0022,\u0022description\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022,\u0022contents\u0022:[{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022VisitorCount\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022HandWashPercentage\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022managedRooms\u0022}],\u0022@context\u0022:[\u0022dtmi:dtdl:context;2\u0022]}}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B161147759?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "2fb5de70c1acefc6e467524bf3a1fc3b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:00 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Ward;161147759. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "611", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a0cf3f7ef3378512ddc044baf877e472", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Ward;161147759\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Ward\u0022,\r\n", + " \u0022description\u0022: \u0022A separate partition in a building, made of rooms and hallways.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022VisitorCount\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022HandWashPercentage\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022managedRooms\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "225", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:Ward;161147759\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:02.1360011\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B161147759?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6c0a6e7a33cc4279bccaf1252675305a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "613", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022dtmi:example:Ward;161147759\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:02.1360011\u002B00:00\u0022,\u0022model\u0022:{\u0022@id\u0022:\u0022dtmi:example:Ward;161147759\u0022,\u0022@type\u0022:\u0022Interface\u0022,\u0022displayName\u0022:\u0022Ward\u0022,\u0022description\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022,\u0022contents\u0022:[{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022VisitorCount\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022HandWashPercentage\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022managedRooms\u0022}],\u0022@context\u0022:[\u0022dtmi:dtdl:context;2\u0022]}}" + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "409053188" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_Lifecycle.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_Lifecycle.json new file mode 100644 index 0000000000000..71e2c055aa42c --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_Lifecycle.json @@ -0,0 +1,345 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3ABuilding%3B14778?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "348e34f8b93ab3cf849b6800e73aa7ef", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Building;14778. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AFloor%3B19666646?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "d249aa6bb1efef21c69f20c14bf66e66", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Floor;19666646. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AHvac%3B126640227?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a4186fe892bf0df0c92821df66bce4a4", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Hvac;126640227. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B165729996?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "5721e0418208456d741aaff239a5fa99", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Ward;165729996. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "2029", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "d7375106ab495817c52689ff0f5fe23b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Building;14778\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Building\u0022,\r\n", + " \u0022description\u0022: \u0022A free-standing structure.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022has\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:Floor;19666646\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022isEquippedWith\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:Hvac;126640227\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022AverageTemperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Hvac;126640227\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022HVAC\u0022,\r\n", + " \u0022description\u0022: \u0022A heating, ventilation, and air conditioning unit.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Efficiency\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022TargetTemperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022TargetHumidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022cools\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:Floor;19666646\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Ward;165729996\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Ward\u0022,\r\n", + " \u0022description\u0022: \u0022A separate partition in a building, made of rooms and hallways.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022VisitorCount\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022HandWashPercentage\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022managedRooms\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "627", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:Building;14778\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A free-standing structure.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Building\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2830182\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Hvac;126640227\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A heating, ventilation, and air conditioning unit.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022HVAC\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2831418\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;165729996\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2832482\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3ABuilding%3B14778?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "8db5521d8945ece0aa5f4b78411b9082", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "604", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022dtmi:example:Building;14778\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A free-standing structure.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Building\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2830182\u002B00:00\u0022,\u0022model\u0022:{\u0022@id\u0022:\u0022dtmi:example:Building;14778\u0022,\u0022@type\u0022:\u0022Interface\u0022,\u0022displayName\u0022:\u0022Building\u0022,\u0022description\u0022:\u0022A free-standing structure.\u0022,\u0022contents\u0022:[{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022has\u0022,\u0022target\u0022:\u0022dtmi:example:Floor;19666646\u0022},{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022isEquippedWith\u0022,\u0022target\u0022:\u0022dtmi:example:Hvac;126640227\u0022},{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022AverageTemperature\u0022,\u0022schema\u0022:\u0022double\u0022}],\u0022@context\u0022:[\u0022dtmi:dtdl:context;2\u0022]}}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?includeModelDefinition=false\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6b5f4527ccac95aec8c892e2f96d3514", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "8050", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:05 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022value\u0022:[{\u0022id\u0022:\u0022dtmi:example:wifiroom;11795\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022RoomWithWifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:40.1087098\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifi;110813340\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022Wifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:40.1093734\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifiroom;11085\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022RoomWithWifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:40.9136432\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifi;178807757\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022Wifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:40.9143412\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;121903001\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:41.5423248\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;137784739\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:43.281271\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;112421922\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:49.7910161\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;112021088\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:51.2775521\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifiroom;13376\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022RoomWithWifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:46:57.5203947\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifi;114348555\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022Wifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:46:57.5205526\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;113890337\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:50:14.8981623\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;145345511\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:50:15.0620158\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;119207084\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:50:22.5786159\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;162914014\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:50:23.4129911\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;112491866\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:58:13.5051157\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;118110353\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:58:14.1322013\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;115195109\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:58:21.5787297\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;114115543\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:58:21.8679372\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;171587792\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-28T23:13:40.3886166\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;114829098\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-28T23:13:40.7004224\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;145940630\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-28T23:13:48.1709632\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;145169011\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-28T23:13:49.3835092\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;113333312\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T19:55:02.0215043\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;111094352\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T19:55:03.4611138\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;118409140\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T19:55:09.6180506\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;111083308\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T19:55:11.9059544\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;121159740\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:42.8709519\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;121200167\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:42.8841701\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;112162783\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:49.9204159\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;147373991\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:50.4758422\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;120708472\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:02.0693692\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;161147759\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:02.1360011\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Building;19930\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A free-standing structure.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Building\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0754051\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Hvac;156543431\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A heating, ventilation, and air conditioning unit.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022HVAC\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0755043\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;129811965\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0755882\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Building;14778\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A free-standing structure.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Building\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2830182\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Hvac;126640227\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A heating, ventilation, and air conditioning unit.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022HVAC\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2831418\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;165729996\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2832482\u002B00:00\u0022}],\u0022nextLink\u0022:null}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3ABuilding%3B14778?api-version=2020-05-31-preview", + "RequestMethod": "PATCH", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "63", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "e6d574376cef7d54704b2cea609f17a9", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{ \u0022op\u0022: \u0022replace\u0022, \u0022path\u0022: \u0022/decommissioned\u0022, \u0022value\u0022: true }]", + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:05 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3ABuilding%3B14778?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "c9d806957700508ea41fc57cf6fef33d", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:06 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AHvac%3B126640227?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "cc403729a946ba93f1e2fa61a0c43529", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:06 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B165729996?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "f24ce8b16c94c014e68442d0a7d88672", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:06 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1727249490" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_LifecycleAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_LifecycleAsync.json new file mode 100644 index 0000000000000..2a0ad47aafdac --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_LifecycleAsync.json @@ -0,0 +1,345 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3ABuilding%3B19930?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "43b7ad321e2ddbd89e9633b5aef791b4", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Building;19930. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AFloor%3B11095524?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "3b29802fe31b958bf1eca834ba6bd2ff", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Floor;11095524. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AHvac%3B156543431?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "597e85768e57884e117d783e14e8b03d", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Hvac;156543431. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B129811965?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6583a9c7ca16ae2b3c322fa6e32b61b5", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Ward;129811965. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "2029", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "350b80e3d8a6dbf2b309651257dc04f8", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Building;19930\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Building\u0022,\r\n", + " \u0022description\u0022: \u0022A free-standing structure.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022has\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:Floor;11095524\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022isEquippedWith\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:Hvac;156543431\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022AverageTemperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Hvac;156543431\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022HVAC\u0022,\r\n", + " \u0022description\u0022: \u0022A heating, ventilation, and air conditioning unit.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Efficiency\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022TargetTemperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022TargetHumidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022cools\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:Floor;11095524\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "},{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Ward;129811965\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Ward\u0022,\r\n", + " \u0022description\u0022: \u0022A separate partition in a building, made of rooms and hallways.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022VisitorCount\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022HandWashPercentage\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022managedRooms\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "627", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:Building;19930\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A free-standing structure.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Building\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0754051\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Hvac;156543431\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A heating, ventilation, and air conditioning unit.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022HVAC\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0755043\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;129811965\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0755882\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3ABuilding%3B19930?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "28a4d4f7657cbb5f53ab1a5b1fe12d52", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "604", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022dtmi:example:Building;19930\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A free-standing structure.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Building\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0754051\u002B00:00\u0022,\u0022model\u0022:{\u0022@id\u0022:\u0022dtmi:example:Building;19930\u0022,\u0022@type\u0022:\u0022Interface\u0022,\u0022displayName\u0022:\u0022Building\u0022,\u0022description\u0022:\u0022A free-standing structure.\u0022,\u0022contents\u0022:[{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022has\u0022,\u0022target\u0022:\u0022dtmi:example:Floor;11095524\u0022},{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022isEquippedWith\u0022,\u0022target\u0022:\u0022dtmi:example:Hvac;156543431\u0022},{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022AverageTemperature\u0022,\u0022schema\u0022:\u0022double\u0022}],\u0022@context\u0022:[\u0022dtmi:dtdl:context;2\u0022]}}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?includeModelDefinition=false\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6731891707a4ee3fb7a8b10c6518575f", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "8242", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:05 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022value\u0022:[{\u0022id\u0022:\u0022dtmi:example:wifiroom;11795\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022RoomWithWifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:40.1087098\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifi;110813340\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022Wifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:40.1093734\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifiroom;11085\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022RoomWithWifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:40.9136432\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifi;178807757\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022Wifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:40.9143412\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;121903001\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:41.5423248\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;137784739\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:43.281271\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;112421922\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:49.7910161\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;112021088\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:45:51.2775521\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifiroom;13376\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022RoomWithWifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:46:57.5203947\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:wifi;114348555\u0022,\u0022description\u0022:{},\u0022displayName\u0022:{\u0022en\u0022:\u0022Wifi\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:46:57.5205526\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;113890337\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:50:14.8981623\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;145345511\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:50:15.0620158\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;119207084\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:50:22.5786159\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;162914014\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:50:23.4129911\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;112491866\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:58:13.5051157\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;118110353\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:58:14.1322013\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;115195109\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:58:21.5787297\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;114115543\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-26T17:58:21.8679372\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;171587792\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-28T23:13:40.3886166\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;114829098\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-28T23:13:40.7004224\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;145940630\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-28T23:13:48.1709632\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;145169011\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-28T23:13:49.3835092\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;113333312\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T19:55:02.0215043\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;111094352\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T19:55:03.4611138\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;118409140\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T19:55:09.6180506\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;111083308\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T19:55:11.9059544\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;121159740\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:42.8709519\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;121200167\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:42.8841701\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;112162783\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:49.9204159\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;147373991\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:50.4758422\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:room;117517802\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022An enclosure inside a building.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Room\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:00.6171277\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;120708472\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:02.0693692\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;161147759\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:02.1360011\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Building;19930\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A free-standing structure.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Building\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0754051\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Hvac;156543431\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A heating, ventilation, and air conditioning unit.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022HVAC\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0755043\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;129811965\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.0755882\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Building;14778\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A free-standing structure.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Building\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2830182\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Hvac;126640227\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A heating, ventilation, and air conditioning unit.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022HVAC\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2831418\u002B00:00\u0022},{\u0022id\u0022:\u0022dtmi:example:Ward;165729996\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:05.2832482\u002B00:00\u0022}],\u0022nextLink\u0022:null}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3ABuilding%3B19930?api-version=2020-05-31-preview", + "RequestMethod": "PATCH", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "63", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0faf362e39867d382050e2fbbd96bbd2", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": "[{ \u0022op\u0022: \u0022replace\u0022, \u0022path\u0022: \u0022/decommissioned\u0022, \u0022value\u0022: true }]", + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:05 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3ABuilding%3B19930?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "cefb12dc9cabef5395b571d3b352553a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:05 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AHvac%3B156543431?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "e82dbb531e31decc50b3465325433120", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:06 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B129811965?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "5330dfec881d91b4e3c07ad1c765cace", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:06 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1133739533" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_MalformedModelId_ThrowsBadRequestException.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_MalformedModelId_ThrowsBadRequestException.json new file mode 100644 index 0000000000000..d59350e5bdad6 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_MalformedModelId_ThrowsBadRequestException.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/thisIsNotAValidModelId?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0f1ea531e8c6d29f4ea206d8c2575903", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 400, + "ResponseHeaders": { + "Content-Length": "198", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:07 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "InvalidArgument", + "message": "The format of the Model ID thisIsNotAValidModelId provided is not supported. See model documentation(http://aka.ms/ADTv2Models) for supported format." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "524958857" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_MalformedModelId_ThrowsBadRequestExceptionAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_MalformedModelId_ThrowsBadRequestExceptionAsync.json new file mode 100644 index 0000000000000..7cd9f4d4e5a5d --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_MalformedModelId_ThrowsBadRequestExceptionAsync.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/thisIsNotAValidModelId?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0d102fb48bc8977a0714d47b05f81616", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 400, + "ResponseHeaders": { + "Content-Length": "198", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:07 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "InvalidArgument", + "message": "The format of the Model ID thisIsNotAValidModelId provided is not supported. See model documentation(http://aka.ms/ADTv2Models) for supported format." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "118439256" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelAlreadyExists_ThrowsConflictException.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelAlreadyExists_ThrowsConflictException.json new file mode 100644 index 0000000000000..8a510edcde919 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelAlreadyExists_ThrowsConflictException.json @@ -0,0 +1,158 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B112162783?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "013758b985a0f528c08437593b00da18", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "613", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:08 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022dtmi:example:Ward;112162783\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:49.9204159\u002B00:00\u0022,\u0022model\u0022:{\u0022@id\u0022:\u0022dtmi:example:Ward;112162783\u0022,\u0022@type\u0022:\u0022Interface\u0022,\u0022displayName\u0022:\u0022Ward\u0022,\u0022description\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022,\u0022contents\u0022:[{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022VisitorCount\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022HandWashPercentage\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022managedRooms\u0022}],\u0022@context\u0022:[\u0022dtmi:dtdl:context;2\u0022]}}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B110887268?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "867d44f4bb029be91403cb4c4c69cfe8", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:08 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Ward;110887268. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "611", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "dbc9a8a901e30166b4165371ab7567f0", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Ward;110887268\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Ward\u0022,\r\n", + " \u0022description\u0022: \u0022A separate partition in a building, made of rooms and hallways.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022VisitorCount\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022HandWashPercentage\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022managedRooms\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "225", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:09 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:Ward;110887268\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:10.1484497\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "611", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "1f817344f20d9db64e658b825ca8731b", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Ward;110887268\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Ward\u0022,\r\n", + " \u0022description\u0022: \u0022A separate partition in a building, made of rooms and hallways.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022VisitorCount\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022HandWashPercentage\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022managedRooms\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 409, + "ResponseHeaders": { + "Content-Length": "231", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:10 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelAlreadyExists", + "message": "Could not add model dtmi:example:Ward;110887268 as it already exists. Use Model_List API to view models that already exist. See the Swagger example.(http://aka.ms/ModelListSwSmpl)" + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "212362391" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelAlreadyExists_ThrowsConflictExceptionAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelAlreadyExists_ThrowsConflictExceptionAsync.json new file mode 100644 index 0000000000000..c905beb1fb141 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelAlreadyExists_ThrowsConflictExceptionAsync.json @@ -0,0 +1,158 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B147373991?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "cd298ef5613848cac63ddf611bc13868", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "613", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:08 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "{\u0022id\u0022:\u0022dtmi:example:Ward;147373991\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T20:42:50.4758422\u002B00:00\u0022,\u0022model\u0022:{\u0022@id\u0022:\u0022dtmi:example:Ward;147373991\u0022,\u0022@type\u0022:\u0022Interface\u0022,\u0022displayName\u0022:\u0022Ward\u0022,\u0022description\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022,\u0022contents\u0022:[{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022VisitorCount\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Property\u0022,\u0022name\u0022:\u0022HandWashPercentage\u0022,\u0022schema\u0022:\u0022double\u0022},{\u0022@type\u0022:\u0022Relationship\u0022,\u0022name\u0022:\u0022managedRooms\u0022}],\u0022@context\u0022:[\u0022dtmi:dtdl:context;2\u0022]}}" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3AWard%3B118301577?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a7045e4e50be504cd81fca7722e0146f", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:08 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:Ward;118301577. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "611", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "3adca63eb104e347f6ca8841269c3a41", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Ward;118301577\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Ward\u0022,\r\n", + " \u0022description\u0022: \u0022A separate partition in a building, made of rooms and hallways.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022VisitorCount\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022HandWashPercentage\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022managedRooms\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "225", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:09 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:Ward;118301577\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022A separate partition in a building, made of rooms and hallways.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Ward\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:10.0920213\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "611", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "4ada88c9e65c3e37dd7d6042ffd0a45c", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:Ward;118301577\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Ward\u0022,\r\n", + " \u0022description\u0022: \u0022A separate partition in a building, made of rooms and hallways.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022VisitorCount\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022HandWashPercentage\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022managedRooms\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 409, + "ResponseHeaders": { + "Content-Length": "231", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:10 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelAlreadyExists", + "message": "Could not add model dtmi:example:Ward;118301577 as it already exists. Use Model_List API to view models that already exist. See the Swagger example.(http://aka.ms/ModelListSwSmpl)" + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1792214466" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelNotExists_ThrowsNotFoundException.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelNotExists_ThrowsNotFoundException.json new file mode 100644 index 0000000000000..e3a1c9e73e6dd --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelNotExists_ThrowsNotFoundException.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/urn%3Adoesnotexist%3Afakemodel%3A1000?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "7adcd40f308eb811200e69d9c8f1cd65", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "216", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:10 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) urn:doesnotexist:fakemodel:1000. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1220736552" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelNotExists_ThrowsNotFoundExceptionAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelNotExists_ThrowsNotFoundExceptionAsync.json new file mode 100644 index 0000000000000..78a5cfcb1bc38 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/ModelsTests/Models_ModelNotExists_ThrowsNotFoundExceptionAsync.json @@ -0,0 +1,35 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/urn%3Adoesnotexist%3Afakemodel%3A1000?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "52a2c92543e5cbf3eff333e8988579e0", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "216", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:10 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) urn:doesnotexist:fakemodel:1000. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1370607071" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/QueryTests/Query_ValidQuery_Success.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/QueryTests/Query_ValidQuery_Success.json new file mode 100644 index 0000000000000..10121bc6ffe2e --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/QueryTests/Query_ValidQuery_Success.json @@ -0,0 +1,635 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Afloor%3B14036604?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "548551592ad0eace100bb6a559053072", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:floor;14036604. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B177323580?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "7700d087c66c71e0fa47354c2bbc9ba4", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:room;177323580. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "870", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "530f4b325a0c208f46b0209ce2459219", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:room;177323580\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Room\u0022,\r\n", + " \u0022description\u0022: \u0022An enclosure inside a building.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022containedIn\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:floor;14036604\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Temperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Humidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022IsOccupied\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022EmployeeId\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "193", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:room;177323580\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022An enclosure inside a building.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Room\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:03.7696215\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin54248529?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "ad11bcb1ed55a58be2d5e3989ee44e1a", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "652", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "ETag": "W/\u0022d4a1a993-90c7-492f-982a-4556b87c623c\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin54248529", + "$etag": "d4a1a993-90c7-492f-982a-4556b87c623c", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;177323580", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin1259202816?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "1f20ba262c4ce04031bba5448eb5b41c", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "271", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomTwin1259202816. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin1259202816?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "166", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "89ff7afbddf7845eae2985ac88a7cbd1", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:room;177323580\u0022\r\n", + " },\r\n", + " \u0022Temperature\u0022: 80,\r\n", + " \u0022Humidity\u0022: 25,\r\n", + " \u0022IsOccupied\u0022: true,\r\n", + " \u0022EmployeeId\u0022: \u0022Employee1\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "654", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "ETag": "W/\u002263caa31c-de26-46f8-b835-f8799f9d01ee\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin1259202816", + "$etag": "63caa31c-de26-46f8-b835-f8799f9d01ee", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;177323580", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/query?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "62", + "Content-Type": "application/json", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "d81fe28131f89064d1cd2331e5605420", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "query": "SELECT * FROM digitaltwins where IsOccupied = true" + }, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "5120", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "query-charge": "7.82", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "items": [ + { + "$dtId": "roomTwin1779752527", + "$etag": "93e9b083-aa42-4df6-aef0-f98bcf212755", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;118886946", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin1802870174", + "$etag": "2a3fb65d-7007-425b-b3b7-2106e12f41a8", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;113987929", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin883117343", + "$etag": "c7fe9908-9881-44ba-927e-ed056b5da128", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;113987929", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin54248529", + "$etag": "d4a1a993-90c7-492f-982a-4556b87c623c", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;177323580", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomWithWifiTwin1826980554", + "$etag": "f202ce41-9bb4-41bf-8bd1-12979ee77652", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "wifiAccessPoint": { + "RouterName": "Cisco1", + "Network": "Room1", + "$metadata": { + "$model": "dtmi:example:wifi;114348555", + "RouterName": { + "desiredValue": "Cisco1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Network": { + "desiredValue": "Room1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + }, + "$metadata": { + "$model": "dtmi:example:wifiroom;13376", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin1824991499", + "$etag": "8e40b63c-94a2-4ed4-930f-575d639cda16", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;112463466", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin882431752", + "$etag": "667d5711-fc7a-47f3-a7c0-8d516cad415d", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;112463466", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + } + ], + "continuationToken": null + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B177323580?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6aa37b2e904e48085b9c7122a7945789", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "277400192" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/QueryTests/Query_ValidQuery_SuccessAsync.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/QueryTests/Query_ValidQuery_SuccessAsync.json new file mode 100644 index 0000000000000..823830a1186b7 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/SessionRecords/QueryTests/Query_ValidQuery_SuccessAsync.json @@ -0,0 +1,635 @@ +{ + "Entries": [ + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Afloor%3B11744460?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "6fea64f07b3b6592a63d64bd08409d31", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:01 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:floor;11744460. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B117001227?includeModelDefinition=true\u0026api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "0e3719e7cc9dd3ad11d3554955beade7", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "212", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:02 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "ModelNotFound", + "message": "There is no Model(s) available that matches the provided id(s) dtmi:example:room;117001227. Check that the Model ID provided is valid by doing a Model_List API call." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "870", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "81a42b5a12eed9803563a83c68c1a815", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "[{\r\n", + " \u0022@id\u0022: \u0022dtmi:example:room;117001227\u0022,\r\n", + " \u0022@type\u0022: \u0022Interface\u0022,\r\n", + " \u0022displayName\u0022: \u0022Room\u0022,\r\n", + " \u0022description\u0022: \u0022An enclosure inside a building.\u0022,\r\n", + " \u0022contents\u0022: [\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Relationship\u0022,\r\n", + " \u0022name\u0022: \u0022containedIn\u0022,\r\n", + " \u0022target\u0022: \u0022dtmi:example:floor;11744460\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Temperature\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022Humidity\u0022,\r\n", + " \u0022schema\u0022: \u0022double\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022IsOccupied\u0022,\r\n", + " \u0022schema\u0022: \u0022boolean\u0022\r\n", + " },\r\n", + " {\r\n", + " \u0022@type\u0022: \u0022Property\u0022,\r\n", + " \u0022name\u0022: \u0022EmployeeId\u0022,\r\n", + " \u0022schema\u0022: \u0022string\u0022\r\n", + " }\r\n", + " ],\r\n", + " \u0022@context\u0022: \u0022dtmi:dtdl:context;2\u0022\r\n", + "}]" + ], + "StatusCode": 201, + "ResponseHeaders": { + "Content-Length": "192", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": "[{\u0022id\u0022:\u0022dtmi:example:room;117001227\u0022,\u0022description\u0022:{\u0022en\u0022:\u0022An enclosure inside a building.\u0022},\u0022displayName\u0022:{\u0022en\u0022:\u0022Room\u0022},\u0022decommissioned\u0022:false,\u0022uploadTime\u0022:\u00222020-05-29T22:27:03.773264\u002B00:00\u0022}]" + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin2138110373?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "a2172f6052523d989b29a83c1b517fb6", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "654", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "ETag": "W/\u0022a1d173c5-8ba1-4040-8ea4-047ee87742a5\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin2138110373", + "$etag": "a1d173c5-8ba1-4040-8ea4-047ee87742a5", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;117001227", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin129896917?api-version=2020-05-31-preview", + "RequestMethod": "GET", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "b0f914add58a5e99d83a24706a502a40", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 404, + "ResponseHeaders": { + "Content-Length": "270", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:03 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "error": { + "code": "DigitalTwinNotFound", + "message": "There is no digital twin instance that exists with the ID roomTwin129896917. Please verify that the twin id is valid and ensure that the twin is not deleted. See section on querying the twins http://aka.ms/adtv2query." + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/digitaltwins/roomTwin129896917?api-version=2020-05-31-preview", + "RequestMethod": "PUT", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "166", + "Content-Type": "application/json; charset=utf-8", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "968ef5a307450bd94352e8d79c1a1228", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": [ + "{\r\n", + " \u0022$metadata\u0022: {\r\n", + " \u0022$model\u0022: \u0022dtmi:example:room;117001227\u0022\r\n", + " },\r\n", + " \u0022Temperature\u0022: 80,\r\n", + " \u0022Humidity\u0022: 25,\r\n", + " \u0022IsOccupied\u0022: true,\r\n", + " \u0022EmployeeId\u0022: \u0022Employee1\u0022\r\n", + "}" + ], + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "653", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "ETag": "W/\u0022ad649823-0814-404c-b4b5-f419b5079f15\u0022", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "$dtId": "roomTwin129896917", + "$etag": "ad649823-0814-404c-b4b5-f419b5079f15", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;117001227", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/query?api-version=2020-05-31-preview", + "RequestMethod": "POST", + "RequestHeaders": { + "Authorization": "Sanitized", + "Content-Length": "62", + "Content-Type": "application/json", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "93139385f51c5ad57e447a1874cd30d9", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": { + "query": "SELECT * FROM digitaltwins where IsOccupied = true" + }, + "StatusCode": 200, + "ResponseHeaders": { + "Content-Length": "5120", + "Content-Type": "application/json; charset=utf-8", + "Date": "Fri, 29 May 2020 22:27:04 GMT", + "query-charge": "7.82", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": { + "items": [ + { + "$dtId": "roomTwin1779752527", + "$etag": "93e9b083-aa42-4df6-aef0-f98bcf212755", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;118886946", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin1802870174", + "$etag": "2a3fb65d-7007-425b-b3b7-2106e12f41a8", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;113987929", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin883117343", + "$etag": "c7fe9908-9881-44ba-927e-ed056b5da128", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;113987929", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin54248529", + "$etag": "d4a1a993-90c7-492f-982a-4556b87c623c", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;177323580", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomWithWifiTwin1826980554", + "$etag": "f202ce41-9bb4-41bf-8bd1-12979ee77652", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "wifiAccessPoint": { + "RouterName": "Cisco1", + "Network": "Room1", + "$metadata": { + "$model": "dtmi:example:wifi;114348555", + "RouterName": { + "desiredValue": "Cisco1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Network": { + "desiredValue": "Room1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + } + } + }, + "$metadata": { + "$model": "dtmi:example:wifiroom;13376", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin1824991499", + "$etag": "8e40b63c-94a2-4ed4-930f-575d639cda16", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;112463466", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + }, + { + "$dtId": "roomTwin882431752", + "$etag": "667d5711-fc7a-47f3-a7c0-8d516cad415d", + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "$metadata": { + "$model": "dtmi:example:room;112463466", + "Temperature": { + "desiredValue": 80, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "Humidity": { + "desiredValue": 25, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "IsOccupied": { + "desiredValue": true, + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "EmployeeId": { + "desiredValue": "Employee1", + "desiredVersion": 1, + "ackVersion": 1, + "ackCode": 200, + "ackDescription": "Auto-Sync" + }, + "$kind": "DigitalTwin" + } + } + ], + "continuationToken": null + } + }, + { + "RequestUri": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net/models/dtmi%3Aexample%3Aroom%3B117001227?api-version=2020-05-31-preview", + "RequestMethod": "DELETE", + "RequestHeaders": { + "Authorization": "Sanitized", + "User-Agent": [ + "azsdk-net-DigitalTwins.Core/1.0.0-dev.20200529.1", + "(.NET Core 4.6.28801.04; Microsoft Windows 10.0.18363 )" + ], + "x-ms-client-request-id": "5b77fc7e20f0a6903bed6c37ecc1c1be", + "x-ms-return-client-request-id": "true" + }, + "RequestBody": null, + "StatusCode": 204, + "ResponseHeaders": { + "Content-Length": "0", + "Date": "Fri, 29 May 2020 22:27:05 GMT", + "Strict-Transport-Security": "max-age=2592000" + }, + "ResponseBody": [] + } + ], + "Variables": { + "DIGITALTWINS_URL": "https://vinadttests.api.scus.pp.azuredigitaltwins-ppe.net", + "RandomSeed": "1812632980" + } +} \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssetSettings.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssetSettings.cs new file mode 100644 index 0000000000000..f266b8c2a4f36 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssetSettings.cs @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using Microsoft.Extensions.Configuration; + +namespace Azure.DigitalTwins.Core.Tests +{ + /// + /// These are the settings that will be used by the end-to-end tests tests. + /// The json files configured in the config will load the settings specific to a user. + /// + public class TestAssetSettings + { + public static TestAssetSettings Instance { get; private set; } + + /// + /// Default Floor Twin Id prefix. + /// + public const string FloorTwinIdPrefix = "floorTwin"; + + /// + /// Default Room Twin Id prefix. + /// + public const string RoomTwinIdPrefix = "roomTwin"; + + /// + /// Default Hvac Twin Id prefix. + /// + public const string HvacTwinIdPrefix = "hvacTwin"; + + /// + /// Default Room with Wifi Twin Id prefix. + /// + public const string RoomWithWifiTwinIdPrefix = "roomWithWifiTwin"; + + /// + /// Default Wifi model Id prefix. + /// + public const string WifiModelIdPrefix = "dtmi:example:wifi;1"; + + /// + /// Default Room model Id prefix. + /// + public const string RoomModelIdPrefix = "dtmi:example:room;1"; + + /// + /// Default Floor model Id prefix. + /// + public const string FloorModelIdPrefix = "dtmi:example:floor;1"; + + /// + /// Default Hvac model Id prefix. + /// + public const string HvacModelIdPrefix = "dtmi:example:hvac;1"; + + /// + /// Default Room with Wifi model Id prefix. + /// + public const string RoomWithWifiModelIdPrefix = "dtmi:example:wifiroom;1"; + + /// + /// Default Floor Model Id. + /// + public string FloorModelId { get; set; } + + /// + /// Default Room Model Id. + /// + public string RoomModelId { get; set; } + + /// + /// Default Hvac Model Id. + /// + public string HvacModelId { get; set; } + + /// + /// Default Building Model Id. + /// + public string BuildingModelId { get; set; } + + /// + /// Default Ward Model Id. + /// + public string WardModelId { get; set; } + + static TestAssetSettings() + { + if (Instance != null) + { + return; + } + + // Initialize the settings related to test assets - Models and IDs + var testsAssetSettingsConfigBuilder = new ConfigurationBuilder(); + + string testAssetSettingsCommonPath = Path.Combine( + TestSettings.Instance.WorkingDirectory, + "config", + "common.test.assets.config.json"); + testsAssetSettingsConfigBuilder.AddJsonFile(testAssetSettingsCommonPath); + + string testAssetSettingsUserPath = Path.Combine( + TestSettings.Instance.WorkingDirectory, + "config", + $"{Environment.UserName}.test.assets.config.json"); + if (File.Exists(testAssetSettingsUserPath)) + { + testsAssetSettingsConfigBuilder.AddJsonFile(testAssetSettingsUserPath); + } + + IConfiguration config = testsAssetSettingsConfigBuilder.Build(); + + Instance = config.Get(); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssets.Designer.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssets.Designer.cs new file mode 100644 index 0000000000000..ebb84bb8dfa12 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssets.Designer.cs @@ -0,0 +1,349 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Azure.DigitalTwins.Core.Tests { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class TestAssets { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal TestAssets() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Azure.DigitalTwins.Core.Tests.TestAssets", typeof(TestAssets).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to { + /// "@id": "BUILDING_MODEL_ID", + /// "@type": "Interface", + /// "displayName": "Building", + /// "description": "A free-standing structure.", + /// "contents": [ + /// { + /// "@type": "Relationship", + /// "name": "has", + /// "target": "FLOOR_MODEL_ID" + /// }, + /// { + /// "@type": "Relationship", + /// "name": "isEquippedWith", + /// "target": "HVAC_MODEL_ID" + /// }, + /// { + /// "@type": "Property", + /// "name": "AverageTempera [rest of string was truncated]";. + /// + internal static string BuildingModelPayload { + get { + return ResourceManager.GetString("BuildingModelPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "@id": "FLOOR_MODEL_ID", + /// "@type": "Interface", + /// "@context": "dtmi:dtdl:context;2", + /// "displayName": "Floor", + /// "description": "A building story.", + /// "contents": [ + /// { + /// "@type": "Relationship", + /// "name": "contains", + /// "target": "ROOM_MODEL_ID", + /// "properties": [ + /// { + /// "@type": "Property", + /// "name": "isAccessRestricted", + /// "schema": "boolean" + /// } + /// [rest of string was truncated]";. + /// + internal static string FloorModelPayload { + get { + return ResourceManager.GetString("FloorModelPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "$metadata": { + /// "$model": "FLOOR_MODEL_ID" + /// }, + /// "AverageTemperature": 75 + ///}. + /// + internal static string FloorTwinPayload { + get { + return ResourceManager.GetString("FloorTwinPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "@id": "HVAC_MODEL_ID", + /// "@type": "Interface", + /// "displayName": "HVAC", + /// "description": "A heating, ventilation, and air conditioning unit.", + /// "contents": [ + /// { + /// "@type": "Property", + /// "name": "Efficiency", + /// "schema": "double" + /// }, + /// { + /// "@type": "Property", + /// "name": "TargetTemperature", + /// "schema": "double" + /// }, + /// { + /// "@type": "Property", + /// "name": "TargetHumid [rest of string was truncated]";. + /// + internal static string HvacModelPayload { + get { + return ResourceManager.GetString("HvacModelPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "$metadata": { + /// "$model": "HVAC_MODEL_ID" + /// }, + /// "TargetTemperature": 80, + /// "TargetHumidity": 25 + ///}. + /// + internal static string HvacTwinPayload { + get { + return ResourceManager.GetString("HvacTwinPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "$targetId": "TARGET_TWIN_ID", + /// "$relationshipName": "RELATIONSHIP_NAME" + ///}. + /// + internal static string RelationshipPayload { + get { + return ResourceManager.GetString("RelationshipPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "$targetId": "TARGET_TWIN_ID", + /// "$relationshipName": "RELATIONSHIP_NAME", + /// "PROPERTY_NAME": "PROPERTY_VALUE" + ///}. + /// + internal static string RelationshipWithPropertyPayload { + get { + return ResourceManager.GetString("RelationshipWithPropertyPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "@id": "ROOM_MODEL_ID", + /// "@type": "Interface", + /// "displayName": "Room", + /// "description": "An enclosure inside a building.", + /// "contents": [ + /// { + /// "@type": "Relationship", + /// "name": "containedIn", + /// "target": "FLOOR_MODEL_ID" + /// }, + /// { + /// "@type": "Property", + /// "name": "Temperature", + /// "schema": "double" + /// }, + /// { + /// "@type": "Property", + /// "name": "Humidity", + /// [rest of string was truncated]";. + /// + internal static string RoomModelPayload { + get { + return ResourceManager.GetString("RoomModelPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "$metadata": { + /// "$model": "ROOM_MODEL_ID" + /// }, + /// "Temperature": 80, + /// "Humidity": 25, + /// "IsOccupied": true, + /// "EmployeeId": "Employee1" + ///}. + /// + internal static string RoomTwinPayload { + get { + return ResourceManager.GetString("RoomTwinPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "@id": "ROOM_WITH_WIFI_MODEL_ID", + /// "@type": "Interface", + /// "displayName": "RoomWithWifi", + /// "contents": [ + /// { + /// "@type": "Property", + /// "name": "Temperature", + /// "schema": "double" + /// }, + /// { + /// "@type": "Property", + /// "name": "Humidity", + /// "schema": "double" + /// }, + /// { + /// "@type": "Property", + /// "name": "IsOccupied", + /// "schema": "boolean" + /// }, + /// { + /// [rest of string was truncated]";. + /// + internal static string RoomWithWifiModelPayload { + get { + return ResourceManager.GetString("RoomWithWifiModelPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "$metadata": { + /// "$model": "ROOM_WITH_WIFI_MODEL_ID" + /// }, + /// "Temperature": 80, + /// "Humidity": 25, + /// "IsOccupied": true, + /// "EmployeeId": "Employee1", + /// "WIFI_COMPONENT_NAME": { + /// "$metadata": { + /// "$model": "WIFI_MODEL_ID" + /// }, + /// "RouterName": "Cisco1", + /// "Network": "Room1" + /// } + ///}. + /// + internal static string RoomWithWifiTwinPayload { + get { + return ResourceManager.GetString("RoomWithWifiTwinPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "@id": "WARD_MODEL_ID", + /// "@type": "Interface", + /// "displayName": "Ward", + /// "description": "A separate partition in a building, made of rooms and hallways.", + /// "contents": [ + /// { + /// "@type": "Property", + /// "name": "VisitorCount", + /// "schema": "double" + /// }, + /// { + /// "@type": "Property", + /// "name": "HandWashPercentage", + /// "schema": "double" + /// }, + /// { + /// "@type": "Relationship", + /// [rest of string was truncated]";. + /// + internal static string WardModelPayload { + get { + return ResourceManager.GetString("WardModelPayload", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to { + /// "@id": "WIFI_MODEL_ID", + /// "@type": "Interface", + /// "@context": "dtmi:dtdl:context;2", + /// "displayName": "Wifi", + /// "contents": [ + /// { + /// "@type": "Property", + /// "name": "RouterName", + /// "schema": "string" + /// }, + /// { + /// "@type": "Property", + /// "name": "Network", + /// "schema": "string" + /// } + /// ] + ///}. + /// + internal static string WifiModelPayload { + get { + return ResourceManager.GetString("WifiModelPayload", resourceCulture); + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssets.resx b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssets.resx new file mode 100644 index 0000000000000..68cd869dc2ae0 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssets.resx @@ -0,0 +1,385 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + { + "@id": "BUILDING_MODEL_ID", + "@type": "Interface", + "displayName": "Building", + "description": "A free-standing structure.", + "contents": [ + { + "@type": "Relationship", + "name": "has", + "target": "FLOOR_MODEL_ID" + }, + { + "@type": "Relationship", + "name": "isEquippedWith", + "target": "HVAC_MODEL_ID" + }, + { + "@type": "Property", + "name": "AverageTemperature", + "schema": "double" + } + ], + "@context": "dtmi:dtdl:context;2" +} + + + { + "@id": "FLOOR_MODEL_ID", + "@type": "Interface", + "@context": "dtmi:dtdl:context;2", + "displayName": "Floor", + "description": "A building story.", + "contents": [ + { + "@type": "Relationship", + "name": "contains", + "target": "ROOM_MODEL_ID", + "properties": [ + { + "@type": "Property", + "name": "isAccessRestricted", + "schema": "boolean" + } + ] + }, + { + "@type": "Relationship", + "name": "cooledBy", + "target": "HVAC_MODEL_ID" + }, + { + "@type": "Property", + "name": "AverageTemperature", + "schema": "double" + } + ] +} + + + { + "$metadata": { + "$model": "FLOOR_MODEL_ID" + }, + "AverageTemperature": 75 +} + + + { + "@id": "HVAC_MODEL_ID", + "@type": "Interface", + "displayName": "HVAC", + "description": "A heating, ventilation, and air conditioning unit.", + "contents": [ + { + "@type": "Property", + "name": "Efficiency", + "schema": "double" + }, + { + "@type": "Property", + "name": "TargetTemperature", + "schema": "double" + }, + { + "@type": "Property", + "name": "TargetHumidity", + "schema": "double" + }, + { + "@type": "Relationship", + "name": "cools", + "target": "FLOOR_MODEL_ID" + } + ], + "@context": "dtmi:dtdl:context;2" +} + + + { + "$metadata": { + "$model": "HVAC_MODEL_ID" + }, + "TargetTemperature": 80, + "TargetHumidity": 25 +} + + + { + "$targetId": "TARGET_TWIN_ID", + "$relationshipName": "RELATIONSHIP_NAME" +} + + + { + "$targetId": "TARGET_TWIN_ID", + "$relationshipName": "RELATIONSHIP_NAME", + "PROPERTY_NAME": "PROPERTY_VALUE" +} + + + { + "@id": "ROOM_MODEL_ID", + "@type": "Interface", + "displayName": "Room", + "description": "An enclosure inside a building.", + "contents": [ + { + "@type": "Relationship", + "name": "containedIn", + "target": "FLOOR_MODEL_ID" + }, + { + "@type": "Property", + "name": "Temperature", + "schema": "double" + }, + { + "@type": "Property", + "name": "Humidity", + "schema": "double" + }, + { + "@type": "Property", + "name": "IsOccupied", + "schema": "boolean" + }, + { + "@type": "Property", + "name": "EmployeeId", + "schema": "string" + } + ], + "@context": "dtmi:dtdl:context;2" +} + + + { + "$metadata": { + "$model": "ROOM_MODEL_ID" + }, + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1" +} + + + { + "@id": "ROOM_WITH_WIFI_MODEL_ID", + "@type": "Interface", + "displayName": "RoomWithWifi", + "contents": [ + { + "@type": "Property", + "name": "Temperature", + "schema": "double" + }, + { + "@type": "Property", + "name": "Humidity", + "schema": "double" + }, + { + "@type": "Property", + "name": "IsOccupied", + "schema": "boolean" + }, + { + "@type": "Property", + "name": "EmployeeId", + "schema": "string" + }, + { + "@type": "Component", + "name": "WIFI_COMPONENT_NAME", + "schema": "WIFI_MODEL_ID" + } + ], + "@context": "dtmi:dtdl:context;2" +} + + + { + "$metadata": { + "$model": "ROOM_WITH_WIFI_MODEL_ID" + }, + "Temperature": 80, + "Humidity": 25, + "IsOccupied": true, + "EmployeeId": "Employee1", + "WIFI_COMPONENT_NAME": { + "$metadata": { + "$model": "WIFI_MODEL_ID" + }, + "RouterName": "Cisco1", + "Network": "Room1" + } +} + + + { + "@id": "WARD_MODEL_ID", + "@type": "Interface", + "displayName": "Ward", + "description": "A separate partition in a building, made of rooms and hallways.", + "contents": [ + { + "@type": "Property", + "name": "VisitorCount", + "schema": "double" + }, + { + "@type": "Property", + "name": "HandWashPercentage", + "schema": "double" + }, + { + "@type": "Relationship", + "name": "managedRooms" + } + ], + "@context": "dtmi:dtdl:context;2" +} + + + { + "@id": "WIFI_MODEL_ID", + "@type": "Interface", + "@context": "dtmi:dtdl:context;2", + "displayName": "Wifi", + "contents": [ + { + "@type": "Property", + "name": "RouterName", + "schema": "string" + }, + { + "@type": "Property", + "name": "Network", + "schema": "string" + } + ] +} + + \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssetsHelper.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssetsHelper.cs new file mode 100644 index 0000000000000..6005e1ad11062 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestAssetsHelper.cs @@ -0,0 +1,120 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using Azure.DigitalTwins.Core.Serialization; + +namespace Azure.DigitalTwins.Core.Tests +{ + public static class TestAssetsHelper + { + public static string GetFloorModelPayload(string floorModelId, string roomModelId, string hvacModelId) + { + return TestAssets.FloorModelPayload + .Replace("FLOOR_MODEL_ID", floorModelId) + .Replace("ROOM_MODEL_ID", roomModelId) + .Replace("HVAC_MODEL_ID", hvacModelId); + } + + public static string GetRoomModelPayload(string roomModelId, string floorModelId) + { + return TestAssets.RoomModelPayload + .Replace("ROOM_MODEL_ID", roomModelId) + .Replace("FLOOR_MODEL_ID", floorModelId); + } + + public static string GetHvacModelPayload(string hvacModelId, string floorModelId) + { + return TestAssets.HvacModelPayload + .Replace("HVAC_MODEL_ID", hvacModelId) + .Replace("FLOOR_MODEL_ID", floorModelId); + } + + public static string GetBuildingModelPayload(string buildingModelId, string hvacModelId, string floorModelId) + { + return TestAssets.BuildingModelPayload + .Replace("BUILDING_MODEL_ID", buildingModelId) + .Replace("HVAC_MODEL_ID", hvacModelId) + .Replace("FLOOR_MODEL_ID", floorModelId); + } + + public static string GetWardModelPayload(string wardModelId) + { + return TestAssets.WardModelPayload.Replace("WARD_MODEL_ID", wardModelId); + } + + public static string GetRoomTwinUpdatePayload() + { + var uou = new UpdateOperationsUtility(); + uou.AppendAddOp("/Humidity", 30); + uou.AppendReplaceOp("/Temperature", 70); + uou.AppendRemoveOp("/EmployeeId"); + return uou.Serialize(); + } + + public static string GetWifiComponentUpdatePayload() + { + var uou = new UpdateOperationsUtility(); + uou.AppendReplaceOp("/Network", "New Network"); + return uou.Serialize(); + } + + public static string GetFloorTwinPayload(string floorModelId) + { + return TestAssets.FloorTwinPayload.Replace("FLOOR_MODEL_ID", floorModelId); + } + + public static string GetRoomTwinPayload(string roomModelId) + { + return TestAssets.RoomTwinPayload.Replace("ROOM_MODEL_ID", roomModelId); + } + + public static string GetRelationshipPayload(string targetTwinId, string relationshipName) + { + return TestAssets.RelationshipPayload + .Replace("TARGET_TWIN_ID", targetTwinId) + .Replace("RELATIONSHIP_NAME", relationshipName); + } + + public static string GetRelationshipWithPropertyPayload(string targetTwinId, string relationshipName, string propertyName, bool propertyValue) + { + return TestAssets.RelationshipWithPropertyPayload + .Replace("TARGET_TWIN_ID", targetTwinId) + .Replace("RELATIONSHIP_NAME", relationshipName) + .Replace("PROPERTY_NAME", propertyName) + .Replace("\"PROPERTY_VALUE\"", propertyValue.ToString().ToLower()); + } + + public static string GetRelationshipUpdatePayload(string propertyName, bool propertyValue) + { + var uou = new UpdateOperationsUtility(); + uou.AppendReplaceOp(propertyName, propertyValue); + return uou.Serialize(); + } + + public static string GetWifiModelPayload(string wifiModelId) + { + return TestAssets.WifiModelPayload.Replace("WIFI_MODEL_ID", wifiModelId); + } + + public static string GetRoomWithWifiModelPayload(string roomWithWifiModelId, string wifiModelId, string wifiComponentName) + { + return TestAssets.RoomWithWifiModelPayload + .Replace("ROOM_WITH_WIFI_MODEL_ID", roomWithWifiModelId) + .Replace("WIFI_MODEL_ID", wifiModelId) + .Replace("WIFI_COMPONENT_NAME", wifiComponentName); + } + + public static string GetRoomWithWifiTwinPayload(string roomWithWifiModelId, string wifiModelId, string wifiComponentName) + { + return TestAssets.RoomWithWifiTwinPayload + .Replace("ROOM_WITH_WIFI_MODEL_ID", roomWithWifiModelId) + .Replace("WIFI_MODEL_ID", wifiModelId) + .Replace("WIFI_COMPONENT_NAME", wifiComponentName); + } + + public static string GetHvacTwinPayload(string hvacModelId) + { + return TestAssets.HvacTwinPayload.Replace("HVAC_MODEL_ID", hvacModelId); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestSettings.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestSettings.cs new file mode 100644 index 0000000000000..4572c7033f88e --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/TestSettings.cs @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.IO; +using System.Reflection; +using Azure.Core.TestFramework; +using Microsoft.Extensions.Configuration; + +namespace Azure.DigitalTwins.Core.Tests +{ + /// + /// These are the settings that will be used by the end-to-end tests tests. + /// The json files configured in the config will load the settings specific to a user. + /// + public class TestSettings + { + public const string AdtEnvironmentVariablesPrefix = "DIGITALTWINS"; + + // If these environment variables exist in the environment, their values will replace (supersede) config.json values. + + private static readonly string s_adtInstanceEndpointUrlEnv = $"{AdtEnvironmentVariablesPrefix}_ADT_INSTANCE_ENDPOINT_URL"; + private static readonly string s_applicationTenantIdEnv = $"{AdtEnvironmentVariablesPrefix}_TENANT_ID"; + private static readonly string s_applicationClientIdEnv = $"{AdtEnvironmentVariablesPrefix}_CLIENT_ID"; + private static readonly string s_applicationClientSecretEnv = $"{AdtEnvironmentVariablesPrefix}_CLIENT_SECRET"; + private static readonly string s_digitalTwinHostnameEnv = $"{AdtEnvironmentVariablesPrefix}_URL"; + + public static TestSettings Instance { get; private set; } + + public RecordedTestMode TestMode { get; set; } + + /// + /// The working directory of the tests. + /// + public string WorkingDirectory { get; private set; } + + /// + /// Host name of the digital twin instance to connect to. + /// + public string DigitalTwinsInstanceHostName { get; set; } + + /// + /// Application ID created to authenticate to the digital twin instance. + /// + public string ApplicationId { get; set; } + + /// + /// Application registration client secret. + /// + public string ClientSecret { get; set; } + + /// + /// Microsoft tenent ID. + /// + public string MicrosoftTenantId { get; set; } + + /// + /// The audience of digital twin for which we need to get an access token. + /// + public string DigitalTwinsAudience { get; set; } + + static TestSettings() + { + if (Instance != null) + { + return; + } + + string codeBase = Assembly.GetExecutingAssembly().CodeBase; + var uri = new UriBuilder(codeBase); + string path = Uri.UnescapeDataString(uri.Path); + string workingDirectory = Path.GetDirectoryName(path); + + string userName = Environment.UserName; + + // Initialize the settings related to DT instance and auth + var testSettingsConfigBuilder = new ConfigurationBuilder(); + + string testSettingsCommonPath = Path.Combine(workingDirectory, "config", "common.config.json"); + testSettingsConfigBuilder.AddJsonFile(testSettingsCommonPath); + + string testSettingsUserPath = Path.Combine(workingDirectory, "config", $"{userName}.config.json"); + if (File.Exists(testSettingsUserPath)) + { + testSettingsConfigBuilder.AddJsonFile(testSettingsUserPath); + } + + IConfiguration config = testSettingsConfigBuilder.Build(); + + Instance = config.Get(); + Instance.WorkingDirectory = workingDirectory; + + // We will override settings if they can be found in the environment variables. + OverrideFromEnvVariables(); + } + + private static void OverrideFromEnvVariables() + { + string envAdtEndpoint = Environment.GetEnvironmentVariable(s_adtInstanceEndpointUrlEnv); + if (!string.IsNullOrWhiteSpace(envAdtEndpoint)) + { + Instance.DigitalTwinsInstanceHostName = envAdtEndpoint; + } + + // Add the following three values to Environment Variables(if not present) as the test framework expects these to be present. + + string envTenantId = Environment.GetEnvironmentVariable(s_applicationTenantIdEnv); + if (!string.IsNullOrWhiteSpace(envTenantId)) + { + Instance.MicrosoftTenantId = envTenantId; + } + else + { + Environment.SetEnvironmentVariable(s_applicationTenantIdEnv, Instance.MicrosoftTenantId); + } + + string envApplicationId = Environment.GetEnvironmentVariable(s_applicationClientIdEnv); + if (!string.IsNullOrWhiteSpace(envApplicationId)) + { + Instance.ApplicationId = envApplicationId; + } + else + { + Environment.SetEnvironmentVariable(s_applicationClientIdEnv, Instance.ApplicationId); + } + + string envClientSecret = Environment.GetEnvironmentVariable(s_applicationClientSecretEnv); + if (!string.IsNullOrWhiteSpace(envClientSecret)) + { + Instance.ClientSecret = envClientSecret; + } + else + { + Environment.SetEnvironmentVariable(s_applicationClientSecretEnv, Instance.ClientSecret); + } + + string digitalTwinHostname = Environment.GetEnvironmentVariable(s_digitalTwinHostnameEnv); + if (!string.IsNullOrWhiteSpace(digitalTwinHostname)) + { + Instance.DigitalTwinsInstanceHostName = digitalTwinHostname; + } + else + { + Environment.SetEnvironmentVariable(s_digitalTwinHostnameEnv, Instance.DigitalTwinsInstanceHostName); + } + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/UpdateOperationsUtilityUnitTests.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/UpdateOperationsUtilityUnitTests.cs new file mode 100644 index 0000000000000..716a7737a470c --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/UpdateOperationsUtilityUnitTests.cs @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System.Text.Json; +using Azure.DigitalTwins.Core.Serialization; +using FluentAssertions; +using NUnit.Framework; + +namespace Azure.DigitalTwins.Core.Tests +{ + [Category("Unit")] + [Parallelizable(ParallelScope.All)] + public class UpdateOperationsUtilityUnitTests + { + [Test] + public void UpdateOperationsUtility_BuildAdd() + { + // arrange + + const string addOp = "add"; + const string replaceOp = "replace"; + const string removeOp = "remove"; + + const string addPath = "/addComponentPath123"; + const string addValue = "value123"; + const string replacePath = "/replaceComponentPath123"; + const string replaceValue = "value456"; + const string removePath = "/removeComponentPath123"; + + var dtUpdateUtility = new UpdateOperationsUtility(); + dtUpdateUtility.AppendAddOp(addPath, addValue); + dtUpdateUtility.AppendReplaceOp(replacePath, replaceValue); + dtUpdateUtility.AppendRemoveOp(removePath); + + // act + string actual = dtUpdateUtility.Serialize(); + + // assert + + JsonDocument parsed = JsonDocument.Parse(actual); + parsed.RootElement.ValueKind.Should().Be(JsonValueKind.Array, "operations should be nested in an array"); + parsed.RootElement.GetArrayLength().Should().Be(3, "three operations were included"); + + JsonElement addElement = parsed.RootElement[0]; + addElement.GetProperty("op").GetString().Should().Be(addOp); + addElement.GetProperty("path").GetString().Should().Be(addPath); + addElement.GetProperty("value").GetString().Should().Be(addValue); + + JsonElement replaceElement = parsed.RootElement[1]; + replaceElement.GetProperty("op").GetString().Should().Be(replaceOp); + replaceElement.GetProperty("path").GetString().Should().Be(replacePath); + replaceElement.GetProperty("value").GetString().Should().Be(replaceValue); + + JsonElement removeElement = parsed.RootElement[2]; + removeElement.GetProperty("op").GetString().Should().Be(removeOp); + removeElement.GetProperty("path").GetString().Should().Be(removePath); + removeElement.TryGetProperty("value", out _).Should().BeFalse(); + } + } +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/UpdateSessionRecords.ps1 b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/UpdateSessionRecords.ps1 new file mode 100644 index 0000000000000..23c2c8b715abc --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/UpdateSessionRecords.ps1 @@ -0,0 +1 @@ +dotnet msbuild /t:UpdateSessionRecords \ No newline at end of file diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/config/common.config.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/config/common.config.json new file mode 100644 index 0000000000000..8d4f9f922eb12 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/config/common.config.json @@ -0,0 +1,5 @@ +{ + "MicrosoftTenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47", + "DigitalTwinsInstanceHostName": "https://common.api.scus.pp.azuredigitaltwins-ppe.net", + "TestMode": "Live" +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/config/common.test.assets.config.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/config/common.test.assets.config.json new file mode 100644 index 0000000000000..a844283427372 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/config/common.test.assets.config.json @@ -0,0 +1,8 @@ +{ + "FloorModelId": "dtmi:example:Floor;1", + "RoomModelId": "dtmi:example:Room;1", + "RoomWithWifiModelId": "dtmi:example:Room;1", + "HvacModelId": "dtmi:example:Hvac;1", + "BuildingModelId": "dtmi:example:Building;1", + "WardModelId": "dtmi:example:Ward;1" +} diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/manifest.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/manifest.json new file mode 100644 index 0000000000000..aed13ea83bbd6 --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/manifest.json @@ -0,0 +1,9 @@ +[{ + "resourceAppId": "0b07f429-9f4b-4714-9392-cc5e8e80c8b0", + "resourceAccess": [ + { + "id": "4589bd03-58cb-4e6c-b17f-b580e39652f8", + "type": "Scope" + } + ] +}] diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/prerequisite readme.md b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/prerequisite readme.md new file mode 100644 index 0000000000000..71ec90302bb6a --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/prerequisite readme.md @@ -0,0 +1,39 @@ +# Prerequisites + +## Install + +### 1. Install the latest Azure CLI package + +- If already installed, check latest version: + - Run `az --version` to make sure `azure-cli` is at least **version 2.0.8** + - If it isn't, update it +- Use this link to install [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest]) + +### 2. Install the ADT extension + +ADT's CLI commands are not standard in the Azure CLI package yet, so you must first download the latest extension + +- Download the [latest snapshot](https://github.com/Azure/azure-digital-twins/tree/private-preview/CLI) of the ADT enabled IoT CLI extension (a .whl file) +- Open Windows Powershell at the location you downloaded the extension to +- Run `az extension list` + - If you have **azure-iot** or **azure-cli-iot-ext** installed, remove both with `az extension remove --name azure-iot` (current alias) and `az extension remove --name azure-cli-iot-ext` (legacy alias) +- Add the new extension with `az extension add -y --source ` +- See the top-level ADT commands with `az dt -h` + +### 3. Whitelist subscription + +To access the digital twins service in your subscription, it must be whitelisted for private preview access. Ask on Teams for a contact. + +## Delete + +To delete the digital twins instance, you need to first delete the endpoint added by the script (the service doesn't yet support cascading delete). + +1. To do this, run the command `az dt endpoint delete -n
-g --en someEventHubEndpoint`. +1. If you have other endpoints that have been added outside this script, you can discover them with the command `az dt endpoint list -n
-g `. + - Then delete them with the same command in step 1. + +## Maintenance + +In order to maintain the functionality of the Setup.ps1 file, make sure this document stays updated with all the required changes if you run/alter this script. + +Currently, this script works with version 0.0.1.dev8. diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/setup.ps1 b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/setup.ps1 new file mode 100644 index 0000000000000..bfcc4b982c45e --- /dev/null +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/tests/prerequisites/setup.ps1 @@ -0,0 +1,204 @@ +param( + [Parameter(Mandatory)] + [string] $Region, + + [Parameter(Mandatory)] + [string] $ResourceGroup, + + [Parameter(Mandatory)] + [string] $SubscriptionId, + + [Parameter()] + [string] $DigitalTwinName, + + [Parameter()] + [string] $AppRegistrationName, + + [Parameter()] + [string] $EventHubName +) + +Function Connect-AzureSubscription() +{ + # Ensure the user is logged in + try + { + $azureContext = az account show + } + catch { } + + if (-not $azureContext) + { + Write-Host "`nPlease login to Azure..." + az login + $azureContext = az account show + } + + # Ensure the desired subscription is selected + $sub = az account show --output tsv --query id + if ($sub -ne $SubscriptionId) + { + Write-Host "`nSelecting subscription $SubscriptionId" + az account set --subscription $SubscriptionId + } + + return $azureContext +} + +$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") +if (-not $isAdmin) +{ + throw "This script must be run in administrative mode." +} + +Connect-AzureSubscription + +$Region = $Region.Replace(' ', '') + +if (-not $DigitalTwinName) +{ + $DigitalTwinName = $ResourceGroup +} + +if (-not $EventHubName) +{ + $EventHubName = $ResourceGroup +} + +if (-not $AppRegistrationName) +{ + $AppRegistrationName = $ResourceGroup +} + +$pathToManifest = "$PSScriptRoot\manifest.json" + +$appId = az ad app list --show-mine --query "[?displayName=='$AppRegistrationName'].appId" --output tsv +if (-not $appId) +{ + Write-Host "`nCreating App Registration $AppRegistrationName`n" + $appId = az ad app create --display-name $AppRegistrationName --native-app --required-resource-accesses $pathToManifest --query 'appId' --output tsv +} + +$spExists = az ad sp list --show-mine --query "[?appId=='$appId'].appId" --output tsv +if (-not $spExists) +{ + Write-Host "`nCreating service principal for app $appId`n" + az ad sp create --id $appId --output none +} + +$rgExists = az group exists --name $ResourceGroup +if ($rgExists -eq "False") +{ + Write-Host "`nCreating Resource Group $ResourceGroup in $Region`n" + az group create --name $ResourceGroup --location $Region --output none +} + +$dtExists = az dt list -g $ResourceGroup --query "[?name=='$DigitalTwinName']" --output tsv --only-show-errors +if (-not $dtExists) +{ + Write-Host "`nCreating Digital Twin $DigitalTwinName`n" + az dt create -n $DigitalTwinName -g $ResourceGroup --location $Region --output none --only-show-errors +} +$dtHostName = az dt show -n $DigitalTwinName -g $ResourceGroup --query 'hostName' --output tsv --only-show-errors + +# The Service Principal takes a while to get propogated and if a different endpoint is hit before that, trying to grant a permission will fail. +# Adding retries so that we can grant the permissions successfully without re-running the script. +Write-Host "Assigning owner role to $appId for $DigitalTwinName`n" +$tries = 0; +while (++$tries -le 10) +{ + try + { + az dt rbac assign-role --assignee $appId --role owner -n $DigitalTwinName --output none --only-show-errors + + if ($LastExitCode -eq 0) + { + Write-Host "`tSucceeded" + break + } + } + catch { } + + if ($tries -ge 10) + { + Write-Error "Max retries reached for granting service principal permissions." + throw + } + + Write-Host "`tGranting service principal permission failed. Waiting 5 seconds before retry..." + Start-Sleep -s 5; +} + +Write-Host("Set a new client secret for $appId`n") +$appSecret = az ad app credential reset --id $appId --years 2 --query 'password' --output tsv + +# Create an eventhub namespace and an eventhub in that namespace to serve as an endpoint for the digital twins instance to use for tests +$eventHubNamespaceExists = az eventhubs namespace list -g $ResourceGroup --query "[?name=='$EventHubName']" --output tsv +if (-not $eventHubNamespaceExists) +{ + Write-Host "`nCreating Event Hub Namespace $EventHubName`n" + az eventhubs namespace create --name $EventHubName -g $ResourceGroup -l $Region --output none +} +else +{ + Write-Host "Skipping creating the eventhub namespace as it already exists" +} + +$eventHubExists = az eventhubs eventhub list --namespace-name $EventHubName -g $ResourceGroup --query "[?name=='$EventHubName']" --output tsv +if (-not $eventHubExists) { + Write-Host "`nCreating Event Hub $EventHubName`n" + az eventhubs eventhub create --name $EventHubName -g $ResourceGroup --namespace-name $EventHubName --output none +} +else { + Write-Host "Skipping creating the eventhub as it already exists" +} + +$Policy = "owner" +$policyExists = az eventhubs eventhub authorization-rule list -g $ResourceGroup --namespace-name $EventHubName --eventhub-name $EventHubName --query "[?name=='$Policy']" --output tsv +if (-not $policyExists) +{ + Write-Host "`nCreating Event Hub Policy $Policy`n" + az eventhubs eventhub authorization-rule create -g $ResourceGroup --namespace-name $EventHubName --eventhub-name $EventHubName --name $Policy --rights Manage Send Listen +} +else +{ + Write-Host "Skipping creating the owner policy as it already exists" +} + +# Link the eventhub to the digital twins instance as a dedicated endpoint + +$endpointName = "someEventHubEndpoint" +$endpointLinkExists = az dt endpoint list -g $ResourceGroup --dt-name $DigitalTwinName --query "[?name=='$endpointName']" --output tsv --only-show-errors +if (-not $endpointLinkExists) +{ + Write-Host "`nConnecting Event Hub Endpoint to Digital Twin instance`n" + az dt endpoint create eventhub --endpoint-name $endpointName --subscription $SubscriptionId --eventhub $EventHubName --eventhub-namespace $EventHubName --eventhub-resource-group $ResourceGroup --dt-name $DigitalTwinName --eventhub-policy $Policy --only-show-errors +} +else +{ + Write-Host "Skipping linking the event hub to the digital twin instance as it is already linked" +} + +$user = $env:UserName +$fileName = "$user.config.json" +Write-Host("Writing user config file - $fileName`n") +$config = @" +{ + "DigitalTwinsInstanceHostName": "https://$($dtHostName)", + "ApplicationId": "$appId", + "ClientSecret": "$appSecret", + "TestMode": "Live" +} +"@ +$config | Out-File "$PSScriptRoot\..\config\$fileName" + +$userSettingsFileSuffix = ".test.assets.config.json" +$userSettingsFileName = "$user$userSettingsFileSuffix" +$userTestAssetSettingsFileName = "$PSScriptRoot\..\config\$userSettingsFileName" +if (-not (Test-Path $userTestAssetSettingsFileName)) +{ + Write-Host "Creating empty user test assets config file - $userSettingsFileName`n" + New-Item -ItemType File -Path $userTestAssetSettingsFileName -Value "{}" | Out-Null +} + +Write-Host "Done!" diff --git a/sdk/digitaltwins/Export-AdtApis.ps1 b/sdk/digitaltwins/Export-AdtApis.ps1 new file mode 100644 index 0000000000000..b7b6d1c99f9f6 --- /dev/null +++ b/sdk/digitaltwins/Export-AdtApis.ps1 @@ -0,0 +1 @@ +..\..\eng\scripts\Export-API.ps1 digitaltwins diff --git a/sdk/digitaltwins/Update-AdtSnippets.ps1 b/sdk/digitaltwins/Update-AdtSnippets.ps1 new file mode 100644 index 0000000000000..cce705762b174 --- /dev/null +++ b/sdk/digitaltwins/Update-AdtSnippets.ps1 @@ -0,0 +1 @@ +..\..\eng\scripts\Update-Snippets.ps1 digitaltwins diff --git a/sdk/digitaltwins/remove-test-resources-pre.ps1 b/sdk/digitaltwins/remove-test-resources-pre.ps1 new file mode 100644 index 0000000000000..1b328f8228158 --- /dev/null +++ b/sdk/digitaltwins/remove-test-resources-pre.ps1 @@ -0,0 +1,51 @@ +# # Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +# IMPORTANT: Do not invoke this file directly. Please instead run eng/Remove-TestResources.ps1 from the repository root. + +#Requires -Version 6.0 +#Requires -PSEdition Core + +# Use same parameter names as declared in eng/Remove-TestResources.ps1 (assume validation therein). +[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] +param ( + [Parameter(Mandatory = $true)] + [string] $ResourceGroupName, + + + [ValidateNotNullOrEmpty()] + [string] $TenantId, + + [ValidatePattern('^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$')] + [string] $SubscriptionId, + + [ValidatePattern('^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$')] + [string] $ProvisionerApplicationId, + + [Parameter(ParameterSetName = 'ResourceGroup+Provisioner', Mandatory = $true)] + [string] $ProvisionerApplicationSecret, + + # Captures any arguments from eng/Remove-TestResources.ps1 not declared here (no parameter errors). + [Parameter(ValueFromRemainingArguments = $true)] + $RemainingArguments +) + +function Log($Message) { + Write-Host ('{0} - {1}' -f [DateTime]::Now.ToLongTimeString(), $Message) +} + +Log "Logging into service principal '$ProvisionerApplicationId'" + +az login --service-principal -u $ProvisionerApplicationId -p $ProvisionerApplicationSecret --tenant $TenantId +az account set --subscription $SubscriptionId + +Log "Running pre removal script for resource group $ResourceGroupName" + +$adtInstanceName = az rest --method get --uri "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroupName/providers/Microsoft.DigitalTwins/digitalTwinsInstances?api-version=2020-03-01-preview" --query "value[*].{Name:name}" --output tsv + +if (![string]::IsNullOrWhiteSpace($adtInstanceName)) { + Write-Verbose "remove-test-resources-pre.ps1: Deleting configured endpoint on '$adtInstanceName' ADT instance to avoid issues during deletion of '$ResourceGroupName' resource group" + az rest --method delete --uri "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroupName/providers/Microsoft.DigitalTwins/digitalTwinsInstances/$adtInstanceName/endpoints/someEventHubEndpoint?api-version=2020-03-01-preview" +} + +az logout \ No newline at end of file diff --git a/sdk/digitaltwins/test-resources.json b/sdk/digitaltwins/test-resources.json new file mode 100644 index 0000000000000..8ba36a6b956f0 --- /dev/null +++ b/sdk/digitaltwins/test-resources.json @@ -0,0 +1,153 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "baseName": { + "type": "string", + "defaultValue": "[resourceGroup().name]", + "metadata": { + "description": "The base resource name." + } + }, + "testApplicationOid": { + "type": "string", + "metadata": { + "description": "The client OID to grant access to test resources." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "The location of the resource. By default, this is the same as the resource group." + } + } + }, + "variables": { + "digitalTwinInstanceResourceId": "[resourceId('Microsoft.DigitalTwins/digitalTwinsInstances', parameters('baseName'))]", + "namespaceResourceId": "[resourceId('Microsoft.EventHub/namespaces', parameters('baseName'))]", + "eventHubResourceId": "[resourceId('Microsoft.EventHub/namespaces/eventhubs', parameters('baseName'), parameters('baseName'))]", + "eventHubAuthorizationResourceId": "[resourceId('Microsoft.EventHub/namespaces/eventhubs/authorizationRules', parameters('baseName'), parameters('baseName'), 'owner')]", + "rbacOwnerRoleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "AdtOwnerRoleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'bcd981a7-7f74-457b-83e1-cceb9e632ffe')]" + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2018-09-01-preview", + "name": "[guid(resourceGroup().id)]", + "properties": { + "roleDefinitionId": "[variables('rbacOwnerRoleDefinitionId')]", + "principalId": "[parameters('testApplicationOid')]" + } + }, + { + "type": "Microsoft.DigitalTwins/digitalTwinsInstances", + "apiVersion": "2020-03-01-preview", + "name": "[parameters('baseName')]", + "location": "[parameters('location')]", + "sku": { + "name": "S1" + }, + "properties": {} + }, + { + "type": "Microsoft.DigitalTwins/digitalTwinsInstances/providers/roleAssignments", + "apiVersion": "2020-03-01-preview", + "name": "[concat(parameters('baseName'),'/Microsoft.Authorization/', guid(uniqueString(parameters('baseName'))))]", + "properties": { + "roleDefinitionId": "[variables('AdtOwnerRoleDefinitionId')]", + "principalId": "[parameters('testApplicationOid')]" + }, + "dependsOn": [ + "[variables('digitalTwinInstanceResourceId')]" + ] + }, + { + "type": "Microsoft.EventHub/namespaces", + "apiVersion": "2018-01-01-preview", + "name": "[parameters('baseName')]", + "location": "[parameters('location')]", + "sku": { + "name": "Standard", + "tier": "Standard", + "capacity": 1 + }, + "properties": { + "zoneRedundant": false, + "isAutoInflateEnabled": false, + "maximumThroughputUnits": 0, + "kafkaEnabled": true + } + }, + { + "type": "Microsoft.EventHub/namespaces/eventhubs", + "apiVersion": "2017-04-01", + "name": "[concat(parameters('baseName'), '/', parameters('baseName'))]", + "location": "[parameters('location')]", + "dependsOn": [ + "[variables('namespaceResourceId')]" + ], + "properties": { + "messageRetentionInDays": 7, + "partitionCount": 4, + "status": "Active" + } + }, + { + "type": "Microsoft.EventHub/namespaces/AuthorizationRules", + "apiVersion": "2017-04-01", + "name": "[concat(parameters('baseName'), '/RootManageSharedAccessKey')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[variables('namespaceResourceId')]" + ], + "properties": { + "rights": [ + "Listen", + "Manage", + "Send" + ] + } + }, + { + "type": "Microsoft.EventHub/namespaces/eventhubs/authorizationRules", + "apiVersion": "2017-04-01", + "name": "[concat(parameters('baseName'), '/', parameters('baseName'), '/owner')]", + "location": "[parameters('location')]", + "dependsOn": [ + "[variables('namespaceResourceId')]", + "[variables('eventHubResourceId')]" + ], + "properties": { + "rights": [ + "Manage", + "Send", + "Listen" + ] + } + }, + { + "type": "Microsoft.DigitalTwins/digitalTwinsInstances/endpoints", + "apiVersion": "2020-03-01-preview", + "name": "[concat(parameters('baseName'), '/someEventHubEndpoint')]", + "dependsOn": [ + "[variables('digitalTwinInstanceResourceId')]", + "[variables('namespaceResourceId')]", + "[variables('eventHubResourceId')]", + "[variables('eventHubAuthorizationResourceId')]" + ], + "properties": { + "endpointType": "EventHub", + "connectionString-PrimaryKey": "[listKeys(variables('eventHubAuthorizationResourceId'),'2017-04-01').primaryConnectionString]", + "connectionString-SecondaryKey": "[listKeys(variables('eventHubAuthorizationResourceId'),'2017-04-01').secondaryConnectionString]" + } + } + ], + "outputs": { + "DIGITALTWINS_ADT_INSTANCE_ENDPOINT_URL": { + "type": "string", + "value": "[concat('https://', reference(variables('digitalTwinInstanceResourceId'), '2020-03-01-preview').hostName)]" + } + } +} diff --git a/sdk/digitaltwins/tests.yml b/sdk/digitaltwins/tests.yml index 91c208817fb68..eac38fc1985e9 100644 --- a/sdk/digitaltwins/tests.yml +++ b/sdk/digitaltwins/tests.yml @@ -11,7 +11,7 @@ jobs: - template: ../../eng/pipelines/templates/jobs/archetype-sdk-tests.yml parameters: ServiceDirectory: digitaltwins - Location: southcentralus + Location: westus2 SubscriptionConfiguration: $(sub-config-azure-cloud-test-resources-preview) EnvVars: # Runs live tests. From 485b53f34d7ecb63fd0df8fc9f85136b99ff9ee4 Mon Sep 17 00:00:00 2001 From: Basel Rustum Date: Mon, 1 Jun 2020 10:44:11 -0700 Subject: [PATCH 2/2] fix(swagger): Update Swagger (#12397) --- .../src/Generated/DigitalTwinsRestClient.cs | 2 + .../src/swagger/digitaltwins.json | 2850 +++++++++-------- 2 files changed, 1430 insertions(+), 1422 deletions(-) diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinsRestClient.cs b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinsRestClient.cs index 646241adaa6dc..4221ff31972ea 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinsRestClient.cs +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/Generated/DigitalTwinsRestClient.cs @@ -517,6 +517,7 @@ internal HttpMessage CreateSendTelemetryRequest(string id, string dtId, object t uri.AppendPath("/digitaltwins/", false); uri.AppendPath(id, true); uri.AppendPath("/telemetry", false); + uri.AppendQuery("api-version", apiVersion, true); request.Uri = uri; request.Headers.Add("dt-id", dtId); if (dtTimestamp != null) @@ -618,6 +619,7 @@ internal HttpMessage CreateSendComponentTelemetryRequest(string id, string compo uri.AppendPath("/components/", false); uri.AppendPath(componentPath, true); uri.AppendPath("/telemetry", false); + uri.AppendQuery("api-version", apiVersion, true); request.Uri = uri; request.Headers.Add("dt-id", dtId); if (dtTimestamp != null) diff --git a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/digitaltwins.json b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/digitaltwins.json index 4ae53fdc16d4d..b17bda7284649 100644 --- a/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/digitaltwins.json +++ b/sdk/digitaltwins/Azure.DigitalTwins.Core/src/swagger/digitaltwins.json @@ -1,1491 +1,1497 @@ { - "swagger": "2.0", - "info": { - "version": "2020-05-31-preview", - "title": "Azure Digital Twins API", - "description": "A service for managing and querying digital twins and digital twin models." + "swagger": "2.0", + "info": { + "version": "2020-05-31-preview", + "title": "Azure Digital Twins API", + "description": "A service for managing and querying digital twins and digital twin models." + }, + "host": "digitaltwins-name.digitaltwins.azure.net", + "schemes": [ + "https" + ], + "produces": [ + "application/json" + ], + "consumes": [ + "application/json" + ], + "paths": { + "/models": { + "post": { + "tags": [ + "Models" + ], + "description": "Uploads one or more models. When any error occurs, no models are uploaded.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n409 (Conflict): One or more of the provided models already exist.", + "operationId": "DigitalTwinModels_Add", + "x-ms-examples": { + "ModelAdd": { + "$ref": "./examples/ModelAdd.json" + } + }, + "parameters": [ + { + "name": "models", + "in": "body", + "description": "An array of models to add.", + "required": false, + "schema": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "object" + } + } + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/NonPagedModelDataCollection" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "get": { + "tags": [ + "Models" + ], + "description": "Retrieves model metadata and, optionally, model definitions.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", + "x-ms-pageable": { + "nextLinkName": "nextLink" + }, + "operationId": "DigitalTwinModels_List", + "x-ms-examples": { + "ModelsGet": { + "$ref": "./examples/ModelsGet.json" + }, + "ModelsGetWithContextAndIncludeModelDefinition": { + "$ref": "./examples/ModelsGetWithDependenciesAndIncludeModelDefinition.json" + } + }, + "parameters": [ + { + "name": "dependenciesFor", + "in": "query", + "description": "The set of the models which will have their dependencies retrieved. If omitted, all models are retrieved.", + "required": false, + "type": "array", + "collectionFormat": "multi", + "items": { + "type": "string" + } + }, + { + "$ref": "#/parameters/includeModelDefinition" + }, + { + "$ref": "#/parameters/max-item-count" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/PagedModelDataCollection" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } }, - "host": "digitaltwins-name.digitaltwins.azure.net", - "schemes": [ - "https" - ], - "produces": [ - "application/json" - ], - "consumes": [ - "application/json" - ], - "paths": { - "/models": { - "post": { - "tags": [ - "Models" - ], - "description": "Uploads one or more models. When any error occurs, no models are uploaded.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n409 (Conflict): One or more of the provided models already exist.", - "operationId": "DigitalTwinModels_Add", - "x-ms-examples": { - "ModelAdd": { - "$ref": "./examples/ModelAdd.json" - } - }, - "parameters": [ - { - "name": "models", - "in": "body", - "description": "An array of models to add.", - "required": false, - "schema": { - "type": "array", - "minItems": 1, - "uniqueItems": true, - "items": { - "type": "object" - } - } - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/NonPagedModelDataCollection" - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - }, - "get": { - "tags": [ - "Models" - ], - "description": "Retrieves model metadata and, optionally, model definitions.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", - "x-ms-pageable": { - "nextLinkName": "nextLink" - }, - "operationId": "DigitalTwinModels_List", - "x-ms-examples": { - "ModelsGet": { - "$ref": "./examples/ModelsGet.json" - }, - "ModelsGetWithContextAndIncludeModelDefinition": { - "$ref": "./examples/ModelsGetWithDependenciesAndIncludeModelDefinition.json" - } - }, - "parameters": [ - { - "name": "dependenciesFor", - "in": "query", - "description": "The set of the models which will have their dependencies retrieved. If omitted, all models are retrieved.", - "required": false, - "type": "array", - "collectionFormat": "multi", - "items": { - "type": "string" - } - }, - { - "$ref": "#/parameters/includeModelDefinition" - }, - { - "$ref": "#/parameters/max-item-count" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/PagedModelDataCollection" - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "/models/{id}": { + "get": { + "tags": [ + "Models" + ], + "description": "Retrieves model metadata and optionally the model definition.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no model with the provided id.", + "operationId": "DigitalTwinModels_GetById", + "x-ms-examples": { + "ModelGetById": { + "$ref": "./examples/ModelGetById.json" + }, + "ModelGetByIdWithIncludeModelDefinition": { + "$ref": "./examples/ModelGetByIdWithIncludeModelDefinition.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/modelId" + }, + { + "$ref": "#/parameters/includeModelDefinition" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/ModelData" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "patch": { + "tags": [ + "Models" + ], + "description": "Updates the metadata for a model.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no model with the provided id.", + "operationId": "DigitalTwinModels_Update", + "consumes": [ + "application/json-patch+json" + ], + "x-ms-examples": { + "ModelUpdateDecommissioned": { + "$ref": "./examples/ModelUpdateDecommissioned.json" + } }, - "/models/{id}": { - "get": { - "tags": [ - "Models" - ], - "description": "Retrieves model metadata and optionally the model definition.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no model with the provided id.", - "operationId": "DigitalTwinModels_GetById", - "x-ms-examples": { - "ModelGetById": { - "$ref": "./examples/ModelGetById.json" - }, - "ModelGetByIdWithIncludeModelDefinition": { - "$ref": "./examples/ModelGetByIdWithIncludeModelDefinition.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/modelId" - }, - { - "$ref": "#/parameters/includeModelDefinition" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/ModelData" - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - }, - "patch": { - "tags": [ - "Models" - ], - "description": "Updates the metadata for a model.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no model with the provided id.", - "operationId": "DigitalTwinModels_Update", - "consumes": [ - "application/json-patch+json" - ], - "x-ms-examples": { - "ModelUpdateDecommissioned": { - "$ref": "./examples/ModelUpdateDecommissioned.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/modelId" - }, - { - "name": "updateModel", - "description": "An update specification described by JSON Patch. Only the decommissioned property can be replaced.", - "in": "body", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "object" - } - } - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "204": { - "description": "Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - }, - "delete": { - "tags": [ - "Models" - ], - "operationId": "DigitalTwinModels_Delete", - "description": "Deletes a model. A model can only be deleted if no other models reference it.\nStatus codes:\n204 (No Content): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no model with the provided id.\n409 (Conflict): There are dependencies on the model that prevent it from being deleted.", - "x-ms-examples": { - "DeleteModel": { - "$ref": "./examples/DeleteModel.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/modelId" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "204": { - "description": "Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "parameters": [ + { + "$ref": "#/parameters/modelId" + }, + { + "name": "updateModel", + "description": "An update specification described by JSON Patch. Only the decommissioned property can be replaced.", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "object" + } + } + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "delete": { + "tags": [ + "Models" + ], + "operationId": "DigitalTwinModels_Delete", + "description": "Deletes a model. A model can only be deleted if no other models reference it.\nStatus codes:\n204 (No Content): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no model with the provided id.\n409 (Conflict): There are dependencies on the model that prevent it from being deleted.", + "x-ms-examples": { + "DeleteModel": { + "$ref": "./examples/DeleteModel.json" + } }, - "/query": { - "post": { - "tags": [ - "Query" - ], - "operationId": "Query_QueryTwins", - "description": "Executes a query that allows traversing relationships and filtering by property values.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", - "x-ms-examples": { - "QueryFirstPage": { - "$ref": "./examples/QueryFirstPage.json" - }, - "QueryNextPage": { - "$ref": "./examples/QueryNextPage.json" - }, - "QueryJoin": { - "$ref": "./examples/QueryJoin.json" - } - }, - "parameters": [ - { - "name": "querySpecification", - "in": "body", - "description": "The query specification to execute.", - "required": true, - "schema": { - "$ref": "#/definitions/QuerySpecification" - } - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/QueryResult" - }, - "headers": { - "query-charge": { - "description": "The query charge.", - "type": "number" - } - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "parameters": [ + { + "$ref": "#/parameters/modelId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + } + }, + "/query": { + "post": { + "tags": [ + "Query" + ], + "operationId": "Query_QueryTwins", + "description": "Executes a query that allows traversing relationships and filtering by property values.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", + "x-ms-examples": { + "QueryFirstPage": { + "$ref": "./examples/QueryFirstPage.json" + }, + "QueryNextPage": { + "$ref": "./examples/QueryNextPage.json" + }, + "QueryJoin": { + "$ref": "./examples/QueryJoin.json" + } }, - "/digitaltwins/{id}": { - "get": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_GetById", - "description": "Retrieves a digital twin.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no digital twin with the provided id.", - "x-ms-examples": { - "GetTwin": { - "$ref": "./examples/GetTwin.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "type": "object" - }, - "headers": { - "ETag": { - "description": "Weak Etag.", - "type": "string" - } - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - }, - "put": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_Add", - "description": "Adds or replaces a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n412 (Precondition Failed): The model is decommissioned or the digital twin already exists (when using If-None-Match: *).", - "x-ms-examples": { - "PutTwinBasicExample": { - "$ref": "./examples/PutTwinBasicExample.json" - }, - "PutTwinAdvancedExample": { - "$ref": "./examples/PutTwinAdvancedExample.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "name": "twin", - "description": "The digital twin instance being added. If provided, the $dtId property is ignored.", - "in": "body", - "required": true, - "schema": { - "type": "object" - } - }, - { - "$ref": "#/parameters/if-none-match-star" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "type": "object" - }, - "headers": { - "ETag": { - "description": "Weak Etag.", - "type": "string" - } - } - }, - "202": { - "description": "Asynchronous Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - }, - "delete": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_Delete", - "description": "Deletes a digital twin. All relationships referencing the digital twin must already be deleted.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", - "x-ms-examples": { - "DeleteTwin": { - "$ref": "./examples/DeleteTwin.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/if-match" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "204": { - "description": "Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "parameters": [ + { + "name": "querySpecification", + "in": "body", + "description": "The query specification to execute.", + "required": true, + "schema": { + "$ref": "#/definitions/QuerySpecification" + } + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/QueryResult" }, - "patch": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_Update", - "description": "Updates a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", - "consumes": [ - "application/json-patch+json" - ], - "x-ms-examples": { - "PatchTwinBasicExample": { - "$ref": "./examples/PatchTwinBasicExample.json" - }, - "PatchTwinAdvancedExample": { - "$ref": "./examples/PatchTwinAdvancedExample.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "name": "patchDocument", - "description": "An update specification described by JSON Patch. Updates to property values and $model elements may happen in the same request. Operations are limited to add, replace and remove.", - "in": "body", - "required": true, - "schema": { - "type": "array", - "items": { - "type": "object" - } - } - }, - { - "$ref": "#/parameters/if-match" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "204": { - "description": "Success", - "headers": { - "ETag": { - "description": "Weak Etag.", - "type": "string" - } - } - }, - "202": { - "description": "Asynchronous Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "headers": { + "query-charge": { + "description": "The query charge.", + "type": "number" + } } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_GetById", + "description": "Retrieves a digital twin.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-examples": { + "GetTwin": { + "$ref": "./examples/GetTwin.json" + } }, - "/digitaltwins/{id}/relationships/{relationshipId}": { - "get": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_GetRelationshipById", - "description": "Retrieves a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is either no digital twin or relationship with the provided id.", - "x-ms-examples": { - "GetRelationshipById": { - "$ref": "./examples/GetRelationshipById.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/relationshipId" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "type": "object" - }, - "headers": { - "ETag": { - "description": "Weak Etag.", - "type": "string" - } - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - }, - "put": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_AddRelationship", - "description": "Adds a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin, target digital twin, or relationship with the provided id.\n409 (Conflict): A relationship with the provided id already exists.", - "x-ms-examples": { - "CreateRelationshipBasicExample": { - "$ref": "./examples/CreateRelationshipBasicExample.json" - }, - "CreateRelationshipAdvancedExample": { - "$ref": "./examples/CreateRelationshipAdvancedExample.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/relationshipId" - }, - { - "name": "relationship", - "in": "body", - "description": "The data for the relationship.", - "required": false, - "schema": { - "type": "object" - } - }, - { - "$ref": "#/parameters/if-none-match-star" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "type": "object" - }, - "headers": { - "ETag": { - "description": "Weak Etag.", - "type": "string" - } - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - }, - "delete": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_DeleteRelationship", - "description": "Deletes a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is either no digital twin or relationship with the provided id.", - "x-ms-examples": { - "DeleteRelationship": { - "$ref": "./examples/DeleteRelationship.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/relationshipId" - }, - { - "$ref": "#/parameters/if-match" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "204": { - "description": "Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" }, - "patch": { - "tags": [ - "Twins" - ], - "consumes": [ - "application/json-patch+json" - ], - "operationId": "DigitalTwins_UpdateRelationship", - "description": "Updates the properties on a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin or relationship with the provided id.", - "x-ms-examples": { - "PatchRelationshipBasicExample": { - "$ref": "./examples/PatchRelationshipBasicExample.json" - }, - "PatchRelationshipAdvancedExample": { - "$ref": "./examples/PatchRelationshipAdvancedExample.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/relationshipId" - }, - { - "name": "patchDocument", - "description": "JSON Patch description of the update to the relationship properties.", - "in": "body", - "required": false, - "schema": { - "type": "array", - "items": { - "type": "object" - } - } - }, - { - "$ref": "#/parameters/if-match" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "204": { - "description": "Success", - "headers": { - "ETag": { - "description": "Weak Etag.", - "type": "string" - } - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } } - }, - "/digitaltwins/{id}/relationships": { - "get": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_ListRelationships", - "description": "Retrieves the relationships from a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", - "x-ms-pageable": { - "nextLinkName": "nextLink" - }, - "x-ms-examples": { - "GetRelationship": { - "$ref": "./examples/GetRelationship.json" - }, - "GetRelationshipByName": { - "$ref": "./examples/GetRelationshipByRelationshipName.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "name": "relationshipName", - "description": "The name of the relationship.", - "in": "query", - "required": false, - "type": "string" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/RelationshipCollection" - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "put": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_Add", + "description": "Adds or replaces a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n412 (Precondition Failed): The model is decommissioned or the digital twin already exists (when using If-None-Match: *).", + "x-ms-examples": { + "PutTwinBasicExample": { + "$ref": "./examples/PutTwinBasicExample.json" + }, + "PutTwinAdvancedExample": { + "$ref": "./examples/PutTwinAdvancedExample.json" + } }, - "/digitaltwins/{id}/incomingrelationships": { - "get": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_ListIncomingRelationships", - "description": "Retrieves all incoming relationship for a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", - "x-ms-pageable": { - "nextLinkName": "nextLink" - }, - "x-ms-examples": { - "GetIncomingRelationship": { - "$ref": "./examples/GetIncomingRelationship.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/IncomingRelationshipCollection" - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "name": "twin", + "description": "The digital twin instance being added. If provided, the $dtId property is ignored.", + "in": "body", + "required": true, + "schema": { + "type": "object" + } + }, + { + "$ref": "#/parameters/if-none-match-star" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + }, + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } } + }, + "202": { + "description": "Asynchronous Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + }, + "delete": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_Delete", + "description": "Deletes a digital twin. All relationships referencing the digital twin must already be deleted.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-examples": { + "DeleteTwin": { + "$ref": "./examples/DeleteTwin.json" + } }, - "/digitaltwins/{id}/telemetry": { - "post": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_SendTelemetry", - "description": "Sends telemetry on behalf of a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", - "x-ms-examples": { - "SendTelemetry": { - "$ref": "./examples/SendTelemetry.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "name": "telemetry", - "in": "body", - "description": "The telemetry measurements to send from the digital twin.", - "required": true, - "schema": { - "type": "object" - } - }, - { - "name": "dt-id", - "in": "header", - "description": "A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages.", - "required": true, - "type": "string" - }, - { - "name": "dt-timestamp", - "in": "header", - "description": "An RFC 3339 timestamp that identifies the time the telemetry was measured.", - "required": false, - "type": "string" - } - ], - "responses": { - "204": { - "description": "Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "patch": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_Update", + "description": "Updates a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "consumes": [ + "application/json-patch+json" + ], + "x-ms-examples": { + "PatchTwinBasicExample": { + "$ref": "./examples/PatchTwinBasicExample.json" + }, + "PatchTwinAdvancedExample": { + "$ref": "./examples/PatchTwinAdvancedExample.json" + } }, - "/digitaltwins/{id}/components/{componentPath}/telemetry": { - "post": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_SendComponentTelemetry", - "description": "Sends telemetry on behalf of a component in a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin with the provided id or the component path is invalid.", - "x-ms-examples": { - "SendTelemetry": { - "$ref": "./examples/SendTelemetryFromComponent.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/componentPath" - }, - { - "name": "telemetry", - "in": "body", - "description": "The telemetry measurements to send from the digital twin's component.", - "required": true, - "schema": { - "type": "object" - } - }, - { - "name": "dt-id", - "in": "header", - "description": "A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages.", - "required": true, - "type": "string" - }, - { - "name": "dt-timestamp", - "in": "header", - "description": "An RFC 3339 timestamp that identifies the time the telemetry was measured.", - "required": false, - "type": "string" - } - ], - "responses": { - "204": { - "description": "Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "name": "patchDocument", + "description": "An update specification described by JSON Patch. Updates to property values and $model elements may happen in the same request. Operations are limited to add, replace and remove.", + "in": "body", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "object" + } + } + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success", + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } } + }, + "202": { + "description": "Asynchronous Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}/relationships/{relationshipId}": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_GetRelationshipById", + "description": "Retrieves a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is either no digital twin or relationship with the provided id.", + "x-ms-examples": { + "GetRelationshipById": { + "$ref": "./examples/GetRelationshipById.json" + } }, - "/digitaltwins/{id}/components/{componentPath}": { - "get": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_GetComponent", - "description": "Retrieves a component from a digital twin.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is either no digital twin with the provided id or the component path is invalid.", - "x-ms-examples": { - "GetComponent": { - "$ref": "./examples/GetComponent.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/componentPath" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "type": "object" - }, - "headers": { - "ETag": { - "description": "Weak Etag.", - "type": "string" - } - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/relationshipId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" }, - "patch": { - "tags": [ - "Twins" - ], - "operationId": "DigitalTwins_UpdateComponent", - "description": "Updates a component on a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin with the provided id or the component path is invalid.", - "x-ms-examples": { - "PatchComponentBasicExample": { - "$ref": "./examples/PatchComponentBasicExample.json" - }, - "PatchComponentAdvancedExample": { - "$ref": "./examples/PatchComponentAdvancedExample.json" - } - }, - "consumes": [ - "application/json-patch+json" - ], - "parameters": [ - { - "$ref": "#/parameters/digitalTwinId" - }, - { - "$ref": "#/parameters/componentPath" - }, - { - "name": "patchDocument", - "description": "An update specification described by JSON Patch. Updates to property values and $model elements may happen in the same request. Operations are limited to add, replace and remove.", - "in": "body", - "required": false, - "schema": { - "type": "array", - "items": { - "type": "object" - } - } - }, - { - "$ref": "#/parameters/if-match" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "204": { - "description": "Success", - "headers": { - "ETag": { - "description": "Weak Etag.", - "type": "string" - } - } - }, - "202": { - "description": "Asynchronous Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } } - }, - "/eventroutes": { - "get": { - "tags": [ - "EventRoutes" - ], - "description": "Retrieves all event routes.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", - "operationId": "EventRoutes_List", - "x-ms-examples": { - "EventRoutesList": { - "$ref": "./examples/EventRoutesList.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/max-item-count" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/EventRouteCollection" - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - }, - "x-ms-pageable": { - "nextLinkName": "nextLink" - } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "put": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_AddRelationship", + "description": "Adds a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin, target digital twin, or relationship with the provided id.\n409 (Conflict): A relationship with the provided id already exists.", + "x-ms-examples": { + "CreateRelationshipBasicExample": { + "$ref": "./examples/CreateRelationshipBasicExample.json" + }, + "CreateRelationshipAdvancedExample": { + "$ref": "./examples/CreateRelationshipAdvancedExample.json" + } }, - "/eventroutes/{id}": { - "get": { - "tags": [ - "EventRoutes" - ], - "description": "Retrieves an event route.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no event route with the provided id.", - "operationId": "EventRoutes_GetById", - "x-ms-examples": { - "EventRouteGet": { - "$ref": "./examples/EventRouteGet.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/eventRouteId" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "200": { - "description": "Success", - "schema": { - "$ref": "#/definitions/EventRoute" - } - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } - }, - "put": { - "tags": [ - "EventRoutes" - ], - "description": "Adds or replaces an event route.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", - "operationId": "EventRoutes_Add", - "x-ms-examples": { - "EventRoutePut": { - "$ref": "./examples/EventRoutePut.json" - }, - "EventRouteWithFilter": { - "$ref": "./examples/EventRoutePutWithFilter.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/eventRouteId" - }, - { - "name": "eventRoute", - "description": "The event route data", - "in": "body", - "schema": { - "$ref": "#/definitions/EventRoute" - } - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "204": { - "description": "Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/relationshipId" + }, + { + "name": "relationship", + "in": "body", + "description": "The data for the relationship.", + "required": false, + "schema": { + "type": "object" + } + }, + { + "$ref": "#/parameters/if-none-match-star" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" }, - "delete": { - "tags": [ - "EventRoutes" - ], - "description": "Deletes an event route.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no event route with the provided id.", - "operationId": "EventRoutes_Delete", - "x-ms-examples": { - "EventRouteDelete": { - "$ref": "./examples/EventRouteDelete.json" - } - }, - "parameters": [ - { - "$ref": "#/parameters/eventRouteId" - }, - { - "$ref": "#/parameters/api-version" - } - ], - "responses": { - "204": { - "description": "Success" - }, - "default": { - "description": "Default response.", - "schema": { - "$ref": "#/definitions/ErrorResponse" - } - } - } + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } } - } - }, - "definitions": { - "EventRoute": { - "description": "A route which directs notification and telemetry events to an endpoint. Endpoints are a destination outside of Azure Digital Twins such as an EventHub.", - "type": "object", - "required": [ - "endpointName" - ], - "properties": { - "id": { - "description": "The id of the event route.", - "type": "string", - "readOnly": true - }, - "endpointName": { - "description": "The name of the endpoint this event route is bound to.", - "type": "string" - }, - "filter": { - "description": "An expression which describes the events which are routed to the endpoint.", - "type": "string" - } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "delete": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_DeleteRelationship", + "description": "Deletes a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is either no digital twin or relationship with the provided id.", + "x-ms-examples": { + "DeleteRelationship": { + "$ref": "./examples/DeleteRelationship.json" + } }, - "EventRouteCollection": { - "description": "A collection of EventRoute objects.", - "type": "object", - "properties": { - "value": { - "description": "The EventRoute objects.", - "type": "array", - "items": { - "$ref": "#/definitions/EventRoute" - } - }, - "nextLink": { - "description": "A URI to retrieve the next page of results.", - "type": "string" - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/relationshipId" + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "patch": { + "tags": [ + "Twins" + ], + "consumes": [ + "application/json-patch+json" + ], + "operationId": "DigitalTwins_UpdateRelationship", + "description": "Updates the properties on a relationship between two digital twins.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin or relationship with the provided id.", + "x-ms-examples": { + "PatchRelationshipBasicExample": { + "$ref": "./examples/PatchRelationshipBasicExample.json" + }, + "PatchRelationshipAdvancedExample": { + "$ref": "./examples/PatchRelationshipAdvancedExample.json" + } }, - "NonPagedModelDataCollection": { - "description": "A collection of ModelData objects.", - "type": "array", - "items": { - "$ref": "#/definitions/ModelData" + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/relationshipId" + }, + { + "name": "patchDocument", + "description": "JSON Patch description of the update to the relationship properties.", + "in": "body", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "object" + } } + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success", + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/digitaltwins/{id}/relationships": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_ListRelationships", + "description": "Retrieves the relationships from a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-pageable": { + "nextLinkName": "nextLink" + }, + "x-ms-examples": { + "GetRelationship": { + "$ref": "./examples/GetRelationship.json" + }, + "GetRelationshipByName": { + "$ref": "./examples/GetRelationshipByRelationshipName.json" + } }, - "PagedModelDataCollection": { - "description": "A collection of ModelData objects.", - "type": "object", - "properties": { - "value": { - "description": "The ModelData objects.", - "type": "array", - "items": { - "$ref": "#/definitions/ModelData" - } - }, - "nextLink": { - "description": "A URI to retrieve the next page of objects.", - "type": "string" - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "name": "relationshipName", + "description": "The name of the relationship.", + "in": "query", + "required": false, + "type": "string" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/RelationshipCollection" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + } + }, + "/digitaltwins/{id}/incomingrelationships": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_ListIncomingRelationships", + "description": "Retrieves all incoming relationship for a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-pageable": { + "nextLinkName": "nextLink" }, - "ModelData": { - "description": "A model definition and metadata for that model.", - "required": [ - "id" - ], - "type": "object", - "properties": { - "displayName": { - "description": "A language map that contains the localized display names as specified in the model definition.", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "description": { - "description": "A language map that contains the localized descriptions as specified in the model definition.", - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "id": { - "description": "The id of the model as specified in the model definition.", - "type": "string" - }, - "uploadTime": { - "description": "The time the model was uploaded to the service.", - "format": "date-time", - "type": "string" - }, - "decommissioned": { - "description": "Indicates if the model is decommissioned. Decommissioned models cannot be referenced by newly created digital twins.", - "type": "boolean", - "default": false - }, - "model": { - "description": "The model definition.", - "type": "object" - } + "x-ms-examples": { + "GetIncomingRelationship": { + "$ref": "./examples/GetIncomingRelationship.json" + } + }, + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/IncomingRelationshipCollection" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + } + }, + "/digitaltwins/{id}/telemetry": { + "post": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_SendTelemetry", + "description": "Sends telemetry on behalf of a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is no digital twin with the provided id.", + "x-ms-examples": { + "SendTelemetry": { + "$ref": "./examples/SendTelemetry.json" + } }, - "RelationshipCollection": { - "description": "A collection of relationships which relate digital twins together.", - "type": "object", - "properties": { - "value": { - "description": "The relationship objects.", - "type": "array", - "items": { - "description": "The relationship JSON document.", - "type": "object" - } - }, - "nextLink": { - "description": "A URI to retrieve the next page of objects.", - "type": "string" - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "name": "telemetry", + "in": "body", + "description": "The telemetry measurements to send from the digital twin.", + "required": true, + "schema": { + "type": "object" + } + }, + { + "name": "dt-id", + "in": "header", + "description": "A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages.", + "required": true, + "type": "string" + }, + { + "name": "dt-timestamp", + "in": "header", + "description": "An RFC 3339 timestamp that identifies the time the telemetry was measured.", + "required": false, + "type": "string" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + } + }, + "/digitaltwins/{id}/components/{componentPath}/telemetry": { + "post": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_SendComponentTelemetry", + "description": "Sends telemetry on behalf of a component in a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin with the provided id or the component path is invalid.", + "x-ms-examples": { + "SendTelemetry": { + "$ref": "./examples/SendTelemetryFromComponent.json" + } }, - "IncomingRelationshipCollection": { - "description": "A collection of incoming relationships which relate digital twins together.", - "type": "object", - "properties": { - "value": { - "type": "array", - "items": { - "$ref": "#/definitions/IncomingRelationship" - } - }, - "nextLink": { - "type": "string", - "description": "A URI to retrieve the next page of objects." - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/componentPath" + }, + { + "name": "telemetry", + "in": "body", + "description": "The telemetry measurements to send from the digital twin's component.", + "required": true, + "schema": { + "type": "object" + } + }, + { + "name": "dt-id", + "in": "header", + "description": "A unique message identifier (in the scope of the digital twin id) that is commonly used for de-duplicating messages.", + "required": true, + "type": "string" + }, + { + "name": "dt-timestamp", + "in": "header", + "description": "An RFC 3339 timestamp that identifies the time the telemetry was measured.", + "required": false, + "type": "string" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + } + }, + "/digitaltwins/{id}/components/{componentPath}": { + "get": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_GetComponent", + "description": "Retrieves a component from a digital twin.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is either no digital twin with the provided id or the component path is invalid.", + "x-ms-examples": { + "GetComponent": { + "$ref": "./examples/GetComponent.json" + } }, - "IncomingRelationship": { - "type": "object", - "description": "An incoming relationship.", - "properties": { - "$relationshipId": { - "type": "string", - "description": "A user-provided string representing the id of this relationship, unique in the context of the source digital twin, i.e. sourceId + relationshipId is unique in the context of the service." - }, - "$sourceId": { - "type": "string", - "description": "The id of the source digital twin." - }, - "$relationshipName": { - "type": "string", - "description": "The name of the relationship." - }, - "$relationshipLink": { - "type": "string", - "description": "Link to the relationship, to be used for deletion." - } + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/componentPath" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "type": "object" + }, + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "patch": { + "tags": [ + "Twins" + ], + "operationId": "DigitalTwins_UpdateComponent", + "description": "Updates a component on a digital twin.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.\n404 (Not Found): There is either no digital twin with the provided id or the component path is invalid.", + "x-ms-examples": { + "PatchComponentBasicExample": { + "$ref": "./examples/PatchComponentBasicExample.json" + }, + "PatchComponentAdvancedExample": { + "$ref": "./examples/PatchComponentAdvancedExample.json" + } }, - "QuerySpecification": { - "description": "A query specification containing either a query statement or a continuation token from a previous query result.", - "type": "object", - "properties": { - "query": { - "description": "The query to execute. This value is ignored if a continuation token is provided.", - "type": "string" - }, - "continuationToken": { - "description": "A token which is used to retrieve the next set of results from a previous query.", - "type": "string" - } + "consumes": [ + "application/json-patch+json" + ], + "parameters": [ + { + "$ref": "#/parameters/digitalTwinId" + }, + { + "$ref": "#/parameters/componentPath" + }, + { + "name": "patchDocument", + "description": "An update specification described by JSON Patch. Updates to property values and $model elements may happen in the same request. Operations are limited to add, replace and remove.", + "in": "body", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "object" + } + } + }, + { + "$ref": "#/parameters/if-match" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success", + "headers": { + "ETag": { + "description": "Weak Etag.", + "type": "string" + } } + }, + "202": { + "description": "Asynchronous Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, + "/eventroutes": { + "get": { + "tags": [ + "EventRoutes" + ], + "description": "Retrieves all event routes.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", + "operationId": "EventRoutes_List", + "x-ms-examples": { + "EventRoutesList": { + "$ref": "./examples/EventRoutesList.json" + } }, - "QueryResult": { - "description": "The results of a query operation and an optional continuation token.", - "type": "object", - "properties": { - "items": { - "description": "The query results.", - "type": "array", - "items": { - "type": "object" - } - }, - "continuationToken": { - "description": "A token which can be used to construct a new QuerySpecification to retrieve the next set of results.", - "type": "string" - } + "parameters": [ + { + "$ref": "#/parameters/max-item-count" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/EventRouteCollection" } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/eventroutes/{id}": { + "get": { + "tags": [ + "EventRoutes" + ], + "description": "Retrieves an event route.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no event route with the provided id.", + "operationId": "EventRoutes_GetById", + "x-ms-examples": { + "EventRouteGet": { + "$ref": "./examples/EventRouteGet.json" + } }, - "ErrorResponse": { - "description": "Error response.", - "properties": { - "error": { - "$ref": "#/definitions/Error", - "description": "The error details." - } + "parameters": [ + { + "$ref": "#/parameters/eventRouteId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "200": { + "description": "Success", + "schema": { + "$ref": "#/definitions/EventRoute" + } + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "put": { + "tags": [ + "EventRoutes" + ], + "description": "Adds or replaces an event route.\nStatus codes:\n200 (OK): Success.\n400 (Bad Request): The request is invalid.", + "operationId": "EventRoutes_Add", + "x-ms-examples": { + "EventRoutePut": { + "$ref": "./examples/EventRoutePut.json" + }, + "EventRouteWithFilter": { + "$ref": "./examples/EventRoutePutWithFilter.json" + } }, - "Error": { - "description": "Error definition.", - "properties": { - "code": { - "description": "Service specific error code which serves as the substatus for the HTTP error code.", - "type": "string", - "readOnly": true - }, - "message": { - "description": "A human-readable representation of the error.", - "type": "string", - "readOnly": true - }, - "details": { - "description": "Internal error details.", - "type": "array", - "items": { - "$ref": "#/definitions/Error" - }, - "readOnly": true - }, - "innererror": { - "description": "An object containing more specific information than the current object about the error.", - "$ref": "#/definitions/InnerError" - } + "parameters": [ + { + "$ref": "#/parameters/eventRouteId" + }, + { + "name": "eventRoute", + "description": "The event route data", + "in": "body", + "schema": { + "$ref": "#/definitions/EventRoute" + } + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } + } + }, + "delete": { + "tags": [ + "EventRoutes" + ], + "description": "Deletes an event route.\nStatus codes:\n200 (OK): Success.\n404 (Not Found): There is no event route with the provided id.", + "operationId": "EventRoutes_Delete", + "x-ms-examples": { + "EventRouteDelete": { + "$ref": "./examples/EventRouteDelete.json" + } }, - "InnerError": { - "description": "A more specific error description than was provided by the containing error.", - "properties": { - "code": { - "description": "A more specific error code than was provided by the containing error.", - "type": "string" - }, - "innererror": { - "description": "An object containing more specific information than the current object about the error.", - "$ref": "#/definitions/InnerError" - } + "parameters": [ + { + "$ref": "#/parameters/eventRouteId" + }, + { + "$ref": "#/parameters/api-version" + } + ], + "responses": { + "204": { + "description": "Success" + }, + "default": { + "description": "Default response.", + "schema": { + "$ref": "#/definitions/ErrorResponse" } + } } + } + } + }, + "definitions": { + "EventRoute": { + "description": "A route which directs notification and telemetry events to an endpoint. Endpoints are a destination outside of Azure Digital Twins such as an EventHub.", + "type": "object", + "required": [ + "endpointName" + ], + "properties": { + "id": { + "description": "The id of the event route.", + "type": "string", + "readOnly": true + }, + "endpointName": { + "description": "The name of the endpoint this event route is bound to.", + "type": "string" + }, + "filter": { + "description": "An expression which describes the events which are routed to the endpoint.", + "type": "string" + } + } }, - "securityDefinitions": { - "oauth2": { - "flow": "implicit", - "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize?resource=0b07f429-9f4b-4714-9392-cc5e8e80c8b0", - "type": "oauth2" + "EventRouteCollection": { + "description": "A collection of EventRoute objects.", + "type": "object", + "properties": { + "value": { + "description": "The EventRoute objects.", + "type": "array", + "items": { + "$ref": "#/definitions/EventRoute" + } + }, + "nextLink": { + "description": "A URI to retrieve the next page of results.", + "type": "string" } + } }, - "parameters": { - "eventRouteId": { - "name": "id", - "in": "path", - "required": true, - "type": "string", - "description": "The id for an event route. The id is unique within event routes and case sensitive.", - "x-ms-parameter-location": "method" + "NonPagedModelDataCollection": { + "description": "A collection of ModelData objects.", + "type": "array", + "items": { + "$ref": "#/definitions/ModelData" + } + }, + "PagedModelDataCollection": { + "description": "A collection of ModelData objects.", + "type": "object", + "properties": { + "value": { + "description": "The ModelData objects.", + "type": "array", + "items": { + "$ref": "#/definitions/ModelData" + } }, - "includeModelDefinition": { - "name": "includeModelDefinition", - "description": "When true the model definition will be returned as part of the result.", - "in": "query", - "required": false, - "type": "boolean", - "default": false, - "x-ms-parameter-location": "method" + "nextLink": { + "description": "A URI to retrieve the next page of objects.", + "type": "string" + } + } + }, + "ModelData": { + "description": "A model definition and metadata for that model.", + "required": [ + "id" + ], + "type": "object", + "properties": { + "displayName": { + "description": "A language map that contains the localized display names as specified in the model definition.", + "type": "object", + "additionalProperties": { + "type": "string" + } }, - "digitalTwinId": { - "name": "id", - "in": "path", - "description": "The id of the digital twin. The id is unique within the service and case sensitive.", - "type": "string", - "required": true, - "x-ms-parameter-location": "method" + "description": { + "description": "A language map that contains the localized descriptions as specified in the model definition.", + "type": "object", + "additionalProperties": { + "type": "string" + } }, - "modelId": { - "name": "id", - "in": "path", - "description": "The id for the model. The id is globally unique and case sensitive.", - "required": true, - "type": "string", - "x-ms-parameter-location": "method" + "id": { + "description": "The id of the model as specified in the model definition.", + "type": "string" }, - "relationshipId": { - "name": "relationshipId", - "description": "The id of the relationship. The id is unique within the digital twin and case sensitive.", - "in": "path", - "required": true, - "type": "string", - "x-ms-parameter-location": "method" + "uploadTime": { + "description": "The time the model was uploaded to the service.", + "format": "date-time", + "type": "string" }, - "componentPath": { - "name": "componentPath", - "in": "path", - "description": "The name of the DTDL component.", - "type": "string", - "required": true, - "x-ms-parameter-location": "method" + "decommissioned": { + "description": "Indicates if the model is decommissioned. Decommissioned models cannot be referenced by newly created digital twins.", + "type": "boolean", + "default": false }, - "api-version": { - "name": "api-version", - "in": "query", - "description": "The requested API version.", - "required": true, - "type": "string", - "enum": [ - "2020-05-31-preview" - ] + "model": { + "description": "The model definition.", + "type": "object" + } + } + }, + "RelationshipCollection": { + "description": "A collection of relationships which relate digital twins together.", + "type": "object", + "properties": { + "value": { + "description": "The relationship objects.", + "type": "array", + "items": { + "description": "The relationship JSON document.", + "type": "object" + } }, - "max-item-count": { - "name": "x-ms-max-item-count", - "in": "header", - "description": "The maximum number of items to retrieve per request. The server may choose to return less than the requested max.", - "required": false, - "type": "integer", - "default": -1, - "x-ms-client-name": "MaxItemCount", - "x-ms-parameter-location": "method", - "x-ms-parameter-grouping": { - "postfix": "Options" - } + "nextLink": { + "description": "A URI to retrieve the next page of objects.", + "type": "string" + } + } + }, + "IncomingRelationshipCollection": { + "description": "A collection of incoming relationships which relate digital twins together.", + "type": "object", + "properties": { + "value": { + "type": "array", + "items": { + "$ref": "#/definitions/IncomingRelationship" + } }, - "if-none-match-star": { - "name": "If-None-Match", - "in": "header", - "description": "Only perform the operation if the entity does not already exist.", - "required": false, - "type": "string", - "enum": [ - "*" - ], - "x-ms-parameter-location": "method" + "nextLink": { + "type": "string", + "description": "A URI to retrieve the next page of objects." + } + } + }, + "IncomingRelationship": { + "type": "object", + "description": "An incoming relationship.", + "properties": { + "$relationshipId": { + "type": "string", + "description": "A user-provided string representing the id of this relationship, unique in the context of the source digital twin, i.e. sourceId + relationshipId is unique in the context of the service." }, - "if-match": { - "name": "If-Match", - "in": "header", - "description": "Only perform the operation if the entity's etag matches one of the etags provided or * is provided.", - "required": false, - "type": "string", - "x-ms-parameter-location": "method" + "$sourceId": { + "type": "string", + "description": "The id of the source digital twin." + }, + "$relationshipName": { + "type": "string", + "description": "The name of the relationship." + }, + "$relationshipLink": { + "type": "string", + "description": "Link to the relationship, to be used for deletion." + } + } + }, + "QuerySpecification": { + "description": "A query specification containing either a query statement or a continuation token from a previous query result.", + "type": "object", + "properties": { + "query": { + "description": "The query to execute. This value is ignored if a continuation token is provided.", + "type": "string" + }, + "continuationToken": { + "description": "A token which is used to retrieve the next set of results from a previous query.", + "type": "string" } + } }, - "security": [ - { - "oauth2": [] + "QueryResult": { + "description": "The results of a query operation and an optional continuation token.", + "type": "object", + "properties": { + "items": { + "description": "The query results.", + "type": "array", + "items": { + "type": "object" + } + }, + "continuationToken": { + "description": "A token which can be used to construct a new QuerySpecification to retrieve the next set of results.", + "type": "string" + } + } + }, + "ErrorResponse": { + "description": "Error response.", + "properties": { + "error": { + "$ref": "#/definitions/Error", + "description": "The error details." + } + } + }, + "Error": { + "description": "Error definition.", + "properties": { + "code": { + "description": "Service specific error code which serves as the substatus for the HTTP error code.", + "type": "string", + "readOnly": true + }, + "message": { + "description": "A human-readable representation of the error.", + "type": "string", + "readOnly": true + }, + "details": { + "description": "Internal error details.", + "type": "array", + "items": { + "$ref": "#/definitions/Error" + }, + "readOnly": true + }, + "innererror": { + "description": "An object containing more specific information than the current object about the error.", + "$ref": "#/definitions/InnerError" + } + } + }, + "InnerError": { + "description": "A more specific error description than was provided by the containing error.", + "properties": { + "code": { + "description": "A more specific error code than was provided by the containing error.", + "type": "string" + }, + "innererror": { + "description": "An object containing more specific information than the current object about the error.", + "$ref": "#/definitions/InnerError" } - ] + } + } + }, + "securityDefinitions": { + "oauth2": { + "flow": "implicit", + "authorizationUrl": "https://login.microsoftonline.com/common/oauth2/authorize?resource=0b07f429-9f4b-4714-9392-cc5e8e80c8b0", + "type": "oauth2" + } + }, + "parameters": { + "eventRouteId": { + "name": "id", + "in": "path", + "required": true, + "type": "string", + "description": "The id for an event route. The id is unique within event routes and case sensitive.", + "x-ms-parameter-location": "method" + }, + "includeModelDefinition": { + "name": "includeModelDefinition", + "description": "When true the model definition will be returned as part of the result.", + "in": "query", + "required": false, + "type": "boolean", + "default": false, + "x-ms-parameter-location": "method" + }, + "digitalTwinId": { + "name": "id", + "in": "path", + "description": "The id of the digital twin. The id is unique within the service and case sensitive.", + "type": "string", + "required": true, + "x-ms-parameter-location": "method" + }, + "modelId": { + "name": "id", + "in": "path", + "description": "The id for the model. The id is globally unique and case sensitive.", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "relationshipId": { + "name": "relationshipId", + "description": "The id of the relationship. The id is unique within the digital twin and case sensitive.", + "in": "path", + "required": true, + "type": "string", + "x-ms-parameter-location": "method" + }, + "componentPath": { + "name": "componentPath", + "in": "path", + "description": "The name of the DTDL component.", + "type": "string", + "required": true, + "x-ms-parameter-location": "method" + }, + "api-version": { + "name": "api-version", + "in": "query", + "description": "The requested API version.", + "required": true, + "type": "string", + "enum": [ + "2020-05-31-preview" + ] + }, + "max-item-count": { + "name": "x-ms-max-item-count", + "in": "header", + "description": "The maximum number of items to retrieve per request. The server may choose to return less than the requested max.", + "required": false, + "type": "integer", + "default": -1, + "x-ms-client-name": "MaxItemCount", + "x-ms-parameter-location": "method", + "x-ms-parameter-grouping": { + "postfix": "Options" + } + }, + "if-none-match-star": { + "name": "If-None-Match", + "in": "header", + "description": "Only perform the operation if the entity does not already exist.", + "required": false, + "type": "string", + "enum": [ + "*" + ], + "x-ms-parameter-location": "method" + }, + "if-match": { + "name": "If-Match", + "in": "header", + "description": "Only perform the operation if the entity's etag matches one of the etags provided or * is provided.", + "required": false, + "type": "string", + "x-ms-parameter-location": "method" + } + }, + "security": [ + { + "oauth2": [] + } + ] }