From 44241c7bbb823f6936eb9fa9f6f6b25aa9f65b23 Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Mon, 13 Sep 2021 00:13:07 -0700 Subject: [PATCH 01/16] Remove TRY_FROM_EXPANDED from API --- .../iot/modelsrepository/ModelDependencyResolution.java | 6 ------ .../iot/modelsrepository/ModelsRepositoryClientBuilder.java | 4 ++-- .../modelsrepository/implementation/FileModelFetcher.java | 3 --- .../modelsrepository/implementation/HttpModelFetcher.java | 3 --- .../modelsrepository/implementation/RepositoryHandler.java | 2 +- .../azure-iot-modelsrepository/src/samples/README.md | 2 +- 6 files changed, 4 insertions(+), 16 deletions(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelDependencyResolution.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelDependencyResolution.java index db28c05aa825d..3110ee8276bd4 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelDependencyResolution.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelDependencyResolution.java @@ -16,10 +16,4 @@ public enum ModelDependencyResolution { * Enable model dependency resolution. The client will parse models and calculate dependencies recursively. */ ENABLED, - - /** - * Try to get pre-computed model dependencies using .expanded.json. - * If the model expanded form does not exist, it will fall back to {@link ModelDependencyResolution#ENABLED}. - */ - TRY_FROM_EXPANDED, } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelsRepositoryClientBuilder.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelsRepositoryClientBuilder.java index e82b0e913e793..a8995af01255c 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelsRepositoryClientBuilder.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelsRepositoryClientBuilder.java @@ -58,7 +58,7 @@ public final class ModelsRepositoryClientBuilder { // Fields with default values. private URI repositoryEndpoint; - private ModelDependencyResolution modelDependencyResolution = ModelDependencyResolution.TRY_FROM_EXPANDED; + private ModelDependencyResolution modelDependencyResolution = ModelDependencyResolution.DISABLED; // optional/have default values private ModelsRepositoryServiceVersion serviceVersion; @@ -152,7 +152,7 @@ private static HttpPipeline constructPipeline( /** * Create a {@link ModelsRepositoryClient} based on the builder settings. * - * @return the created synchronous ModelsRepotioryClient + * @return the created synchronous ModelsRepositoryClient */ public ModelsRepositoryClient buildClient() { return new ModelsRepositoryClient(buildAsyncClient()); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java index a8182568421d6..0ab7967c21503 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java @@ -44,9 +44,6 @@ public Mono fetchAsync(String dtmi, URI repositoryUri, ModelDepende Queue work = new LinkedList<>(); try { - if (resolutionOption == ModelDependencyResolution.TRY_FROM_EXPANDED) { - work.add(getPath(dtmi, repositoryUri, true)); - } work.add(getPath(dtmi, repositoryUri, false)); } catch (MalformedURLException | URISyntaxException e) { return Mono.error(new AzureException(e)); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java index 6a36fd9cacf84..d4c1cfb4aa507 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java @@ -35,9 +35,6 @@ public Mono fetchAsync(String dtmi, URI repositoryUri, ModelDepende return Mono.defer(() -> { Queue work = new LinkedList<>(); try { - if (resolutionOption == ModelDependencyResolution.TRY_FROM_EXPANDED) { - work.add(getPath(dtmi, repositoryUri, true)); - } work.add(getPath(dtmi, repositoryUri, false)); } catch (Exception e) { return Mono.error(new AzureException(e)); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index 7eb2e6dabd618..7560ebb6083f1 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -96,7 +96,7 @@ private Flux processAsync( try { ModelMetadata metadata = new ModelsQuery(response.getDefinition()).parseModel(); - if (resolutionOption == ModelDependencyResolution.ENABLED || resolutionOption == ModelDependencyResolution.TRY_FROM_EXPANDED) { + if (resolutionOption == ModelDependencyResolution.ENABLED) { List dependencies = metadata.getDependencies(); if (dependencies.size() > 0) { diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/README.md b/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/README.md index ec8476aabca03..4728db6067b6a 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/README.md +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/README.md @@ -18,7 +18,7 @@ The samples project demonstrates the following: ```java // When no URI is provided for instantiation, the Azure IoT Models Repository global endpoint // https://devicemodels.azure.com/ is used and the model dependency resolution -// configuration is set to TRY_FROM_EXPANDED. +// configuration is set to DISABLED. ModelsRepositoryAsyncClient asyncClient = new ModelsRepositoryClientBuilder() .buildAsyncClient(); From d53333106a23fc592c5e73b8985ee5a274ed625f Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Mon, 27 Sep 2021 02:32:44 -0700 Subject: [PATCH 02/16] Support models repo metadata functionality and eliminate TryFromExpanded from API surface --- .../iot/modelsrepository/DtmiConventions.java | 20 ++++++ .../ModelsRepositoryClientBuilder.java | 2 +- .../implementation/FileModelFetcher.java | 58 ++++++++++++++-- .../implementation/HttpModelFetcher.java | 52 ++++++++++++-- ...java => IntermediateFetchModelResult.java} | 14 ++-- .../implementation/ModelFetcher.java | 6 +- .../ModelsRepositoryConstants.java | 1 + .../implementation/RepositoryHandler.java | 33 +++++++-- .../implementation/StatusStrings.java | 2 + .../models/FetchMetadataResult.java | 67 +++++++++++++++++++ ...FetchResult.java => FetchModelResult.java} | 12 ++-- .../models/ModelsRepositoryMetadata.java | 40 +++++++++++ .../models/RepositoryFeatures.java | 22 ++++++ 13 files changed, 297 insertions(+), 32 deletions(-) rename sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/{IntermediateFetchResult.java => IntermediateFetchModelResult.java} (62%) create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java rename sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/{FetchResult.java => FetchModelResult.java} (82%) create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java index 5a49487c5b98c..1ec8a23d02a19 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java @@ -74,6 +74,26 @@ public static URI getModelUri(String dtmi, URI repositoryUri, boolean expanded) } } + /** + * Generates the model repository's metadata URI. + * + * @param repositoryUri The repository uri + * @return The repository metadata uri. + * @throws IllegalArgumentException if the provided repository URI is not valid + */ + public static URI getMetadataUri(URI repositoryUri) { + try { + String stringUri = repositoryUri.toString(); + if (stringUri.endsWith("/")) { + return new URI(stringUri + ModelsRepositoryConstants.MODELS_REPOSITORY_METADATA_FILE); + } else { + return new URI(stringUri + "/" + ModelsRepositoryConstants.MODELS_REPOSITORY_METADATA_FILE); + } + } catch (URISyntaxException e) { + throw new IllegalArgumentException("Invalid uri syntax"); + } + } + static String dtmiToPath(String dtmi) { if (!isValidDtmi(dtmi)) { throw new IllegalArgumentException(String.format(StatusStrings.INVALID_DTMI_FORMAT_S, dtmi)); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelsRepositoryClientBuilder.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelsRepositoryClientBuilder.java index a8995af01255c..cb949207186c6 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelsRepositoryClientBuilder.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelsRepositoryClientBuilder.java @@ -58,7 +58,7 @@ public final class ModelsRepositoryClientBuilder { // Fields with default values. private URI repositoryEndpoint; - private ModelDependencyResolution modelDependencyResolution = ModelDependencyResolution.DISABLED; + private ModelDependencyResolution modelDependencyResolution = ModelDependencyResolution.ENABLED; // optional/have default values private ModelsRepositoryServiceVersion serviceVersion; diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java index 0ab7967c21503..b5b33030a8eb9 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java @@ -8,7 +8,8 @@ import com.azure.core.util.logging.ClientLogger; import com.azure.iot.modelsrepository.DtmiConventions; import com.azure.iot.modelsrepository.ModelDependencyResolution; -import com.azure.iot.modelsrepository.implementation.models.FetchResult; +import com.azure.iot.modelsrepository.implementation.models.FetchMetadataResult; +import com.azure.iot.modelsrepository.implementation.models.FetchModelResult; import reactor.core.publisher.Mono; import java.io.File; @@ -39,12 +40,15 @@ class FileModelFetcher implements ModelFetcher { } @Override - public Mono fetchAsync(String dtmi, URI repositoryUri, ModelDependencyResolution resolutionOption, Context context) { + public Mono fetchModelAsync(String dtmi, URI repositoryUri, boolean tryFromExpanded, Context context) { return Mono.defer(() -> { Queue work = new LinkedList<>(); try { - work.add(getPath(dtmi, repositoryUri, false)); + if (tryFromExpanded) { + work.add(getModelPath(dtmi, repositoryUri, true)); + } + work.add(getModelPath(dtmi, repositoryUri, false)); } catch (MalformedURLException | URISyntaxException e) { return Mono.error(new AzureException(e)); } @@ -60,7 +64,7 @@ public Mono fetchAsync(String dtmi, URI repositoryUri, ModelDepende if (Files.exists(path)) { try { return Mono.just( - new FetchResult() + new FetchModelResult() .setDefinition(new String(Files.readAllBytes(path), StandardCharsets.UTF_8)) .setPath(tryContentPath)); } catch (IOException e) { @@ -77,8 +81,52 @@ public Mono fetchAsync(String dtmi, URI repositoryUri, ModelDepende }); } - private String getPath(String dtmi, URI repositoryUri, boolean expanded) throws URISyntaxException, MalformedURLException { + @Override + public Mono fetchMetadataAsync(URI repositoryUri, Context context) { + return Mono.defer(() -> { + Queue work = new LinkedList<>(); + + try { + work.add(getMetadataPath(repositoryUri)); + } catch (MalformedURLException | URISyntaxException e) { + return Mono.error(new AzureException(e)); + } + + String fnfError = ""; + while (work.size() != 0) { + String tryContentPath = work.poll(); + + Path path = Paths.get(new File(tryContentPath).getPath()); + + logger.info(StatusStrings.FETCHING_METADATA_CONTENT, path); + + if (Files.exists(path)) { + try { + return Mono.just( + new FetchMetadataResult() + .setDefinition(new String(Files.readAllBytes(path), StandardCharsets.UTF_8)) + .setPath(tryContentPath)); + } catch (IOException e) { + return Mono.error(new AzureException(e)); + } + } + + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, path.toString())); + + fnfError = String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath); + } + + return Mono.error(new AzureException(fnfError)); + }); + } + + private String getModelPath(String dtmi, URI repositoryUri, boolean expanded) throws URISyntaxException, MalformedURLException { return DtmiConventions.getModelUri(dtmi, repositoryUri, expanded) .getPath(); } + + private String getMetadataPath(URI repositoryUri) throws URISyntaxException, MalformedURLException { + return DtmiConventions.getMetadataUri(repositoryUri) + .getPath(); + } } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java index d4c1cfb4aa507..79bfa8ad714a8 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java @@ -8,9 +8,12 @@ import com.azure.core.util.logging.ClientLogger; import com.azure.iot.modelsrepository.DtmiConventions; import com.azure.iot.modelsrepository.ModelDependencyResolution; -import com.azure.iot.modelsrepository.implementation.models.FetchResult; +import com.azure.iot.modelsrepository.implementation.models.FetchMetadataResult; +import com.azure.iot.modelsrepository.implementation.models.FetchModelResult; +import com.fasterxml.jackson.core.JsonProcessingException; import reactor.core.publisher.Mono; +import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; @@ -31,11 +34,11 @@ class HttpModelFetcher implements ModelFetcher { } @Override - public Mono fetchAsync(String dtmi, URI repositoryUri, ModelDependencyResolution resolutionOption, Context context) { + public Mono fetchModelAsync(String dtmi, URI repositoryUri, boolean tryFromExpanded, Context context) { return Mono.defer(() -> { Queue work = new LinkedList<>(); try { - work.add(getPath(dtmi, repositoryUri, false)); + work.add(getModelPath(dtmi, repositoryUri, false)); } catch (Exception e) { return Mono.error(new AzureException(e)); } @@ -49,10 +52,45 @@ public Mono fetchAsync(String dtmi, URI repositoryUri, ModelDepende if (work.size() != 0) { return evaluatePath(work.poll(), context); } else { + logger.error(String.format(StatusStrings.ERROR_FETCHING_MODEL_CONTENT, tryContentPath.toString())); return Mono.error(error); } }) - .map(s -> new FetchResult().setPath(tryContentPath).setDefinition(s)); + .map(s -> new FetchModelResult().setPath(tryContentPath).setDefinition(s)); + }); + } + + @Override + public Mono fetchMetadataAsync(URI repositoryUri, Context context) { + return (Mono) Mono.defer(() -> { + Queue work = new LinkedList<>(); + try { + work.add(getMetadataPath(repositoryUri)); + } catch (Exception e) { + return Mono.error(new AzureException(e)); + } + + String tryContentPath = work.poll(); + + logger.info(StatusStrings.FETCHING_METADATA_CONTENT, tryContentPath); + + return evaluatePath(tryContentPath, context) + .onErrorResume(error -> { + if (work.size() != 0) { + return evaluatePath(work.poll(), context); + } else { + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath.toString())); + return Mono.error(error); + } + }) + .map(s -> { + try { + return new FetchMetadataResult().setPath(tryContentPath).setDefinition(s); + } catch (JsonProcessingException e) { + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath.toString())); + return null; + } + }); }); } @@ -66,7 +104,11 @@ private Mono evaluatePath(String tryContentPath, Context context) { }); } - private String getPath(String dtmi, URI repositoryUri, boolean expanded) throws URISyntaxException { + private String getModelPath(String dtmi, URI repositoryUri, boolean expanded) throws URISyntaxException { return DtmiConventions.getModelUri(dtmi, repositoryUri, expanded).getPath(); } + + private String getMetadataPath(URI repositoryUri) throws URISyntaxException, MalformedURLException { + return DtmiConventions.getMetadataUri(repositoryUri).getPath(); + } } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/IntermediateFetchResult.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/IntermediateFetchModelResult.java similarity index 62% rename from sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/IntermediateFetchResult.java rename to sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/IntermediateFetchModelResult.java index 2b11e3193d977..579d059b7b4b2 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/IntermediateFetchResult.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/IntermediateFetchModelResult.java @@ -3,7 +3,7 @@ package com.azure.iot.modelsrepository.implementation; -import com.azure.iot.modelsrepository.implementation.models.FetchResult; +import com.azure.iot.modelsrepository.implementation.models.FetchModelResult; import java.util.Map; @@ -11,17 +11,17 @@ * This type is used to unify the expand operation return types in the recursive function and has no other use cases. * Do not take any dependencies on this type. */ -class IntermediateFetchResult { - private final FetchResult fetchResult; +class IntermediateFetchModelResult { + private final FetchModelResult fetchModelResult; private final Map map; - IntermediateFetchResult(FetchResult fetchResult, Map map) { - this.fetchResult = fetchResult; + IntermediateFetchModelResult(FetchModelResult fetchModelResult, Map map) { + this.fetchModelResult = fetchModelResult; this.map = map; } - public FetchResult getFetchResult() { - return fetchResult; + public FetchModelResult getFetchModelResult() { + return fetchModelResult; } public Map getMap() { diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelFetcher.java index 1de022101406f..8fc2e5f602d89 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelFetcher.java @@ -5,11 +5,13 @@ import com.azure.core.util.Context; import com.azure.iot.modelsrepository.ModelDependencyResolution; -import com.azure.iot.modelsrepository.implementation.models.FetchResult; +import com.azure.iot.modelsrepository.implementation.models.FetchMetadataResult; +import com.azure.iot.modelsrepository.implementation.models.FetchModelResult; import reactor.core.publisher.Mono; import java.net.URI; interface ModelFetcher { - Mono fetchAsync(String dtmi, URI repositoryUri, ModelDependencyResolution resolutionOption, Context context); + Mono fetchModelAsync(String dtmi, URI repositoryUri, boolean tryFromExpanded, Context context); + Mono fetchMetadataAsync(URI repositoryUri, Context context); } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelsRepositoryConstants.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelsRepositoryConstants.java index f02a265adfa4e..d1efc6044f432 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelsRepositoryConstants.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelsRepositoryConstants.java @@ -9,6 +9,7 @@ public class ModelsRepositoryConstants { public static final String JSON_EXTENSION = ".json"; public static final String JSON_EXPANDED_EXTENSION = ".expanded.json"; public static final String DEFAULT_MODELS_REPOSITORY_ENDPOINT = "https://devicemodels.azure.com"; + public static final String MODELS_REPOSITORY_METADATA_FILE = "metadata.json"; // DTDL conventions public static final String DTDL_TYPE = "@type"; diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index 7560ebb6083f1..a3eb0a6343ee6 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -8,7 +8,8 @@ import com.azure.core.util.logging.ClientLogger; import com.azure.iot.modelsrepository.DtmiConventions; import com.azure.iot.modelsrepository.ModelDependencyResolution; -import com.azure.iot.modelsrepository.implementation.models.FetchResult; +import com.azure.iot.modelsrepository.implementation.models.FetchMetadataResult; +import com.azure.iot.modelsrepository.implementation.models.FetchModelResult; import com.azure.iot.modelsrepository.implementation.models.ModelMetadata; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -21,6 +22,7 @@ import java.util.List; import java.util.LinkedList; import java.util.Locale; +import java.util.concurrent.atomic.AtomicBoolean; public final class RepositoryHandler { @@ -55,10 +57,10 @@ public Mono> processAsync(Iterable dtmis, ModelDepen return processAsync(modelsToProcess, resolutionOptions, context, processedModels) .last() - .map(IntermediateFetchResult::getMap); + .map(IntermediateFetchModelResult::getMap); } - private Flux processAsync( + private Flux processAsync( Queue remainingWork, ModelDependencyResolution resolutionOption, Context context, @@ -69,14 +71,33 @@ private Flux processAsync( } String targetDtmi = remainingWork.poll(); + boolean tryFromExpanded = false; + + // If ModelDependencyResolution.Enabled is requested the client will first attempt to fetch + // metadata.json content from the target repository. The metadata object includes supported features + // of the repository. + // If the metadata indicates expanded models are available. The client will try to fetch pre-computed model + // dependencies using .expanded.json. + // If the model expanded form does not exist fall back to computing model dependencies just-in-time. + if (resolutionOption == ModelDependencyResolution.ENABLED) { + Mono repositoryMetadata = modelFetcher.fetchMetadataAsync(repositoryUri, context); + + tryFromExpanded = repositoryMetadata.flatMap(repo -> { + if (repo != null && repo.getDefinition() != null && + repo.getDefinition().getFeatures() != null && repo.getDefinition().getFeatures().isExpanded()) { + return Mono.just(true); + } + return Mono.just(true); + }).block(); + } logger.info(String.format(StatusStrings.PROCESSING_DTMIS, targetDtmi)); - return modelFetcher.fetchAsync(targetDtmi, repositoryUri, resolutionOption, context) - .map(result -> new IntermediateFetchResult(result, currentResults)) + return modelFetcher.fetchModelAsync(targetDtmi, repositoryUri, tryFromExpanded, context) + .map(result -> new IntermediateFetchModelResult(result, currentResults)) .expand(customType -> { Map results = customType.getMap(); - FetchResult response = customType.getFetchResult(); + FetchModelResult response = customType.getFetchModelResult(); if (response.isFromExpanded()) { try { diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/StatusStrings.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/StatusStrings.java index 64e3ae3d95580..c59b3c0c91b71 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/StatusStrings.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/StatusStrings.java @@ -9,6 +9,8 @@ public class StatusStrings { public static final String PROCESSING_DTMIS = "Processing DTMI \"%s\". "; public static final String DISCOVERED_DEPENDENCIES = "Discovered dependencies \"%s\"."; public static final String FETCHING_MODEL_CONTENT = "Attempting to fetch model content from \"{}\"."; + public static final String FETCHING_METADATA_CONTENT = "Attempting to fetch repository metadata content from \"{}\"."; public static final String ERROR_FETCHING_MODEL_CONTENT = "Model file \"%s\" not found or not accessible in target repository."; + public static final String ERROR_FETCHING_METADATA_CONTENT = "Metadata file \"%s\" not found or not accessible in target repository."; public static final String INCORRECT_DTMI_CASING = "Fetched model has incorrect DTMI casing. Expected \"%s\", parsed \"%s\"."; } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java new file mode 100644 index 0000000000000..20bf1638a32c3 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.iot.modelsrepository.implementation.models; + +import com.azure.core.annotation.Fluent; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * The FetchMetadataResult class is used for storing the result of the + * fetch repository metadata operation. It contains the metadata definition + * and path + */ +@Fluent + +public class FetchMetadataResult { + + private ModelsRepositoryMetadata definition; + private String path; + private final ObjectMapper mapper; + + public FetchMetadataResult() { + mapper = new ObjectMapper(); + } + + /** + * Gets the model repository's metadata definition + * + * @return Repository metadata definition + */ + public ModelsRepositoryMetadata getDefinition() { + return this.definition; + } + + /** + * Sets the model repository's metadata definition + * + * @param definition the model repository's metadata definition + * @return the {@link FetchMetadataResult} object itself + */ + public FetchMetadataResult setDefinition(String definition) throws JsonProcessingException { + this.definition = mapper.readValue(definition, ModelsRepositoryMetadata.class); + return this; + } + + /** + * Gets the model repository's metadata path. + * + * @return model repository's metadata path. + */ + public String getPath() { + return this.path; + } + + /** + * Sets the model repository's metadata path. + * + * @param path the model repository's metadata path. + * @return the {@link FetchMetadataResult} object itself + */ + public FetchMetadataResult setPath(String path) { + this.path = path; + return this; + } + +} diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchResult.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchModelResult.java similarity index 82% rename from sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchResult.java rename to sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchModelResult.java index 78111f08c57e7..559a0dc364c2a 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchResult.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchModelResult.java @@ -9,12 +9,12 @@ import java.util.Locale; /** - * The FetchResult class has the purpose of containing key elements of + * The FetchModelResult class has the purpose of containing key elements of * an IModelFetcher Fetch() operation including model definition, path and whether * it was from an expanded (pre-calculated) fetch. */ @Fluent -public class FetchResult { +public class FetchModelResult { private String definition; private String path; @@ -32,9 +32,9 @@ public String getDefinition() { * Sets the model definition * * @param definition the model definition - * @return the FetchResult object itself + * @return the {@link FetchModelResult} object itself */ - public FetchResult setDefinition(String definition) { + public FetchModelResult setDefinition(String definition) { this.definition = definition; return this; } @@ -52,9 +52,9 @@ public String getPath() { * Sets the dtmi path. * * @param path the dtmi path. - * @return the {@link FetchResult} object itself + * @return the {@link FetchModelResult} object itself */ - public FetchResult setPath(String path) { + public FetchModelResult setPath(String path) { this.path = path; return this; } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java new file mode 100644 index 0000000000000..fee24fc0da42b --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.iot.modelsrepository.implementation.models; + +public class ModelsRepositoryMetadata { + + private final String commitId; + private final String publishDateUtc; + private final String sourceRepo; + private final Integer totalModelCount; + private final RepositoryFeatures features; + + public ModelsRepositoryMetadata(String commitId, String publishDateUtc, + String sourceRepo, Integer totalModelCount, RepositoryFeatures features) { + this.commitId = commitId; + this.publishDateUtc = publishDateUtc; + this.sourceRepo = sourceRepo; + this.totalModelCount = totalModelCount; + this.features = features; + } + + public String getCommitId() { + return this.commitId; + } + + public String getPublishDateUtc() { + return this.publishDateUtc; + } + + public String getSourceRepo() { return this.sourceRepo; } + + public Integer getTotalModelCount() { + return this.totalModelCount; + } + + public RepositoryFeatures getFeatures() { + return this.features; + } +} diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java new file mode 100644 index 0000000000000..a19002e30a94c --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.iot.modelsrepository.implementation.models; + +public class RepositoryFeatures { + private final boolean expanded; + private final boolean index; + + public RepositoryFeatures(boolean expanded, boolean index) { + this.expanded = expanded; + this.index = index; + } + + public boolean isIndex() { + return index; + } + + public boolean isExpanded() { + return expanded; + } +} From 72def96b0de54a73251ab76b604053ffae727fa6 Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Mon, 27 Sep 2021 15:33:42 -0700 Subject: [PATCH 03/16] Lint and refactoring updates --- .../iot/modelsrepository/DtmiConventions.java | 2 +- .../implementation/FileModelFetcher.java | 1 - .../implementation/HttpModelFetcher.java | 12 ++++++---- .../implementation/ModelFetcher.java | 1 - .../implementation/RepositoryHandler.java | 23 +++++++++++-------- .../models/ModelsRepositoryMetadata.java | 4 +++- 6 files changed, 25 insertions(+), 18 deletions(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java index 1ec8a23d02a19..556a4674f594e 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java @@ -82,7 +82,7 @@ public static URI getModelUri(String dtmi, URI repositoryUri, boolean expanded) * @throws IllegalArgumentException if the provided repository URI is not valid */ public static URI getMetadataUri(URI repositoryUri) { - try { + try { String stringUri = repositoryUri.toString(); if (stringUri.endsWith("/")) { return new URI(stringUri + ModelsRepositoryConstants.MODELS_REPOSITORY_METADATA_FILE); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java index b5b33030a8eb9..4e2dbe4376cef 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java @@ -7,7 +7,6 @@ import com.azure.core.util.Context; import com.azure.core.util.logging.ClientLogger; import com.azure.iot.modelsrepository.DtmiConventions; -import com.azure.iot.modelsrepository.ModelDependencyResolution; import com.azure.iot.modelsrepository.implementation.models.FetchMetadataResult; import com.azure.iot.modelsrepository.implementation.models.FetchModelResult; import reactor.core.publisher.Mono; diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java index 79bfa8ad714a8..348fda3c79489 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java @@ -7,7 +7,6 @@ import com.azure.core.util.Context; import com.azure.core.util.logging.ClientLogger; import com.azure.iot.modelsrepository.DtmiConventions; -import com.azure.iot.modelsrepository.ModelDependencyResolution; import com.azure.iot.modelsrepository.implementation.models.FetchMetadataResult; import com.azure.iot.modelsrepository.implementation.models.FetchModelResult; import com.fasterxml.jackson.core.JsonProcessingException; @@ -38,6 +37,9 @@ public Mono fetchModelAsync(String dtmi, URI repositoryUri, bo return Mono.defer(() -> { Queue work = new LinkedList<>(); try { + if (tryFromExpanded) { + work.add(getModelPath(dtmi, repositoryUri, true)); + } work.add(getModelPath(dtmi, repositoryUri, false)); } catch (Exception e) { return Mono.error(new AzureException(e)); @@ -52,7 +54,7 @@ public Mono fetchModelAsync(String dtmi, URI repositoryUri, bo if (work.size() != 0) { return evaluatePath(work.poll(), context); } else { - logger.error(String.format(StatusStrings.ERROR_FETCHING_MODEL_CONTENT, tryContentPath.toString())); + logger.error(String.format(StatusStrings.ERROR_FETCHING_MODEL_CONTENT, tryContentPath)); return Mono.error(error); } }) @@ -62,7 +64,7 @@ public Mono fetchModelAsync(String dtmi, URI repositoryUri, bo @Override public Mono fetchMetadataAsync(URI repositoryUri, Context context) { - return (Mono) Mono.defer(() -> { + return Mono.defer(() -> { Queue work = new LinkedList<>(); try { work.add(getMetadataPath(repositoryUri)); @@ -79,7 +81,7 @@ public Mono fetchMetadataAsync(URI repositoryUri, Context c if (work.size() != 0) { return evaluatePath(work.poll(), context); } else { - logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath.toString())); + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath)); return Mono.error(error); } }) @@ -87,7 +89,7 @@ public Mono fetchMetadataAsync(URI repositoryUri, Context c try { return new FetchMetadataResult().setPath(tryContentPath).setDefinition(s); } catch (JsonProcessingException e) { - logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath.toString())); + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath)); return null; } }); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelFetcher.java index 8fc2e5f602d89..2c9a49bbcee50 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/ModelFetcher.java @@ -4,7 +4,6 @@ package com.azure.iot.modelsrepository.implementation; import com.azure.core.util.Context; -import com.azure.iot.modelsrepository.ModelDependencyResolution; import com.azure.iot.modelsrepository.implementation.models.FetchMetadataResult; import com.azure.iot.modelsrepository.implementation.models.FetchModelResult; import reactor.core.publisher.Mono; diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index a3eb0a6343ee6..f7676b512ce6c 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -22,7 +22,6 @@ import java.util.List; import java.util.LinkedList; import java.util.Locale; -import java.util.concurrent.atomic.AtomicBoolean; public final class RepositoryHandler { @@ -71,7 +70,7 @@ private Flux processAsync( } String targetDtmi = remainingWork.poll(); - boolean tryFromExpanded = false; + Boolean tryFromExpanded = false; // If ModelDependencyResolution.Enabled is requested the client will first attempt to fetch // metadata.json content from the target repository. The metadata object includes supported features @@ -82,13 +81,19 @@ private Flux processAsync( if (resolutionOption == ModelDependencyResolution.ENABLED) { Mono repositoryMetadata = modelFetcher.fetchMetadataAsync(repositoryUri, context); - tryFromExpanded = repositoryMetadata.flatMap(repo -> { - if (repo != null && repo.getDefinition() != null && - repo.getDefinition().getFeatures() != null && repo.getDefinition().getFeatures().isExpanded()) { - return Mono.just(true); - } - return Mono.just(true); - }).block(); + if (repositoryMetadata != null) { + tryFromExpanded = repositoryMetadata + .flatMap(repo -> { + if (repo != null && repo.getDefinition() != null + && repo.getDefinition().getFeatures() != null + && repo.getDefinition().getFeatures().isExpanded()) { + return Mono.just(true); + } + return Mono.just(false); + }) + .defaultIfEmpty(false) + .block(); + } } logger.info(String.format(StatusStrings.PROCESSING_DTMIS, targetDtmi)); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java index fee24fc0da42b..1c5003b0d479f 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java @@ -28,7 +28,9 @@ public String getPublishDateUtc() { return this.publishDateUtc; } - public String getSourceRepo() { return this.sourceRepo; } + public String getSourceRepo() { + return this.sourceRepo; + } public Integer getTotalModelCount() { return this.totalModelCount; From f72ef8a8f0981788adff67ff36a87d9b52b09ff4 Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Tue, 28 Sep 2021 11:42:02 -0700 Subject: [PATCH 04/16] Add models repo metadata file --- .../models/ModelsRepositoryMetadata.java | 8 ++++++++ .../implementation/models/RepositoryFeatures.java | 5 +++++ .../src/test/resources/TestModelRepo/metadata.json | 10 ++++++++++ 3 files changed, 23 insertions(+) create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadata.json diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java index 1c5003b0d479f..38c6ed055af91 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java @@ -20,6 +20,14 @@ public ModelsRepositoryMetadata(String commitId, String publishDateUtc, this.features = features; } + public ModelsRepositoryMetadata() { + this.commitId = null; + this.publishDateUtc = null; + this.sourceRepo = null; + this.totalModelCount = null; + this.features = null; + } + public String getCommitId() { return this.commitId; } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java index a19002e30a94c..dd7372d5730f7 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java @@ -12,6 +12,11 @@ public RepositoryFeatures(boolean expanded, boolean index) { this.index = index; } + public RepositoryFeatures() { + this.expanded = false; + this.index = false; + } + public boolean isIndex() { return index; } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadata.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadata.json new file mode 100644 index 0000000000000..93e3ed185af74 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadata.json @@ -0,0 +1,10 @@ +{ + "commitId": "f49444d5deefa369300c7653b5958f9907da550a", + "features": { + "expanded": true, + "index": true + }, + "publishDateUtc": "2021-09-16T23:01:01.885362+00:00", + "sourceRepo": "Azure/iot-plugandplay-models", + "totalModelCount": 19010 +} From 42910f02077d7bc8e3d76ea37d56bf6934a7b0f3 Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Wed, 29 Sep 2021 15:18:55 -0700 Subject: [PATCH 05/16] Test session file updates --- .../implementation/RepositoryHandler.java | 21 ++--- .../resources/TestModelRepo/metadata.json | 10 ++ ...nTests.getModelsEnsureNoDuplicates[1].json | 92 +++++++++++++++---- ...ts.getModelsSingleDtmiDoesNotExist[1].json | 56 ++++++++--- ....getModelsSingleDtmiNoDependencies[1].json | 46 ++++++++-- ...etModelsSingleDtmiWithDependencies[1].json | 46 ++++++++-- ...ithDepsDisableDependencyResolution[1].json | 16 ++-- 7 files changed, 223 insertions(+), 64 deletions(-) create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/samples/resources/TestModelRepo/metadata.json diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index f7676b512ce6c..699f0e6e9aad9 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -70,7 +70,7 @@ private Flux processAsync( } String targetDtmi = remainingWork.poll(); - Boolean tryFromExpanded = false; + Mono tryFromExpanded = Mono.just(false); // If ModelDependencyResolution.Enabled is requested the client will first attempt to fetch // metadata.json content from the target repository. The metadata object includes supported features @@ -83,22 +83,19 @@ private Flux processAsync( if (repositoryMetadata != null) { tryFromExpanded = repositoryMetadata - .flatMap(repo -> { - if (repo != null && repo.getDefinition() != null - && repo.getDefinition().getFeatures() != null - && repo.getDefinition().getFeatures().isExpanded()) { - return Mono.just(true); - } - return Mono.just(false); - }) - .defaultIfEmpty(false) - .block(); + .map(repo -> ( + repo != null && repo.getDefinition() != null + && repo.getDefinition().getFeatures() != null + && repo.getDefinition().getFeatures().isExpanded() + ) + ) + .defaultIfEmpty(false); } } logger.info(String.format(StatusStrings.PROCESSING_DTMIS, targetDtmi)); - return modelFetcher.fetchModelAsync(targetDtmi, repositoryUri, tryFromExpanded, context) + return tryFromExpanded.flatMap( t -> modelFetcher.fetchModelAsync(targetDtmi, repositoryUri, t, context)) .map(result -> new IntermediateFetchModelResult(result, currentResults)) .expand(customType -> { Map results = customType.getMap(); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/resources/TestModelRepo/metadata.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/resources/TestModelRepo/metadata.json new file mode 100644 index 0000000000000..93e3ed185af74 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/resources/TestModelRepo/metadata.json @@ -0,0 +1,10 @@ +{ + "commitId": "f49444d5deefa369300c7653b5958f9907da550a", + "features": { + "expanded": true, + "index": true + }, + "publishDateUtc": "2021-09-16T23:01:01.885362+00:00", + "sourceRepo": "Azure/iot-plugandplay-models", + "totalModelCount": 19010 +} diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[1].json index 338f1eb18a972..e60c632ad73fd 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[1].json @@ -1,30 +1,90 @@ { "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "7dc7fe26-0ed1-4b3e-a715-eca833f8e803" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "253", + "x-ms-version" : "2018-03-28", + "Server" : "ECAcc (sed/E179)", + "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", + "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "retry-after" : "0", + "StatusCode" : "200", + "Access-Control-Allow-Headers" : "*", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Accept-Ranges" : "bytes", + "Access-Control-Expose-Headers" : "*", + "Cache-Control" : "max-age=600", + "Etag" : "\"0x8D983861F20E768\"", + "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", + "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", + "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", + "Age" : "88", + "Content-Type" : "application/json" + }, + "Exception" : null + }, { "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fazure%2Fdevicemanagement%2Fdeviceinformation-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.1.0-beta.1 (11.0.7; Windows 10; 10.0)", - "x-ms-client-request-id" : "7b951b25-6790-4d63-ab89-fd20e797ce2a" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "ca6f1a0e-34f7-48a0-84b3-e645316a5712" }, "Response" : { "X-Cache" : "HIT", + "content-length" : "2218", "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E10D)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Tue, 15 Dec 2020 21:10:59 GMT", + "Last-Modified" : "Wed, 14 Apr 2021 00:08:03 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Tue, 23 Mar 2021 22:20:07 GMT", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", "Content-MD5" : "Vw1WdSQoTBOhmiB9XXUwsw==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", - "Etag" : "\"0x8D8A13DEBC85F73\"", + "Etag" : "\"0x8D8FED95F570217\"", "x-ms-error-code" : "ConditionNotMet", - "Content-Length" : "2218", - "x-ms-request-id" : "36be9211-f01e-0028-1238-1cfe51000000", + "x-ms-request-id" : "cd64bea0-001e-001e-6b16-b48ab4000000", "Body" : "[\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Device Information\",\n \"contents\": [\n {\n \"@type\": \"Property\",\n \"name\": \"manufacturer\",\n \"displayName\": \"Manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"model\",\n \"displayName\": \"Device model\",\n \"schema\": \"string\",\n \"description\": \"Device model name or ID. Ex. Surface Book 2.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"swVersion\",\n \"displayName\": \"Software version\",\n \"schema\": \"string\",\n \"description\": \"Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"osName\",\n \"displayName\": \"Operating system name\",\n \"schema\": \"string\",\n \"description\": \"Name of the operating system on the device. Ex. Windows 10 IoT Core.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorArchitecture\",\n \"displayName\": \"Processor architecture\",\n \"schema\": \"string\",\n \"description\": \"Architecture of the processor on the device. Ex. x64 or ARM.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorManufacturer\",\n \"displayName\": \"Processor manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Name of the manufacturer of the processor on the device. Ex. Intel.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalStorage\",\n \"displayName\": \"Total storage\",\n \"schema\": \"double\",\n \"description\": \"Total available storage on the device in kilobytes. Ex. 2048000 kilobytes.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalMemory\",\n \"displayName\": \"Total memory\",\n \"schema\": \"double\",\n \"description\": \"Total available memory on the device in kilobytes. Ex. 256000 kilobytes.\"\n }\n ]\n }\n]", - "Age" : "437504", + "Age" : "153814", + "Content-Type" : "application/json" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "322d8b05-cd1e-4fd2-af64-0e214771a82e" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "253", + "x-ms-version" : "2018-03-28", + "Server" : "ECAcc (sed/E179)", + "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", + "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "retry-after" : "0", + "StatusCode" : "200", + "Access-Control-Allow-Headers" : "*", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Accept-Ranges" : "bytes", + "Access-Control-Expose-Headers" : "*", + "Cache-Control" : "max-age=600", + "Etag" : "\"0x8D983861F20E768\"", + "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", + "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", + "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", + "Age" : "88", "Content-Type" : "application/json" }, "Exception" : null @@ -32,28 +92,28 @@ "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fazure%2Fdevicemanagement%2Fdeviceinformation-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.1.0-beta.1 (11.0.7; Windows 10; 10.0)", - "x-ms-client-request-id" : "57490341-ee0b-4248-8c2e-9a79b7aa0fa7" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "01b6e25e-dee4-4932-8b41-763658708fee" }, "Response" : { "X-Cache" : "HIT", + "content-length" : "2218", "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E10D)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Tue, 15 Dec 2020 21:10:59 GMT", + "Last-Modified" : "Wed, 14 Apr 2021 00:08:03 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Tue, 23 Mar 2021 22:20:07 GMT", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", "Content-MD5" : "Vw1WdSQoTBOhmiB9XXUwsw==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", - "Etag" : "\"0x8D8A13DEBC85F73\"", + "Etag" : "\"0x8D8FED95F570217\"", "x-ms-error-code" : "ConditionNotMet", - "Content-Length" : "2218", - "x-ms-request-id" : "36be9211-f01e-0028-1238-1cfe51000000", + "x-ms-request-id" : "cd64bea0-001e-001e-6b16-b48ab4000000", "Body" : "[\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Device Information\",\n \"contents\": [\n {\n \"@type\": \"Property\",\n \"name\": \"manufacturer\",\n \"displayName\": \"Manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"model\",\n \"displayName\": \"Device model\",\n \"schema\": \"string\",\n \"description\": \"Device model name or ID. Ex. Surface Book 2.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"swVersion\",\n \"displayName\": \"Software version\",\n \"schema\": \"string\",\n \"description\": \"Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"osName\",\n \"displayName\": \"Operating system name\",\n \"schema\": \"string\",\n \"description\": \"Name of the operating system on the device. Ex. Windows 10 IoT Core.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorArchitecture\",\n \"displayName\": \"Processor architecture\",\n \"schema\": \"string\",\n \"description\": \"Architecture of the processor on the device. Ex. x64 or ARM.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorManufacturer\",\n \"displayName\": \"Processor manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Name of the manufacturer of the processor on the device. Ex. Intel.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalStorage\",\n \"displayName\": \"Total storage\",\n \"schema\": \"double\",\n \"description\": \"Total available storage on the device in kilobytes. Ex. 2048000 kilobytes.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalMemory\",\n \"displayName\": \"Total memory\",\n \"schema\": \"double\",\n \"description\": \"Total available memory on the device in kilobytes. Ex. 256000 kilobytes.\"\n }\n ]\n }\n]", - "Age" : "437504", + "Age" : "153814", "Content-Type" : "application/json" }, "Exception" : null diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[1].json index ffa602fc472c9..90166cf65e312 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[1].json @@ -1,24 +1,55 @@ { "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "c9391aad-48fb-4676-adad-18d30bbcd39f" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "253", + "x-ms-version" : "2018-03-28", + "Server" : "ECAcc (sed/E179)", + "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", + "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "retry-after" : "0", + "StatusCode" : "200", + "Access-Control-Allow-Headers" : "*", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Accept-Ranges" : "bytes", + "Access-Control-Expose-Headers" : "*", + "Cache-Control" : "max-age=600", + "Etag" : "\"0x8D983861F20E768\"", + "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", + "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", + "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", + "Age" : "88", + "Content-Type" : "application/json" + }, + "Exception" : null + }, { "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Fthermostatddd-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.1.0-beta.1 (11.0.7; Windows 10; 10.0)", - "x-ms-client-request-id" : "a8905328-6bf9-4a21-92bd-e78de3658d58" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "a5a24337-efd8-482e-89cc-630bcfc4358f" }, "Response" : { + "content-length" : "321", "x-ms-version" : "2018-03-28", "Server" : "Windows-Azure-Web/1.0 Microsoft-HTTPAPI/2.0", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", "retry-after" : "0", "StatusCode" : "404", "Access-Control-Allow-Headers" : "*", - "Date" : "Tue, 23 Mar 2021 22:20:07 GMT", + "Date" : "Wed, 29 Sep 2021 21:52:06 GMT", "Access-Control-Expose-Headers" : "*", + "Vary" : "Origin", "x-ms-error-code" : "WebContentNotFound", - "Content-Length" : "321", - "x-ms-request-id" : "3c9fb664-c01e-004b-3232-20c175000000", - "Body" : "WebContentNotFound

The requested content does not exist.

  • HttpStatusCode: 404
  • ErrorCode: WebContentNotFound
  • RequestId : 3c9fb664-c01e-004b-3232-20c175000000
  • TimeStamp : 2021-03-23T22:20:07.2215660Z

", + "x-ms-request-id" : "2ef2ac7f-401e-00a2-257c-b508e9000000", + "Body" : "WebContentNotFound

The requested content does not exist.

  • HttpStatusCode: 404
  • ErrorCode: WebContentNotFound
  • RequestId : 2ef2ac7f-401e-00a2-257c-b508e9000000
  • TimeStamp : 2021-09-29T21:52:07.4957322Z

", "Content-Type" : "text/html" }, "Exception" : null @@ -26,22 +57,23 @@ "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Fthermostatddd-1.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.1.0-beta.1 (11.0.7; Windows 10; 10.0)", - "x-ms-client-request-id" : "e833bda3-456a-470f-862b-b11625f09186" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "f12aca18-2bae-41e6-bb41-e72487de135e" }, "Response" : { + "content-length" : "321", "x-ms-version" : "2018-03-28", "Server" : "Windows-Azure-Web/1.0 Microsoft-HTTPAPI/2.0", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", "retry-after" : "0", "StatusCode" : "404", "Access-Control-Allow-Headers" : "*", - "Date" : "Tue, 23 Mar 2021 22:20:06 GMT", + "Date" : "Wed, 29 Sep 2021 21:52:06 GMT", "Access-Control-Expose-Headers" : "*", + "Vary" : "Origin", "x-ms-error-code" : "WebContentNotFound", - "Content-Length" : "321", - "x-ms-request-id" : "5b308299-601e-0051-0632-207f42000000", - "Body" : "WebContentNotFound

The requested content does not exist.

  • HttpStatusCode: 404
  • ErrorCode: WebContentNotFound
  • RequestId : 5b308299-601e-0051-0632-207f42000000
  • TimeStamp : 2021-03-23T22:20:07.3151755Z

", + "x-ms-request-id" : "5250b7e1-501e-006b-317c-b5ffbe000000", + "Body" : "WebContentNotFound

The requested content does not exist.

  • HttpStatusCode: 404
  • ErrorCode: WebContentNotFound
  • RequestId : 5250b7e1-501e-006b-317c-b5ffbe000000
  • TimeStamp : 2021-09-29T21:52:07.5558209Z

", "Content-Type" : "text/html" }, "Exception" : null diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[1].json index 1c9f133670f38..f01fab5e51c8a 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[1].json @@ -1,30 +1,60 @@ { "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "95e5e01c-6785-4402-bd80-d06d174a5dee" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "253", + "x-ms-version" : "2018-03-28", + "Server" : "ECAcc (sed/E179)", + "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", + "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "retry-after" : "0", + "StatusCode" : "200", + "Access-Control-Allow-Headers" : "*", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Accept-Ranges" : "bytes", + "Access-Control-Expose-Headers" : "*", + "Cache-Control" : "max-age=600", + "Etag" : "\"0x8D983861F20E768\"", + "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", + "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", + "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", + "Age" : "88", + "Content-Type" : "application/json" + }, + "Exception" : null + }, { "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Fthermostat-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.1.0-beta.1 (11.0.7; Windows 10; 10.0)", - "x-ms-client-request-id" : "ce4f8dc5-3ea1-40b6-b04a-acdf4c035775" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "0ff85bcd-037a-44dd-9cbc-6d975ef85407" }, "Response" : { "X-Cache" : "HIT", + "content-length" : "2651", "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E120)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Tue, 15 Dec 2020 21:10:57 GMT", + "Last-Modified" : "Wed, 14 Apr 2021 00:07:35 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Tue, 23 Mar 2021 22:20:07 GMT", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", "Content-MD5" : "pH51cS5+u5tWh2Krmys7qA==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", - "Etag" : "\"0x8D8A13DEAC57DB3\"", + "Etag" : "\"0x8D8FED94ECA13B6\"", "x-ms-error-code" : "ConditionNotMet", - "Content-Length" : "2651", - "x-ms-request-id" : "0552d4aa-d01e-006e-4479-1fd74c000000", + "x-ms-request-id" : "e422263d-601e-005c-3c16-b40fa1000000", "Body" : "[\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:Thermostat;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Thermostat\",\n \"description\": \"Reports current temperature and provides desired temperature control.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"Temperature\"\n ],\n \"name\": \"temperature\",\n \"displayName\": \"Temperature\",\n \"description\": \"Temperature in degrees Celsius.\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\"\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"targetTemperature\",\n \"schema\": \"double\",\n \"displayName\": \"Target Temperature\",\n \"description\": \"Allows to remotely specify the desired target temperature.\",\n \"unit\": \"degreeCelsius\",\n \"writable\": true\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"maxTempSinceLastReboot\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\",\n \"displayName\": \"Max temperature since last reboot.\",\n \"description\": \"Returns the max temperature since last device reboot.\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"getMaxMinReport\",\n \"displayName\": \"Get Max-Min report.\",\n \"description\": \"This command returns the max, min and average temperature from the specified time to the current time.\",\n \"request\": {\n \"name\": \"since\",\n \"displayName\": \"Since\",\n \"description\": \"Period to return the max-min report.\",\n \"schema\": \"dateTime\"\n },\n \"response\": {\n \"name\": \"tempReport\",\n \"displayName\": \"Temperature Report\",\n \"schema\": {\n \"@type\": \"Object\",\n \"fields\": [\n {\n \"name\": \"maxTemp\",\n \"displayName\": \"Max temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"minTemp\",\n \"displayName\": \"Min temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"avgTemp\",\n \"displayName\": \"Average Temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"startTime\",\n \"displayName\": \"Start Time\",\n \"schema\": \"dateTime\"\n },\n {\n \"name\": \"endTime\",\n \"displayName\": \"End Time\",\n \"schema\": \"dateTime\"\n }\n ]\n }\n }\n }\n ]\n }\n]", - "Age" : "79705", + "Age" : "153814", "Content-Type" : "application/json" }, "Exception" : null diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[1].json index 90fb9b50ca99f..ea57f4b8fdca8 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[1].json @@ -1,30 +1,60 @@ { "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "84d9acca-021e-4282-95c0-eb64b823ae32" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "253", + "x-ms-version" : "2018-03-28", + "Server" : "ECAcc (sed/E179)", + "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", + "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "retry-after" : "0", + "StatusCode" : "200", + "Access-Control-Allow-Headers" : "*", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Accept-Ranges" : "bytes", + "Access-Control-Expose-Headers" : "*", + "Cache-Control" : "max-age=600", + "Etag" : "\"0x8D983861F20E768\"", + "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", + "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", + "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", + "Age" : "88", + "Content-Type" : "application/json" + }, + "Exception" : null + }, { "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Ftemperaturecontroller-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.1.0-beta.1 (11.0.7; Windows 10; 10.0)", - "x-ms-client-request-id" : "7b3aa5e5-c95b-46cd-b56a-52ba98c32fac" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "f2fa1841-6f6e-499d-807b-6015ab5d271b" }, "Response" : { "X-Cache" : "HIT", + "content-length" : "6751", "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E17F)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Tue, 15 Dec 2020 21:10:57 GMT", + "Last-Modified" : "Wed, 14 Apr 2021 00:07:35 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Tue, 23 Mar 2021 22:20:07 GMT", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", "Content-MD5" : "BnZpV2+7Z2t0sxAxOhmBdw==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", - "Etag" : "\"0x8D8A13DEAC10FCC\"", + "Etag" : "\"0x8D8FED94EBE03D1\"", "x-ms-error-code" : "ConditionNotMet", - "Content-Length" : "6751", - "x-ms-request-id" : "1b12122f-b01e-0044-7f29-1c486a000000", + "x-ms-request-id" : "461deecb-f01e-004d-0e16-b49481000000", "Body" : "[\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:TemperatureController;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Temperature Controller\",\n \"description\": \"Device with two thermostats and remote reboot.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"DataSize\"\n ],\n \"name\": \"workingSet\",\n \"displayName\": \"Working Set\",\n \"description\": \"Current working set of the device memory in KiB.\",\n \"schema\": \"double\",\n \"unit\": \"kibibyte\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"serialNumber\",\n \"displayName\": \"Serial Number\",\n \"description\": \"Serial number of the device.\",\n \"schema\": \"string\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"reboot\",\n \"displayName\": \"Reboot\",\n \"description\": \"Reboots the device after waiting the number of seconds specified.\",\n \"request\": {\n \"name\": \"delay\",\n \"displayName\": \"Delay\",\n \"description\": \"Number of seconds to wait before rebooting the device.\",\n \"schema\": \"integer\"\n }\n },\n {\n \"@type\": \"Component\",\n \"schema\": \"dtmi:com:example:Thermostat;1\",\n \"name\": \"thermostat1\",\n \"displayName\": \"Thermostat One\",\n \"description\": \"Thermostat One of Two.\"\n },\n {\n \"@type\": \"Component\",\n \"schema\": \"dtmi:com:example:Thermostat;1\",\n \"name\": \"thermostat2\",\n \"displayName\": \"Thermostat Two\",\n \"description\": \"Thermostat Two of Two.\"\n },\n {\n \"@type\": \"Component\",\n \"schema\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"name\": \"deviceInformation\",\n \"displayName\": \"Device Information interface\",\n \"description\": \"Optional interface with basic device hardware information.\"\n }\n ]\n },\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:Thermostat;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Thermostat\",\n \"description\": \"Reports current temperature and provides desired temperature control.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"Temperature\"\n ],\n \"name\": \"temperature\",\n \"displayName\": \"Temperature\",\n \"description\": \"Temperature in degrees Celsius.\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\"\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"targetTemperature\",\n \"schema\": \"double\",\n \"displayName\": \"Target Temperature\",\n \"description\": \"Allows to remotely specify the desired target temperature.\",\n \"unit\": \"degreeCelsius\",\n \"writable\": true\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"maxTempSinceLastReboot\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\",\n \"displayName\": \"Max temperature since last reboot.\",\n \"description\": \"Returns the max temperature since last device reboot.\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"getMaxMinReport\",\n \"displayName\": \"Get Max-Min report.\",\n \"description\": \"This command returns the max, min and average temperature from the specified time to the current time.\",\n \"request\": {\n \"name\": \"since\",\n \"displayName\": \"Since\",\n \"description\": \"Period to return the max-min report.\",\n \"schema\": \"dateTime\"\n },\n \"response\": {\n \"name\": \"tempReport\",\n \"displayName\": \"Temperature Report\",\n \"schema\": {\n \"@type\": \"Object\",\n \"fields\": [\n {\n \"name\": \"maxTemp\",\n \"displayName\": \"Max temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"minTemp\",\n \"displayName\": \"Min temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"avgTemp\",\n \"displayName\": \"Average Temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"startTime\",\n \"displayName\": \"Start Time\",\n \"schema\": \"dateTime\"\n },\n {\n \"name\": \"endTime\",\n \"displayName\": \"End Time\",\n \"schema\": \"dateTime\"\n }\n ]\n }\n }\n }\n ]\n },\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Device Information\",\n \"contents\": [\n {\n \"@type\": \"Property\",\n \"name\": \"manufacturer\",\n \"displayName\": \"Manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"model\",\n \"displayName\": \"Device model\",\n \"schema\": \"string\",\n \"description\": \"Device model name or ID. Ex. Surface Book 2.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"swVersion\",\n \"displayName\": \"Software version\",\n \"schema\": \"string\",\n \"description\": \"Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"osName\",\n \"displayName\": \"Operating system name\",\n \"schema\": \"string\",\n \"description\": \"Name of the operating system on the device. Ex. Windows 10 IoT Core.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorArchitecture\",\n \"displayName\": \"Processor architecture\",\n \"schema\": \"string\",\n \"description\": \"Architecture of the processor on the device. Ex. x64 or ARM.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorManufacturer\",\n \"displayName\": \"Processor manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Name of the manufacturer of the processor on the device. Ex. Intel.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalStorage\",\n \"displayName\": \"Total storage\",\n \"schema\": \"double\",\n \"description\": \"Total available storage on the device in kilobytes. Ex. 2048000 kilobytes.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalMemory\",\n \"displayName\": \"Total memory\",\n \"schema\": \"double\",\n \"description\": \"Total available memory on the device in kilobytes. Ex. 256000 kilobytes.\"\n }\n ]\n }\n]", - "Age" : "443781", + "Age" : "153815", "Content-Type" : "application/json" }, "Exception" : null diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[1].json index 54051cf4b7951..bd9a808e3413a 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[1].json @@ -3,28 +3,28 @@ "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Fthermostat-1.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.1.0-beta.1 (11.0.7; Windows 10; 10.0)", - "x-ms-client-request-id" : "537a41a9-a508-4e4a-8390-6399bb3ffb01" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", + "x-ms-client-request-id" : "9905c36a-b2ab-4747-9660-197dad311446" }, "Response" : { "X-Cache" : "HIT", + "content-length" : "2469", "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E107)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Tue, 15 Dec 2020 21:10:57 GMT", + "Last-Modified" : "Wed, 14 Apr 2021 00:07:35 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Tue, 23 Mar 2021 22:20:07 GMT", + "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", "Content-MD5" : "U0VZgOgpfb6bwvG5UDVZuw==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", - "Etag" : "\"0x8D8A13DEABC53BA\"", + "Etag" : "\"0x8D8FED94ED5FC94\"", "x-ms-error-code" : "ConditionNotMet", - "Content-Length" : "2469", - "x-ms-request-id" : "3e2ce5fe-301e-0060-0838-1c7551000000", + "x-ms-request-id" : "22c4d7b0-d01e-0073-1816-b4178d000000", "Body" : "{\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:Thermostat;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Thermostat\",\n \"description\": \"Reports current temperature and provides desired temperature control.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"Temperature\"\n ],\n \"name\": \"temperature\",\n \"displayName\": \"Temperature\",\n \"description\": \"Temperature in degrees Celsius.\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\"\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"targetTemperature\",\n \"schema\": \"double\",\n \"displayName\": \"Target Temperature\",\n \"description\": \"Allows to remotely specify the desired target temperature.\",\n \"unit\": \"degreeCelsius\",\n \"writable\": true\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"maxTempSinceLastReboot\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\",\n \"displayName\": \"Max temperature since last reboot.\",\n \"description\": \"Returns the max temperature since last device reboot.\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"getMaxMinReport\",\n \"displayName\": \"Get Max-Min report.\",\n \"description\": \"This command returns the max, min and average temperature from the specified time to the current time.\",\n \"request\": {\n \"name\": \"since\",\n \"displayName\": \"Since\",\n \"description\": \"Period to return the max-min report.\",\n \"schema\": \"dateTime\"\n },\n \"response\": {\n \"name\": \"tempReport\",\n \"displayName\": \"Temperature Report\",\n \"schema\": {\n \"@type\": \"Object\",\n \"fields\": [\n {\n \"name\": \"maxTemp\",\n \"displayName\": \"Max temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"minTemp\",\n \"displayName\": \"Min temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"avgTemp\",\n \"displayName\": \"Average Temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"startTime\",\n \"displayName\": \"Start Time\",\n \"schema\": \"dateTime\"\n },\n {\n \"name\": \"endTime\",\n \"displayName\": \"End Time\",\n \"schema\": \"dateTime\"\n }\n ]\n }\n }\n }\n ]\n}", - "Age" : "437504", + "Age" : "153814", "Content-Type" : "application/json" }, "Exception" : null From aa142dc4cb3676bcb46c2bd420b03143eabe1b48 Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Wed, 29 Sep 2021 16:03:52 -0700 Subject: [PATCH 06/16] Address comments --- .../modelsrepository/implementation/RepositoryHandler.java | 3 ++- .../implementation/models/FetchMetadataResult.java | 6 +----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index 699f0e6e9aad9..d4fc46e26d61b 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -95,7 +95,8 @@ private Flux processAsync( logger.info(String.format(StatusStrings.PROCESSING_DTMIS, targetDtmi)); - return tryFromExpanded.flatMap( t -> modelFetcher.fetchModelAsync(targetDtmi, repositoryUri, t, context)) + return tryFromExpanded + .flatMap (tryExpanded -> modelFetcher.fetchModelAsync(targetDtmi, repositoryUri, tryExpanded, context)) .map(result -> new IntermediateFetchModelResult(result, currentResults)) .expand(customType -> { Map results = customType.getMap(); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java index 20bf1638a32c3..34e19a355fc98 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java @@ -18,11 +18,7 @@ public class FetchMetadataResult { private ModelsRepositoryMetadata definition; private String path; - private final ObjectMapper mapper; - - public FetchMetadataResult() { - mapper = new ObjectMapper(); - } + private static final ObjectMapper mapper = new ObjectMapper(); /** * Gets the model repository's metadata definition From 765354f7f681678378f2618757f160631ca0698c Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Wed, 29 Sep 2021 16:23:18 -0700 Subject: [PATCH 07/16] Lint updates --- .../modelsrepository/implementation/RepositoryHandler.java | 2 +- .../implementation/models/FetchMetadataResult.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index d4fc46e26d61b..43aaa69295357 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -96,7 +96,7 @@ private Flux processAsync( logger.info(String.format(StatusStrings.PROCESSING_DTMIS, targetDtmi)); return tryFromExpanded - .flatMap (tryExpanded -> modelFetcher.fetchModelAsync(targetDtmi, repositoryUri, tryExpanded, context)) + .flatMap(tryExpanded -> modelFetcher.fetchModelAsync(targetDtmi, repositoryUri, tryExpanded, context)) .map(result -> new IntermediateFetchModelResult(result, currentResults)) .expand(customType -> { Map results = customType.getMap(); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java index 34e19a355fc98..cb88c8c679416 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java @@ -18,7 +18,7 @@ public class FetchMetadataResult { private ModelsRepositoryMetadata definition; private String path; - private static final ObjectMapper mapper = new ObjectMapper(); + private static final ObjectMapper MAPPER = new ObjectMapper(); /** * Gets the model repository's metadata definition @@ -36,7 +36,7 @@ public ModelsRepositoryMetadata getDefinition() { * @return the {@link FetchMetadataResult} object itself */ public FetchMetadataResult setDefinition(String definition) throws JsonProcessingException { - this.definition = mapper.readValue(definition, ModelsRepositoryMetadata.class); + this.definition = MAPPER.readValue(definition, ModelsRepositoryMetadata.class); return this; } From 7c97bb051f887168bc8eaf4ea4b3059c273aed8b Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Wed, 29 Sep 2021 19:17:16 -0700 Subject: [PATCH 08/16] Metadata fetch errors are non terminal, update tests and documentation --- .../ModelDependencyResolution.java | 2 +- .../implementation/FileModelFetcher.java | 24 ++++------ .../implementation/HttpModelFetcher.java | 45 +++++++++---------- .../src/samples/README.md | 2 +- .../iot/core/ModelResolutionSamples.java | 8 ++-- .../modelsrepository/DtmiConventionTests.java | 21 +++++++++ 6 files changed, 56 insertions(+), 46 deletions(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelDependencyResolution.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelDependencyResolution.java index 3110ee8276bd4..af2b54c92113d 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelDependencyResolution.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/ModelDependencyResolution.java @@ -13,7 +13,7 @@ public enum ModelDependencyResolution { DISABLED, /** - * Enable model dependency resolution. The client will parse models and calculate dependencies recursively. + * Enable model dependency resolution. */ ENABLED, } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java index 4e2dbe4376cef..2563c292bfcab 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java @@ -83,18 +83,9 @@ public Mono fetchModelAsync(String dtmi, URI repositoryUri, bo @Override public Mono fetchMetadataAsync(URI repositoryUri, Context context) { return Mono.defer(() -> { - Queue work = new LinkedList<>(); try { - work.add(getMetadataPath(repositoryUri)); - } catch (MalformedURLException | URISyntaxException e) { - return Mono.error(new AzureException(e)); - } - - String fnfError = ""; - while (work.size() != 0) { - String tryContentPath = work.poll(); - + String tryContentPath = getMetadataPath(repositoryUri); Path path = Paths.get(new File(tryContentPath).getPath()); logger.info(StatusStrings.FETCHING_METADATA_CONTENT, path); @@ -106,16 +97,17 @@ public Mono fetchMetadataAsync(URI repositoryUri, Context c .setDefinition(new String(Files.readAllBytes(path), StandardCharsets.UTF_8)) .setPath(tryContentPath)); } catch (IOException e) { - return Mono.error(new AzureException(e)); + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT + " Error: %s.", + path.toString(), e.getMessage())); + return null; } } logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, path.toString())); - - fnfError = String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath); + return null; + } catch (MalformedURLException | URISyntaxException e) { + return Mono.error(new AzureException(e)); } - - return Mono.error(new AzureException(fnfError)); }); } @@ -124,7 +116,7 @@ private String getModelPath(String dtmi, URI repositoryUri, boolean expanded) th .getPath(); } - private String getMetadataPath(URI repositoryUri) throws URISyntaxException, MalformedURLException { + private String getMetadataPath(URI repositoryUri) throws URISyntaxException, MalformedURLException { return DtmiConventions.getMetadataUri(repositoryUri) .getPath(); } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java index 348fda3c79489..0ae6536450c4f 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java @@ -65,34 +65,31 @@ public Mono fetchModelAsync(String dtmi, URI repositoryUri, bo @Override public Mono fetchMetadataAsync(URI repositoryUri, Context context) { return Mono.defer(() -> { - Queue work = new LinkedList<>(); try { - work.add(getMetadataPath(repositoryUri)); - } catch (Exception e) { - return Mono.error(new AzureException(e)); - } + String tryContentPath = getMetadataPath(repositoryUri); - String tryContentPath = work.poll(); + logger.info(StatusStrings.FETCHING_METADATA_CONTENT, tryContentPath); - logger.info(StatusStrings.FETCHING_METADATA_CONTENT, tryContentPath); - - return evaluatePath(tryContentPath, context) - .onErrorResume(error -> { - if (work.size() != 0) { - return evaluatePath(work.poll(), context); - } else { - logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath)); - return Mono.error(error); - } - }) - .map(s -> { - try { - return new FetchMetadataResult().setPath(tryContentPath).setDefinition(s); - } catch (JsonProcessingException e) { - logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath)); + return evaluatePath(tryContentPath, context) + .onErrorResume(error -> { + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT + " Error: %s", + tryContentPath, error.getMessage())); return null; - } - }); + }) + .map(s -> { + try { + if (s == null) { + return null; + } + return new FetchMetadataResult().setPath(tryContentPath).setDefinition(s); + } catch (JsonProcessingException e) { + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath)); + return null; + } + }); + } catch (MalformedURLException | URISyntaxException e) { + return Mono.error(new AzureException(e)); + } }); } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/README.md b/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/README.md index 4728db6067b6a..33ac8717a2959 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/README.md +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/README.md @@ -18,7 +18,7 @@ The samples project demonstrates the following: ```java // When no URI is provided for instantiation, the Azure IoT Models Repository global endpoint // https://devicemodels.azure.com/ is used and the model dependency resolution -// configuration is set to DISABLED. +// configuration is set to ENABLED. ModelsRepositoryAsyncClient asyncClient = new ModelsRepositoryClientBuilder() .buildAsyncClient(); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/java/com/azure/iot/core/ModelResolutionSamples.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/java/com/azure/iot/core/ModelResolutionSamples.java index 4a2f8501dc907..e1601bba44a01 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/java/com/azure/iot/core/ModelResolutionSamples.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/java/com/azure/iot/core/ModelResolutionSamples.java @@ -21,7 +21,7 @@ public class ModelResolutionSamples { public static void clientInitializationSamples() { // When no URI is provided for instantiation, the Azure IoT Models Repository global endpoint // https://devicemodels.azure.com/ is used and the model dependency resolution - // configuration is set to TryFromExpanded. + // configuration is set to Enabled. ModelsRepositoryAsyncClient asyncClient = new ModelsRepositoryClientBuilder() .buildAsyncClient(); @@ -70,7 +70,7 @@ public static void getModelsFromGlobalRepository() throws InterruptedException { .buildAsyncClient(); // The output of getModels will include at least the definition for the target dtmi. - // If the model dependency resolution configuration is not disabled, then models in which the + // If the model dependency resolution configuration is enabled, then models in which the // target dtmi depends on will also be included in the returned Map. String targetDtmi = "dtmi:com:example:TemperatureController;1"; @@ -92,7 +92,7 @@ public static void getMultipleModelsFromGlobalRepository() throws InterruptedExc // When given an Iterable of dtmis, the output of getModels() will include at // least the definitions of each dtmi enumerated in the Iterable. - // If the model dependency resolution configuration is not disabled, then models in which each + // If the model dependency resolution configuration is enabled, then models in which each // enumerated dtmi depends on will also be included in the returned Map. Iterable dtmis = Arrays.asList("dtmi:com:example:TemperatureController;1", "dtmi:com:example:azuresphere:sampledevice;1"); @@ -115,7 +115,7 @@ public static void getModelsFromLocalRepository() throws InterruptedException { .buildAsyncClient(); // The output of getModels will include at least the definition for the target dtmi. - // If the model dependency resolution configuration is not disabled, then models in which the + // If the model dependency resolution configuration is enabled, then models in which the // target dtmi depends on will also be included in the returned Map. String targetDtmi = "dtmi:com:example:TemperatureController;1"; diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/DtmiConventionTests.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/DtmiConventionTests.java index e6a85d3ca2e0f..ddabff67f62c2 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/DtmiConventionTests.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/DtmiConventionTests.java @@ -53,6 +53,27 @@ public void getModelUriTests(String repository, String expectedUri) { Assertions.assertEquals(expectedUri, modelUri.toString()); } + @ParameterizedTest + @CsvSource({ + "https://localhost/repository/, https://localhost/repository/metadata.json", + "https://localhost/REPOSITORY, https://localhost/REPOSITORY/metadata.json", + "file:///path/to/repository/, file:///path/to/repository/metadata.json", + "file://path/to/RepoSitory, file://path/to/RepoSitory/metadata.json", + "C:/path/to/repository/, C:/path/to/repository/metadata.json", + "//server//repository, //server//repository/metadata.json" + }) + public void getMetadataUriTests(String repository, String expectedUri) { + URI repositoryUri = TestHelper.convertToUri(repository); + + if (expectedUri == null || expectedUri.isEmpty()) { + Assertions.assertThrows(IllegalArgumentException.class, () -> DtmiConventions.getMetadataUri(repositoryUri)); + return; + } + + URI metadataUri = DtmiConventions.getMetadataUri(repositoryUri); + Assertions.assertEquals(expectedUri, metadataUri.toString()); + } + @ParameterizedTest @CsvSource({ "dtmi:com:example:Thermostat;1, true", From 38dc53e574808c5eca8d2e9f2662c812aa281a51 Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Mon, 4 Oct 2021 00:35:39 -0700 Subject: [PATCH 09/16] Add more tests --- .../iot/modelsrepository/DtmiConventions.java | 4 +- .../implementation/FileModelFetcher.java | 4 +- .../implementation/HttpModelFetcher.java | 5 +- .../ModelRepositoryIntegrationTests.java | 14 +- .../iot/modelsrepository/TestHelper.java | 8 +- .../resources/TestModelRepo/metadata.json | 10 - .../devicemanagement/deviceinformation-1.json | 64 ++++++ .../devicemanagement/deviceinformation-2.json | 16 ++ .../dtmi/com/example/base-1.json | 56 +++++ .../dtmi/com/example/base-2.json | 57 +++++ .../dtmi/com/example/building-1.json | 19 ++ .../dtmi/com/example/camera-3.json | 13 ++ .../dtmi/com/example/coldstorage-1.json | 13 ++ .../dtmi/com/example/conferenceroom-1.json | 13 ++ .../example/danglingexpanded-1.expanded.json | 215 ++++++++++++++++++ .../dtmi/com/example/freezer-1.json | 12 + .../incompleteexpanded-1.expanded.json | 151 ++++++++++++ .../dtmi/com/example/invalidmodel-1.json | 13 ++ .../dtmi/com/example/invalidmodel-2.json | 23 ++ .../dtmi/com/example/phone-2.json | 23 ++ .../dtmi/com/example/room-1.json | 12 + .../temperaturecontroller-1.expanded.json | 215 ++++++++++++++++++ .../com/example/temperaturecontroller-1.json | 60 +++++ .../dtmi/com/example/thermostat-1.json | 19 ++ .../dtmi/company/demodevice-1.json | 31 +++ .../dtmi/company/demodevice-2.json | 31 +++ .../dtmi/strict/badfilepath-1.json | 12 + .../dtmi/strict/emptyarray-1.json | 1 + .../dtmi/strict/namespaceconflict-1.json | 37 +++ .../dtmi/strict/nondtdl-1.json | 1 + .../dtmi/strict/unsupportedrootarray-1.json | 91 ++++++++ .../metadataModelsrepo}/metadata.json | 0 32 files changed, 1219 insertions(+), 24 deletions(-) delete mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadata.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/azure/devicemanagement/deviceinformation-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/azure/devicemanagement/deviceinformation-2.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/base-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/base-2.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/building-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/camera-3.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/coldstorage-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/conferenceroom-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/danglingexpanded-1.expanded.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/freezer-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/incompleteexpanded-1.expanded.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/invalidmodel-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/invalidmodel-2.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/phone-2.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/room-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/temperaturecontroller-1.expanded.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/temperaturecontroller-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/thermostat-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/company/demodevice-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/company/demodevice-2.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/badfilepath-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/emptyarray-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/namespaceconflict-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/nondtdl-1.json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/unsupportedrootarray-1.json rename sdk/modelsrepository/azure-iot-modelsrepository/src/{samples/resources/TestModelRepo => test/resources/TestModelRepo/metadataModelsrepo}/metadata.json (100%) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java index 556a4674f594e..10522b74b5bcf 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java @@ -41,8 +41,8 @@ public static boolean isValidDtmi(String dtmi) { if (dtmi == null || dtmi.isEmpty()) { return false; } - - return VALID_DTMI_PATTERN.matcher(dtmi).matches(); + return true; + // return VALID_DTMI_PATTERN.matcher(dtmi).matches(); } /** diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java index 2563c292bfcab..e7f9c8f889a51 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java @@ -99,12 +99,12 @@ public Mono fetchMetadataAsync(URI repositoryUri, Context c } catch (IOException e) { logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT + " Error: %s.", path.toString(), e.getMessage())); - return null; + return Mono.empty(); } } logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, path.toString())); - return null; + return Mono.empty(); } catch (MalformedURLException | URISyntaxException e) { return Mono.error(new AzureException(e)); } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java index 0ae6536450c4f..667c953a0d8f5 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java @@ -74,13 +74,10 @@ public Mono fetchMetadataAsync(URI repositoryUri, Context c .onErrorResume(error -> { logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT + " Error: %s", tryContentPath, error.getMessage())); - return null; + return Mono.empty(); }) .map(s -> { try { - if (s == null) { - return null; - } return new FetchMetadataResult().setPath(tryContentPath).setDefinition(s); } catch (JsonProcessingException e) { logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath)); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/ModelRepositoryIntegrationTests.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/ModelRepositoryIntegrationTests.java index 7d7ab8e98fb9b..714ea1ae3f2f2 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/ModelRepositoryIntegrationTests.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/ModelRepositoryIntegrationTests.java @@ -22,13 +22,19 @@ class ModelRepositoryIntegrationTests extends ModelsRepositoryTestBase { @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) @MethodSource("com.azure.iot.modelsrepository.TestHelper#getTestParameters") public void getModelsSingleDtmiNoDependencies(HttpClient httpClient, ModelsRepositoryServiceVersion serviceVersion, String repositoryUri) throws URISyntaxException { - final String dtmi = "dtmi:com:example:Thermostat;1"; - + String dtmi= ""; + if (repositoryUri == TestHelper.MODELS_REPOSITORY_NO_METADATA_ENDPOINT) { + dtmi = "Azure:iot;plugandplay;models:main:dtmi:com:example:abcThermostat;1"; + } else { + dtmi = "dtmi:com:example:Thermostat;1"; + } + + final String DTMI = dtmi; ModelsRepositoryAsyncClient client = getAsyncClient(httpClient, serviceVersion, repositoryUri); StepVerifier - .create(client.getModels(dtmi)) - .assertNext(model -> Assertions.assertTrue(model.keySet().size() == 1 && model.containsKey(dtmi))) + .create(client.getModels(DTMI)) + .assertNext(model -> Assertions.assertTrue(model.keySet().size() == 1 && model.containsKey(DTMI))) .verifyComplete(); } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/TestHelper.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/TestHelper.java index 736cf59272970..89729b8221d41 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/TestHelper.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/TestHelper.java @@ -22,7 +22,9 @@ class TestHelper { public static final String DISPLAY_NAME_WITH_ARGUMENTS = "{displayName} with [{arguments}]"; private static final String AZURE_IOT_MODELSREPOSITORY_TEST_SERVICE_VERSIONS = "AZURE_IOT_MODELSREPOSITORY_TEST_SERVICE_VERSIONS"; - private static final String LOCAL_TEST_REPOSITORY_PATH = (System.getProperty("user.dir") + "/src/test/resources/TestModelRepo/").replace("\\", "/"); + private static final String LOCAL_TEST_REPOSITORY_PATH_WITH_METADATA = (System.getProperty("user.dir") + "/src/test/resources/TestModelRepo/metadataModelsrepo/").replace("\\", "/"); + private static final String LOCAL_TEST_REPOSITORY_NO_METADATA_PATH = (System.getProperty("user.dir") + "/src/test/resources/TestModelRepo/").replace("\\", "/"); + public static final String MODELS_REPOSITORY_NO_METADATA_ENDPOINT = "https://raw.githubusercontent.com"; private static final String SERVICE_VERSION_FROM_ENV = Configuration.getGlobalConfiguration().get(AZURE_IOT_MODELSREPOSITORY_TEST_SERVICE_VERSIONS); @@ -51,7 +53,9 @@ static Stream getTestParameters() { static Stream getApplicableRepositoryUris() { ArrayList endpointList = new ArrayList<>(); endpointList.add(ModelsRepositoryConstants.DEFAULT_MODELS_REPOSITORY_ENDPOINT); - endpointList.add(LOCAL_TEST_REPOSITORY_PATH); + endpointList.add(LOCAL_TEST_REPOSITORY_PATH_WITH_METADATA); + endpointList.add(MODELS_REPOSITORY_NO_METADATA_ENDPOINT); + endpointList.add(LOCAL_TEST_REPOSITORY_NO_METADATA_PATH); return StreamSupport.stream(endpointList.spliterator(), false); } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadata.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadata.json deleted file mode 100644 index 93e3ed185af74..0000000000000 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadata.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "commitId": "f49444d5deefa369300c7653b5958f9907da550a", - "features": { - "expanded": true, - "index": true - }, - "publishDateUtc": "2021-09-16T23:01:01.885362+00:00", - "sourceRepo": "Azure/iot-plugandplay-models", - "totalModelCount": 19010 -} diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/azure/devicemanagement/deviceinformation-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/azure/devicemanagement/deviceinformation-1.json new file mode 100644 index 0000000000000..8a37e6d2c2c37 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/azure/devicemanagement/deviceinformation-1.json @@ -0,0 +1,64 @@ +{ + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:azure:DeviceManagement:DeviceInformation;1", + "@type": "Interface", + "displayName": "Device Information", + "contents": [ + { + "@type": "Property", + "name": "manufacturer", + "displayName": "Manufacturer", + "schema": "string", + "description": "Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso." + }, + { + "@type": "Property", + "name": "model", + "displayName": "Device model", + "schema": "string", + "description": "Device model name or ID. Ex. Surface Book 2." + }, + { + "@type": "Property", + "name": "swVersion", + "displayName": "Software version", + "schema": "string", + "description": "Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45" + }, + { + "@type": "Property", + "name": "osName", + "displayName": "Operating system name", + "schema": "string", + "description": "Name of the operating system on the device. Ex. Windows 10 IoT Core." + }, + { + "@type": "Property", + "name": "processorArchitecture", + "displayName": "Processor architecture", + "schema": "string", + "description": "Architecture of the processor on the device. Ex. x64 or ARM." + }, + { + "@type": "Property", + "name": "processorManufacturer", + "displayName": "Processor manufacturer", + "schema": "string", + "description": "Name of the manufacturer of the processor on the device. Ex. Intel." + }, + { + "@type": "Property", + "name": "totalStorage", + "displayName": "Total storage", + "schema": "double", + "description": "Total available storage on the device in kilobytes. Ex. 2048000 kilobytes." + }, + { + "@type": "Property", + "name": "totalMemory", + "displayName": "Total memory", + "schema": "double", + "description": "Total available memory on the device in kilobytes. Ex. 256000 kilobytes." + } + ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/azure/devicemanagement/deviceinformation-2.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/azure/devicemanagement/deviceinformation-2.json new file mode 100644 index 0000000000000..d35b8a3e3a1d5 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/azure/devicemanagement/deviceinformation-2.json @@ -0,0 +1,16 @@ +{ + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:azure:DeviceManagement:DeviceInformation;2", + "@type": "Interface", + "extends": "dtmi:azure:DeviceManagement:DeviceInformation;1", + "displayName": "Device Information", + "contents": [ + { + "@type": "Property", + "name": "osKernelVersion", + "displayName": "OS Kernel Version", + "schema": "string", + "description": "OS Kernel Version. Ex. Linux 4.15.0-54-generic x86_64." + } + ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/base-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/base-1.json new file mode 100644 index 0000000000000..85424e8a229e6 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/base-1.json @@ -0,0 +1,56 @@ +{ + "@id": "dtmi:com:example:base;1", + "@type": "Interface", + "contents": [ + { + "@type": "Property", + "name": "baseSerialNumber", + "schema": "string" + } + ], + "displayName": { + "en": "mybaseProp" + }, + "extends": [ + { + "@id": "dtmi:com:example:basic;1", + "@type": "Interface", + "contents": [ + { + "@type": "Property", + "name": "serialNumber", + "schema": "string", + "writable": false + }, + { + "@type": [ + "Telemetry", + "Temperature" + ], + "displayName": { + "en": "temperature" + }, + "name": "temperature", + "schema": "double", + "unit": "degreeCelsius" + }, + { + "@type": "Property", + "displayName": { + "en": "targetTemperature" + }, + "name": "targetTemperature", + "schema": "double", + "writable": true + } + ], + "displayName": { + "en": "Basic" + } + } + ], + "@context": [ + "dtmi:iotcentral:context;2", + "dtmi:dtdl:context;2" + ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/base-2.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/base-2.json new file mode 100644 index 0000000000000..29accafcc252e --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/base-2.json @@ -0,0 +1,57 @@ +{ + "@id": "dtmi:com:example:base;2", + "@type": "Interface", + "contents": [ + { + "@type": "Property", + "name": "baseSerialNumber", + "schema": "string" + } + ], + "displayName": { + "en": "mybaseProp" + }, + "extends": [ + { + "@id": "dtmi:com:example:basic;1", + "@type": "Interface", + "contents": [ + { + "@type": "Property", + "name": "serialNumber", + "schema": "string", + "writable": false + }, + { + "@type": [ + "Telemetry", + "Temperature" + ], + "displayName": { + "en": "temperature" + }, + "name": "temperature", + "schema": "double", + "unit": "degreeCelsius" + }, + { + "@type": "Property", + "displayName": { + "en": "targetTemperature" + }, + "name": "targetTemperature", + "schema": "double", + "writable": true + } + ], + "displayName": { + "en": "Basic" + } + }, + "dtmi:com:example:Freezer;1" + ], + "@context": [ + "dtmi:iotcentral:context;2", + "dtmi:dtdl:context;2" + ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/building-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/building-1.json new file mode 100644 index 0000000000000..c8b6bc6f73756 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/building-1.json @@ -0,0 +1,19 @@ +{ + "@id": "dtmi:com:example:Building;1", + "@type": "Interface", + "displayName": "Building", + "contents": [ + { + "@type": "Property", + "name": "name", + "schema": "string", + "writable": true + }, + { + "@type": "Relationship", + "name": "contains", + "target": "dtmi:com:example:Room;1" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/camera-3.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/camera-3.json new file mode 100644 index 0000000000000..f912746c0040d --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/camera-3.json @@ -0,0 +1,13 @@ +{ + "@id": "dtmi:com:example:Camera;3", + "@type": "Interface", + "displayName": "Phone", + "contents": [ + { + "@type": "Component", + "name": "deviceInfo", + "schema": "dtmi:azure:DeviceManagement:DeviceInformation;1" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/coldstorage-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/coldstorage-1.json new file mode 100644 index 0000000000000..a3b8466118a90 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/coldstorage-1.json @@ -0,0 +1,13 @@ +{ + "@id": "dtmi:com:example:ColdStorage;1", + "@type": "Interface", + "extends": ["dtmi:com:example:Room;1", "dtmi:com:example:Freezer;1"], + "contents": [ + { + "@type": "Property", + "name": "capacity", + "schema": "integer" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/conferenceroom-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/conferenceroom-1.json new file mode 100644 index 0000000000000..2e756ee73b6e9 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/conferenceroom-1.json @@ -0,0 +1,13 @@ +{ + "@id": "dtmi:com:example:ConferenceRoom;1", + "@type": "Interface", + "extends": "dtmi:com:example:Room;1", + "contents": [ + { + "@type": "Property", + "name": "capacity", + "schema": "integer" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/danglingexpanded-1.expanded.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/danglingexpanded-1.expanded.json new file mode 100644 index 0000000000000..93126c749ce9a --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/danglingexpanded-1.expanded.json @@ -0,0 +1,215 @@ +[ + { + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:com:example:DanglingExpanded;1", + "@type": "Interface", + "displayName": "Valid expanded model with no root model.", + "description": "Device with two thermostats and remote reboot.", + "contents": [ + { + "@type": [ + "Telemetry", + "DataSize" + ], + "name": "workingSet", + "displayName": "Working Set", + "description": "Current working set of the device memory in KiB.", + "schema": "double", + "unit": "kibibyte" + }, + { + "@type": "Property", + "name": "serialNumber", + "displayName": "Serial Number", + "description": "Serial number of the device.", + "schema": "string" + }, + { + "@type": "Command", + "name": "reboot", + "displayName": "Reboot", + "description": "Reboots the device after waiting the number of seconds specified.", + "request": { + "name": "delay", + "displayName": "Delay", + "description": "Number of seconds to wait before rebooting the device.", + "schema": "integer" + } + }, + { + "@type": "Component", + "schema": "dtmi:com:example:Thermostat;1", + "name": "thermostat1", + "displayName": "Thermostat One", + "description": "Thermostat One of Two." + }, + { + "@type": "Component", + "schema": "dtmi:com:example:Thermostat;1", + "name": "thermostat2", + "displayName": "Thermostat Two", + "description": "Thermostat Two of Two." + }, + { + "@type": "Component", + "schema": "dtmi:azure:DeviceManagement:DeviceInformation;1", + "name": "deviceInformation", + "displayName": "Device Information interface", + "description": "Optional interface with basic device hardware information." + } + ] + }, + { + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:com:example:Thermostat;1", + "@type": "Interface", + "displayName": "Thermostat", + "description": "Reports current temperature and provides desired temperature control.", + "contents": [ + { + "@type": [ + "Telemetry", + "Temperature" + ], + "name": "temperature", + "displayName": "Temperature", + "description": "Temperature in degrees Celsius.", + "schema": "double", + "unit": "degreeCelsius" + }, + { + "@type": [ + "Property", + "Temperature" + ], + "name": "targetTemperature", + "schema": "double", + "displayName": "Target Temperature", + "description": "Allows to remotely specify the desired target temperature.", + "unit": "degreeCelsius", + "writable": true + }, + { + "@type": [ + "Property", + "Temperature" + ], + "name": "maxTempSinceLastReboot", + "schema": "double", + "unit": "degreeCelsius", + "displayName": "Max temperature since last reboot.", + "description": "Returns the max temperature since last device reboot." + }, + { + "@type": "Command", + "name": "getMaxMinReport", + "displayName": "Get Max-Min report.", + "description": "This command returns the max, min and average temperature from the specified time to the current time.", + "request": { + "name": "since", + "displayName": "Since", + "description": "Period to return the max-min report.", + "schema": "dateTime" + }, + "response": { + "name": "tempReport", + "displayName": "Temperature Report", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "maxTemp", + "displayName": "Max temperature", + "schema": "double" + }, + { + "name": "minTemp", + "displayName": "Min temperature", + "schema": "double" + }, + { + "name": "avgTemp", + "displayName": "Average Temperature", + "schema": "double" + }, + { + "name": "startTime", + "displayName": "Start Time", + "schema": "dateTime" + }, + { + "name": "endTime", + "displayName": "End Time", + "schema": "dateTime" + } + ] + } + } + } + ] + }, + { + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:azure:DeviceManagement:DeviceInformation;1", + "@type": "Interface", + "displayName": "Device Information", + "contents": [ + { + "@type": "Property", + "name": "manufacturer", + "displayName": "Manufacturer", + "schema": "string", + "description": "Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso." + }, + { + "@type": "Property", + "name": "model", + "displayName": "Device model", + "schema": "string", + "description": "Device model name or ID. Ex. Surface Book 2." + }, + { + "@type": "Property", + "name": "swVersion", + "displayName": "Software version", + "schema": "string", + "description": "Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45" + }, + { + "@type": "Property", + "name": "osName", + "displayName": "Operating system name", + "schema": "string", + "description": "Name of the operating system on the device. Ex. Windows 10 IoT Core." + }, + { + "@type": "Property", + "name": "processorArchitecture", + "displayName": "Processor architecture", + "schema": "string", + "description": "Architecture of the processor on the device. Ex. x64 or ARM." + }, + { + "@type": "Property", + "name": "processorManufacturer", + "displayName": "Processor manufacturer", + "schema": "string", + "description": "Name of the manufacturer of the processor on the device. Ex. Intel." + }, + { + "@type": "Property", + "name": "totalStorage", + "displayName": "Total storage", + "schema": "double", + "description": "Total available storage on the device in kilobytes. Ex. 2048000 kilobytes." + }, + { + "@type": "Property", + "name": "totalMemory", + "displayName": "Total memory", + "schema": "double", + "description": "Total available memory on the device in kilobytes. Ex. 256000 kilobytes." + } + ] + } +] diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/freezer-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/freezer-1.json new file mode 100644 index 0000000000000..6006b66732991 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/freezer-1.json @@ -0,0 +1,12 @@ +{ + "@id": "dtmi:com:example:Freezer;1", + "@type": "Interface", + "contents": [ + { + "@type": "Component", + "name": "deviceInfo", + "schema": "dtmi:com:example:Thermostat;1" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/incompleteexpanded-1.expanded.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/incompleteexpanded-1.expanded.json new file mode 100644 index 0000000000000..1688ef4c0e3c5 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/incompleteexpanded-1.expanded.json @@ -0,0 +1,151 @@ +[ + { + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:com:example:IncompleteExpanded;1", + "@type": "Interface", + "displayName": "Incomplete expanded Temperature Controller", + "description": "Device with two thermostats and remote reboot.", + "contents": [ + { + "@type": [ + "Telemetry", + "DataSize" + ], + "name": "workingSet", + "displayName": "Working Set", + "description": "Current working set of the device memory in KiB.", + "schema": "double", + "unit": "kibibyte" + }, + { + "@type": "Property", + "name": "serialNumber", + "displayName": "Serial Number", + "description": "Serial number of the device.", + "schema": "string" + }, + { + "@type": "Command", + "name": "reboot", + "displayName": "Reboot", + "description": "Reboots the device after waiting the number of seconds specified.", + "request": { + "name": "delay", + "displayName": "Delay", + "description": "Number of seconds to wait before rebooting the device.", + "schema": "integer" + } + }, + { + "@type": "Component", + "schema": "dtmi:com:example:Thermostat;1", + "name": "thermostat1", + "displayName": "Thermostat One", + "description": "Thermostat One of Two." + }, + { + "@type": "Component", + "schema": "dtmi:com:example:Thermostat;1", + "name": "thermostat2", + "displayName": "Thermostat Two", + "description": "Thermostat Two of Two." + }, + { + "@type": "Component", + "schema": "dtmi:azure:DeviceManagement:DeviceInformation;1", + "name": "deviceInformation", + "displayName": "Device Information interface", + "description": "Optional interface with basic device hardware information." + } + ] + }, + { + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:com:example:Thermostat;1", + "@type": "Interface", + "displayName": "Thermostat", + "description": "Reports current temperature and provides desired temperature control.", + "contents": [ + { + "@type": [ + "Telemetry", + "Temperature" + ], + "name": "temperature", + "displayName": "Temperature", + "description": "Temperature in degrees Celsius.", + "schema": "double", + "unit": "degreeCelsius" + }, + { + "@type": [ + "Property", + "Temperature" + ], + "name": "targetTemperature", + "schema": "double", + "displayName": "Target Temperature", + "description": "Allows to remotely specify the desired target temperature.", + "unit": "degreeCelsius", + "writable": true + }, + { + "@type": [ + "Property", + "Temperature" + ], + "name": "maxTempSinceLastReboot", + "schema": "double", + "unit": "degreeCelsius", + "displayName": "Max temperature since last reboot.", + "description": "Returns the max temperature since last device reboot." + }, + { + "@type": "Command", + "name": "getMaxMinReport", + "displayName": "Get Max-Min report.", + "description": "This command returns the max, min and average temperature from the specified time to the current time.", + "request": { + "name": "since", + "displayName": "Since", + "description": "Period to return the max-min report.", + "schema": "dateTime" + }, + "response": { + "name": "tempReport", + "displayName": "Temperature Report", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "maxTemp", + "displayName": "Max temperature", + "schema": "double" + }, + { + "name": "minTemp", + "displayName": "Min temperature", + "schema": "double" + }, + { + "name": "avgTemp", + "displayName": "Average Temperature", + "schema": "double" + }, + { + "name": "startTime", + "displayName": "Start Time", + "schema": "dateTime" + }, + { + "name": "endTime", + "displayName": "End Time", + "schema": "dateTime" + } + ] + } + } + } + ] + } +] diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/invalidmodel-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/invalidmodel-1.json new file mode 100644 index 0000000000000..4f18d7b176584 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/invalidmodel-1.json @@ -0,0 +1,13 @@ +{ + "@id": "dtmi:com:example:invalidmodel;1", + "@type": "Interface", + "displayName": "Phone", + "contents": [ + { + "@type": "Component", + "name": "deviceInfo", + "schema": "dtmi:azure:fakeDeviceManagement:FakeDeviceInformation;2" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/invalidmodel-2.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/invalidmodel-2.json new file mode 100644 index 0000000000000..61443734cd900 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/invalidmodel-2.json @@ -0,0 +1,23 @@ +{ + "@id": "dtmi:com:example:Phone;2", + "@type": "Interfacez", + "displayName": "Phone", + "contentsz": [ + { + "@type": "Component", + "name": "frontCamera", + "schema": "dtmi:com:example:Camera;3" + }, + { + "@type": "Component", + "name": "backCamera", + "schema": "dtmi:com:example:Camera;3" + }, + { + "@type": "Component", + "name": "deviceInfo", + "schema": "dtmi:azure:deviceManagement:DeviceInformation;2" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/phone-2.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/phone-2.json new file mode 100644 index 0000000000000..26c7efbdedc01 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/phone-2.json @@ -0,0 +1,23 @@ +{ + "@id": "dtmi:com:example:Phone;2", + "@type": "Interface", + "displayName": "Phone", + "contents": [ + { + "@type": "Component", + "name": "frontCamera", + "schema": "dtmi:com:example:Camera;3" + }, + { + "@type": "Component", + "name": "backCamera", + "schema": "dtmi:com:example:Camera;3" + }, + { + "@type": "Component", + "name": "deviceInfo", + "schema": "dtmi:azure:DeviceManagement:DeviceInformation;2" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/room-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/room-1.json new file mode 100644 index 0000000000000..1a07edec4d984 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/room-1.json @@ -0,0 +1,12 @@ +{ + "@id": "dtmi:com:example:Room;1", + "@type": "Interface", + "contents": [ + { + "@type": "Property", + "name": "occupied", + "schema": "boolean" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/temperaturecontroller-1.expanded.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/temperaturecontroller-1.expanded.json new file mode 100644 index 0000000000000..14e8e294189e3 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/temperaturecontroller-1.expanded.json @@ -0,0 +1,215 @@ +[ + { + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:com:example:TemperatureController;1", + "@type": "Interface", + "displayName": "Temperature Controller", + "description": "Device with two thermostats and remote reboot.", + "contents": [ + { + "@type": [ + "Telemetry", + "DataSize" + ], + "name": "workingSet", + "displayName": "Working Set", + "description": "Current working set of the device memory in KiB.", + "schema": "double", + "unit": "kibibyte" + }, + { + "@type": "Property", + "name": "serialNumber", + "displayName": "Serial Number", + "description": "Serial number of the device.", + "schema": "string" + }, + { + "@type": "Command", + "name": "reboot", + "displayName": "Reboot", + "description": "Reboots the device after waiting the number of seconds specified.", + "request": { + "name": "delay", + "displayName": "Delay", + "description": "Number of seconds to wait before rebooting the device.", + "schema": "integer" + } + }, + { + "@type": "Component", + "schema": "dtmi:com:example:Thermostat;1", + "name": "thermostat1", + "displayName": "Thermostat One", + "description": "Thermostat One of Two." + }, + { + "@type": "Component", + "schema": "dtmi:com:example:Thermostat;1", + "name": "thermostat2", + "displayName": "Thermostat Two", + "description": "Thermostat Two of Two." + }, + { + "@type": "Component", + "schema": "dtmi:azure:DeviceManagement:DeviceInformation;1", + "name": "deviceInformation", + "displayName": "Device Information interface", + "description": "Optional interface with basic device hardware information." + } + ] + }, + { + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:com:example:Thermostat;1", + "@type": "Interface", + "displayName": "Thermostat", + "description": "Reports current temperature and provides desired temperature control.", + "contents": [ + { + "@type": [ + "Telemetry", + "Temperature" + ], + "name": "temperature", + "displayName": "Temperature", + "description": "Temperature in degrees Celsius.", + "schema": "double", + "unit": "degreeCelsius" + }, + { + "@type": [ + "Property", + "Temperature" + ], + "name": "targetTemperature", + "schema": "double", + "displayName": "Target Temperature", + "description": "Allows to remotely specify the desired target temperature.", + "unit": "degreeCelsius", + "writable": true + }, + { + "@type": [ + "Property", + "Temperature" + ], + "name": "maxTempSinceLastReboot", + "schema": "double", + "unit": "degreeCelsius", + "displayName": "Max temperature since last reboot.", + "description": "Returns the max temperature since last device reboot." + }, + { + "@type": "Command", + "name": "getMaxMinReport", + "displayName": "Get Max-Min report.", + "description": "This command returns the max, min and average temperature from the specified time to the current time.", + "request": { + "name": "since", + "displayName": "Since", + "description": "Period to return the max-min report.", + "schema": "dateTime" + }, + "response": { + "name": "tempReport", + "displayName": "Temperature Report", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "maxTemp", + "displayName": "Max temperature", + "schema": "double" + }, + { + "name": "minTemp", + "displayName": "Min temperature", + "schema": "double" + }, + { + "name": "avgTemp", + "displayName": "Average Temperature", + "schema": "double" + }, + { + "name": "startTime", + "displayName": "Start Time", + "schema": "dateTime" + }, + { + "name": "endTime", + "displayName": "End Time", + "schema": "dateTime" + } + ] + } + } + } + ] + }, + { + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:azure:DeviceManagement:DeviceInformation;1", + "@type": "Interface", + "displayName": "Device Information", + "contents": [ + { + "@type": "Property", + "name": "manufacturer", + "displayName": "Manufacturer", + "schema": "string", + "description": "Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso." + }, + { + "@type": "Property", + "name": "model", + "displayName": "Device model", + "schema": "string", + "description": "Device model name or ID. Ex. Surface Book 2." + }, + { + "@type": "Property", + "name": "swVersion", + "displayName": "Software version", + "schema": "string", + "description": "Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45" + }, + { + "@type": "Property", + "name": "osName", + "displayName": "Operating system name", + "schema": "string", + "description": "Name of the operating system on the device. Ex. Windows 10 IoT Core." + }, + { + "@type": "Property", + "name": "processorArchitecture", + "displayName": "Processor architecture", + "schema": "string", + "description": "Architecture of the processor on the device. Ex. x64 or ARM." + }, + { + "@type": "Property", + "name": "processorManufacturer", + "displayName": "Processor manufacturer", + "schema": "string", + "description": "Name of the manufacturer of the processor on the device. Ex. Intel." + }, + { + "@type": "Property", + "name": "totalStorage", + "displayName": "Total storage", + "schema": "double", + "description": "Total available storage on the device in kilobytes. Ex. 2048000 kilobytes." + }, + { + "@type": "Property", + "name": "totalMemory", + "displayName": "Total memory", + "schema": "double", + "description": "Total available memory on the device in kilobytes. Ex. 256000 kilobytes." + } + ] + } +] \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/temperaturecontroller-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/temperaturecontroller-1.json new file mode 100644 index 0000000000000..c455ddf8bae67 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/temperaturecontroller-1.json @@ -0,0 +1,60 @@ +{ + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:com:example:TemperatureController;1", + "@type": "Interface", + "displayName": "Temperature Controller", + "description": "Device with two thermostats and remote reboot.", + "contents": [ + { + "@type": [ + "Telemetry", + "DataSize" + ], + "name": "workingSet", + "displayName": "Working Set", + "description": "Current working set of the device memory in KiB.", + "schema": "double", + "unit": "kibibyte" + }, + { + "@type": "Property", + "name": "serialNumber", + "displayName": "Serial Number", + "description": "Serial number of the device.", + "schema": "string" + }, + { + "@type": "Command", + "name": "reboot", + "displayName": "Reboot", + "description": "Reboots the device after waiting the number of seconds specified.", + "request": { + "name": "delay", + "displayName": "Delay", + "description": "Number of seconds to wait before rebooting the device.", + "schema": "integer" + } + }, + { + "@type": "Component", + "schema": "dtmi:com:example:Thermostat;1", + "name": "thermostat1", + "displayName": "Thermostat One", + "description": "Thermostat One of Two." + }, + { + "@type": "Component", + "schema": "dtmi:com:example:Thermostat;1", + "name": "thermostat2", + "displayName": "Thermostat Two", + "description": "Thermostat Two of Two." + }, + { + "@type": "Component", + "schema": "dtmi:azure:DeviceManagement:DeviceInformation;1", + "name": "deviceInformation", + "displayName": "Device Information interface", + "description": "Optional interface with basic device hardware information." + } + ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/thermostat-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/thermostat-1.json new file mode 100644 index 0000000000000..315a307bbcb38 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/com/example/thermostat-1.json @@ -0,0 +1,19 @@ +{ + "@id": "dtmi:com:example:Thermostat;1", + "@type": "Interface", + "displayName": "Thermostat", + "contents": [ + { + "@type": "Telemetry", + "name": "temp", + "schema": "double" + }, + { + "@type": "Property", + "name": "setPointTemp", + "writable": true, + "schema": "double" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/company/demodevice-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/company/demodevice-1.json new file mode 100644 index 0000000000000..33c9554664a60 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/company/demodevice-1.json @@ -0,0 +1,31 @@ +{ + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:company:demodevice;1", + "@type": "Interface", + "displayName": "demodevice", + "contents": [ + { + "@type": "Component", + "name": "c1", + "schema": "dtmi:azure:deviceManagement:DeviceInformation;1" + }, + { + "@type": "Telemetry", + "name": "temperature", + "schema": "double" + }, + { + "@type": "Property", + "name": "deviceStatus", + "schema": "string" + }, + { + "@type": "Command", + "name": "reboot", + "request": { + "name": "delay", + "schema": "integer" + } + } + ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/company/demodevice-2.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/company/demodevice-2.json new file mode 100644 index 0000000000000..9d9b3bd2322aa --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/company/demodevice-2.json @@ -0,0 +1,31 @@ +{ + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:company:demodevice;1", + "@type": "Interface", + "displayName": "demodevice", + "contents": [ + { + "@type": "Component", + "name": "c1", + "schema": "dtmi:azure:DeviceManagement:DeviceInformation;1" + }, + { + "@type": "Telemetry", + "name": "temperature", + "schema": "double" + }, + { + "@type": "Property", + "name": "deviceStatus", + "schema": "string" + }, + { + "@type": "Command", + "name": "reboot", + "request": { + "name": "delay", + "schema": "integer" + } + } + ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/badfilepath-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/badfilepath-1.json new file mode 100644 index 0000000000000..6006b66732991 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/badfilepath-1.json @@ -0,0 +1,12 @@ +{ + "@id": "dtmi:com:example:Freezer;1", + "@type": "Interface", + "contents": [ + { + "@type": "Component", + "name": "deviceInfo", + "schema": "dtmi:com:example:Thermostat;1" + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/emptyarray-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/emptyarray-1.json new file mode 100644 index 0000000000000..0637a088a01e8 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/emptyarray-1.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/namespaceconflict-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/namespaceconflict-1.json new file mode 100644 index 0000000000000..6f2df812a67fa --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/namespaceconflict-1.json @@ -0,0 +1,37 @@ +{ + "@id": "dtmi:strict:namespaceconflict;1", + "@type": "Interface", + "contents": [ + { + "@type": "Telemetry", + "name": "accelerometer1", + "schema": "dtmi:com:example:acceleration;1" + }, + { + "@type": "Telemetry", + "name": "accelerometer2", + "schema": "dtmi:com:example:acceleration;1" + } + ], + "schemas": [ + { + "@id": "dtmi:com:example:acceleration;1", + "@type": "Object", + "fields": [ + { + "name": "x", + "schema": "double" + }, + { + "name": "y", + "schema": "double" + }, + { + "name": "z", + "schema": "double" + } + ] + } + ], + "@context": "dtmi:dtdl:context;2" +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/nondtdl-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/nondtdl-1.json new file mode 100644 index 0000000000000..b25ba2ac3af65 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/nondtdl-1.json @@ -0,0 +1 @@ +"content" \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/unsupportedrootarray-1.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/unsupportedrootarray-1.json new file mode 100644 index 0000000000000..1f282307a8c3c --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/dtmi/strict/unsupportedrootarray-1.json @@ -0,0 +1,91 @@ +[ + { + "@context": "dtmi:dtdl:context;2", + "@id": "dtmi:strict:unsupportedrootarray;1", + "@type": "Interface", + "displayName": "Thermostat", + "description": "Reports current temperature and provides desired temperature control.", + "contents": [ + { + "@type": [ + "Telemetry", + "Temperature" + ], + "name": "temperature", + "displayName": "Temperature", + "description": "Temperature in degrees Celsius.", + "schema": "double", + "unit": "degreeCelsius" + }, + { + "@type": [ + "Property", + "Temperature" + ], + "name": "targetTemperature", + "schema": "double", + "displayName": "Target Temperature", + "description": "Allows to remotely specify the desired target temperature.", + "unit": "degreeCelsius", + "writable": true + }, + { + "@type": [ + "Property", + "Temperature" + ], + "name": "maxTempSinceLastReboot", + "schema": "double", + "unit": "degreeCelsius", + "displayName": "Max temperature since last reboot.", + "description": "Returns the max temperature since last device reboot." + }, + { + "@type": "Command", + "name": "getMaxMinReport", + "displayName": "Get Max-Min report.", + "description": "This command returns the max, min and average temperature from the specified time to the current time.", + "request": { + "name": "since", + "displayName": "Since", + "description": "Period to return the max-min report.", + "schema": "dateTime" + }, + "response": { + "name": "tempReport", + "displayName": "Temperature Report", + "schema": { + "@type": "Object", + "fields": [ + { + "name": "maxTemp", + "displayName": "Max temperature", + "schema": "double" + }, + { + "name": "minTemp", + "displayName": "Min temperature", + "schema": "double" + }, + { + "name": "avgTemp", + "displayName": "Average Temperature", + "schema": "double" + }, + { + "name": "startTime", + "displayName": "Start Time", + "schema": "dateTime" + }, + { + "name": "endTime", + "displayName": "End Time", + "schema": "dateTime" + } + ] + } + } + } + ] + } +] \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/samples/resources/TestModelRepo/metadata.json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/metadata.json similarity index 100% rename from sdk/modelsrepository/azure-iot-modelsrepository/src/samples/resources/TestModelRepo/metadata.json rename to sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/TestModelRepo/metadataModelsrepo/metadata.json From 217ccf36e95ac8f097cb9776c7b8f7aaf02ce461 Mon Sep 17 00:00:00 2001 From: Azad Abbasi Date: Mon, 4 Oct 2021 17:28:50 -0700 Subject: [PATCH 10/16] Fix recursive function issue. --- .../azure/iot/modelsrepository/DtmiConventions.java | 4 ++-- .../implementation/RepositoryHandler.java | 13 ++++++++----- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java index 10522b74b5bcf..25a613db8b749 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java @@ -41,8 +41,8 @@ public static boolean isValidDtmi(String dtmi) { if (dtmi == null || dtmi.isEmpty()) { return false; } - return true; - // return VALID_DTMI_PATTERN.matcher(dtmi).matches(); + //return true; + return VALID_DTMI_PATTERN.matcher(dtmi).matches(); } /** diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index 43aaa69295357..d0f04a8aba2cb 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -69,7 +69,7 @@ private Flux processAsync( return Flux.empty(); } - String targetDtmi = remainingWork.poll(); + //String targetDtmi = remainingWork.poll(); Mono tryFromExpanded = Mono.just(false); // If ModelDependencyResolution.Enabled is requested the client will first attempt to fetch @@ -93,15 +93,18 @@ private Flux processAsync( } } - logger.info(String.format(StatusStrings.PROCESSING_DTMIS, targetDtmi)); + logger.info(String.format(StatusStrings.PROCESSING_DTMIS, remainingWork.peek())); return tryFromExpanded - .flatMap(tryExpanded -> modelFetcher.fetchModelAsync(targetDtmi, repositoryUri, tryExpanded, context)) + .flatMap(tryExpanded -> modelFetcher.fetchModelAsync(remainingWork.peek(), repositoryUri, tryExpanded, context)) .map(result -> new IntermediateFetchModelResult(result, currentResults)) - .expand(customType -> { + .expandDeep(customType -> { + if (remainingWork.isEmpty()) { + return Flux.empty(); + } Map results = customType.getMap(); FetchModelResult response = customType.getFetchModelResult(); - + String targetDtmi = remainingWork.poll(); if (response.isFromExpanded()) { try { Map expanded = new ModelsQuery(response.getDefinition()).listToMap(); From 5f57d2b624b3801bfcacf25a96865d80d71040a7 Mon Sep 17 00:00:00 2001 From: Azad Abbasi Date: Tue, 5 Oct 2021 18:41:41 -0700 Subject: [PATCH 11/16] Fix test issues. --- .../iot/modelsrepository/DtmiConventions.java | 11 ++++ .../implementation/FileModelFetcher.java | 47 +++++++------- .../implementation/HttpModelFetcher.java | 44 +++++++------ .../implementation/RepositoryHandler.java | 62 ++++++++++--------- .../ModelRepositoryIntegrationTests.java | 14 ++--- .../iot/modelsrepository/TestHelper.java | 2 +- 6 files changed, 93 insertions(+), 87 deletions(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java index 25a613db8b749..02ad3095603da 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java @@ -74,6 +74,17 @@ public static URI getModelUri(String dtmi, URI repositoryUri, boolean expanded) } } + public static String getModelPath(String dtmi, boolean expanded) { + String dtmiPath = dtmiToPath(dtmi); + + if (expanded) { + dtmiPath = dtmiPath.replace(ModelsRepositoryConstants.JSON_EXTENSION, + ModelsRepositoryConstants.JSON_EXPANDED_EXTENSION); + } + + return dtmiPath; + } + /** * Generates the model repository's metadata URI. * diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java index e7f9c8f889a51..b74873dd85099 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java @@ -82,33 +82,30 @@ public Mono fetchModelAsync(String dtmi, URI repositoryUri, bo @Override public Mono fetchMetadataAsync(URI repositoryUri, Context context) { - return Mono.defer(() -> { - - try { - String tryContentPath = getMetadataPath(repositoryUri); - Path path = Paths.get(new File(tryContentPath).getPath()); - - logger.info(StatusStrings.FETCHING_METADATA_CONTENT, path); - - if (Files.exists(path)) { - try { - return Mono.just( - new FetchMetadataResult() - .setDefinition(new String(Files.readAllBytes(path), StandardCharsets.UTF_8)) - .setPath(tryContentPath)); - } catch (IOException e) { - logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT + " Error: %s.", - path.toString(), e.getMessage())); - return Mono.empty(); - } + try { + String tryContentPath = getMetadataPath(repositoryUri); + Path path = Paths.get(new File(tryContentPath).getPath()); + + logger.info(StatusStrings.FETCHING_METADATA_CONTENT, path); + + if (Files.exists(path)) { + try { + return Mono.just( + new FetchMetadataResult() + .setDefinition(new String(Files.readAllBytes(path), StandardCharsets.UTF_8)) + .setPath(tryContentPath)); + } catch (IOException e) { + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT + " Error: %s.", + path.toString(), e.getMessage())); + return Mono.empty(); } - - logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, path.toString())); - return Mono.empty(); - } catch (MalformedURLException | URISyntaxException e) { - return Mono.error(new AzureException(e)); } - }); + + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, path.toString())); + return Mono.just(new FetchMetadataResult()); + } catch (MalformedURLException | URISyntaxException e) { + return Mono.error(new AzureException(e)); + } } private String getModelPath(String dtmi, URI repositoryUri, boolean expanded) throws URISyntaxException, MalformedURLException { diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java index 667c953a0d8f5..f5773f3cef9c9 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/HttpModelFetcher.java @@ -64,30 +64,28 @@ public Mono fetchModelAsync(String dtmi, URI repositoryUri, bo @Override public Mono fetchMetadataAsync(URI repositoryUri, Context context) { - return Mono.defer(() -> { - try { - String tryContentPath = getMetadataPath(repositoryUri); + try { + String tryContentPath = getMetadataPath(repositoryUri); - logger.info(StatusStrings.FETCHING_METADATA_CONTENT, tryContentPath); + logger.info(StatusStrings.FETCHING_METADATA_CONTENT, tryContentPath); - return evaluatePath(tryContentPath, context) - .onErrorResume(error -> { - logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT + " Error: %s", - tryContentPath, error.getMessage())); - return Mono.empty(); - }) - .map(s -> { - try { - return new FetchMetadataResult().setPath(tryContentPath).setDefinition(s); - } catch (JsonProcessingException e) { - logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath)); - return null; - } - }); - } catch (MalformedURLException | URISyntaxException e) { - return Mono.error(new AzureException(e)); - } - }); + return evaluatePath(tryContentPath, context) + .onErrorResume(error -> { + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT + " Error: %s", + tryContentPath, error.getMessage())); + return Mono.error(error); + }) + .map(s -> { + try { + return new FetchMetadataResult().setPath(tryContentPath).setDefinition(s); + } catch (JsonProcessingException e) { + logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT, tryContentPath)); + return null; + } + }); + } catch (MalformedURLException | URISyntaxException e) { + return Mono.error(new AzureException(e)); + } } private Mono evaluatePath(String tryContentPath, Context context) { @@ -101,7 +99,7 @@ private Mono evaluatePath(String tryContentPath, Context context) { } private String getModelPath(String dtmi, URI repositoryUri, boolean expanded) throws URISyntaxException { - return DtmiConventions.getModelUri(dtmi, repositoryUri, expanded).getPath(); + return DtmiConventions.getModelPath(dtmi, expanded); } private String getMetadataPath(URI repositoryUri) throws URISyntaxException, MalformedURLException { diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index d0f04a8aba2cb..df6af51d548be 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -36,8 +36,8 @@ public RepositoryHandler(URI repositoryUri, ModelsRepositoryAPIImpl protocolLaye if (this.repositoryUri.getScheme() != null && this.repositoryUri.getScheme() - .toLowerCase(Locale.getDefault()) - .startsWith(ModelsRepositoryConstants.HTTP)) { + .toLowerCase(Locale.getDefault()) + .startsWith(ModelsRepositoryConstants.HTTP)) { this.modelFetcher = new HttpModelFetcher(protocolLayer); } else { this.modelFetcher = new FileModelFetcher(); @@ -69,42 +69,23 @@ private Flux processAsync( return Flux.empty(); } - //String targetDtmi = remainingWork.poll(); - Mono tryFromExpanded = Mono.just(false); - - // If ModelDependencyResolution.Enabled is requested the client will first attempt to fetch - // metadata.json content from the target repository. The metadata object includes supported features - // of the repository. - // If the metadata indicates expanded models are available. The client will try to fetch pre-computed model - // dependencies using .expanded.json. - // If the model expanded form does not exist fall back to computing model dependencies just-in-time. - if (resolutionOption == ModelDependencyResolution.ENABLED) { - Mono repositoryMetadata = modelFetcher.fetchMetadataAsync(repositoryUri, context); - - if (repositoryMetadata != null) { - tryFromExpanded = repositoryMetadata - .map(repo -> ( - repo != null && repo.getDefinition() != null - && repo.getDefinition().getFeatures() != null - && repo.getDefinition().getFeatures().isExpanded() - ) - ) - .defaultIfEmpty(false); - } - } - logger.info(String.format(StatusStrings.PROCESSING_DTMIS, remainingWork.peek())); - return tryFromExpanded - .flatMap(tryExpanded -> modelFetcher.fetchModelAsync(remainingWork.peek(), repositoryUri, tryExpanded, context)) + return isFromExpanded(resolutionOption, context) + .flatMap(tryExpanded -> { + logger.info("Try from expanded is " + tryExpanded); + return modelFetcher.fetchModelAsync(remainingWork.peek(), repositoryUri, tryExpanded, context); + }) .map(result -> new IntermediateFetchModelResult(result, currentResults)) .expandDeep(customType -> { if (remainingWork.isEmpty()) { return Flux.empty(); } + Map results = customType.getMap(); FetchModelResult response = customType.getFetchModelResult(); String targetDtmi = remainingWork.poll(); + if (response.isFromExpanded()) { try { Map expanded = new ModelsQuery(response.getDefinition()).listToMap(); @@ -162,4 +143,29 @@ private Queue prepareWork(Iterable dtmis) { return modelsToProcess; } + + private Mono isFromExpanded(ModelDependencyResolution resolutionOption, Context context) { + // If ModelDependencyResolution.Enabled is requested the client will first attempt to fetch + // metadata.json content from the target repository. The metadata object includes supported features + // of the repository. + // If the metadata indicates expanded models are available. The client will try to fetch pre-computed model + // dependencies using .expanded.json. + // If the model expanded form does not exist fall back to computing model dependencies just-in-time. + if (resolutionOption == ModelDependencyResolution.ENABLED) { + return modelFetcher.fetchMetadataAsync(repositoryUri, context) + .onErrorResume(error -> Mono.just(new FetchMetadataResult())) + .flatMap(result -> { + Boolean tryFromExpanded = false; + if (result != null) { + logger.error("got me some results: " + result); + tryFromExpanded = result != null && result.getDefinition() != null + && result.getDefinition().getFeatures() != null + && result.getDefinition().getFeatures().isExpanded(); + } + return Mono.just(tryFromExpanded); + }); + } + + return Mono.just(false); + } } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/ModelRepositoryIntegrationTests.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/ModelRepositoryIntegrationTests.java index 714ea1ae3f2f2..613b3c8d32cf4 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/ModelRepositoryIntegrationTests.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/ModelRepositoryIntegrationTests.java @@ -22,19 +22,13 @@ class ModelRepositoryIntegrationTests extends ModelsRepositoryTestBase { @ParameterizedTest(name = DISPLAY_NAME_WITH_ARGUMENTS) @MethodSource("com.azure.iot.modelsrepository.TestHelper#getTestParameters") public void getModelsSingleDtmiNoDependencies(HttpClient httpClient, ModelsRepositoryServiceVersion serviceVersion, String repositoryUri) throws URISyntaxException { - String dtmi= ""; - if (repositoryUri == TestHelper.MODELS_REPOSITORY_NO_METADATA_ENDPOINT) { - dtmi = "Azure:iot;plugandplay;models:main:dtmi:com:example:abcThermostat;1"; - } else { - dtmi = "dtmi:com:example:Thermostat;1"; - } - - final String DTMI = dtmi; + String dtmi = "dtmi:com:example:Thermostat;1"; + ModelsRepositoryAsyncClient client = getAsyncClient(httpClient, serviceVersion, repositoryUri); StepVerifier - .create(client.getModels(DTMI)) - .assertNext(model -> Assertions.assertTrue(model.keySet().size() == 1 && model.containsKey(DTMI))) + .create(client.getModels(dtmi)) + .assertNext(model -> Assertions.assertTrue(model.keySet().size() == 1 && model.containsKey(dtmi))) .verifyComplete(); } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/TestHelper.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/TestHelper.java index 89729b8221d41..03bd3dcf97251 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/TestHelper.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/java/com/azure/iot/modelsrepository/TestHelper.java @@ -24,7 +24,7 @@ class TestHelper { private static final String AZURE_IOT_MODELSREPOSITORY_TEST_SERVICE_VERSIONS = "AZURE_IOT_MODELSREPOSITORY_TEST_SERVICE_VERSIONS"; private static final String LOCAL_TEST_REPOSITORY_PATH_WITH_METADATA = (System.getProperty("user.dir") + "/src/test/resources/TestModelRepo/metadataModelsrepo/").replace("\\", "/"); private static final String LOCAL_TEST_REPOSITORY_NO_METADATA_PATH = (System.getProperty("user.dir") + "/src/test/resources/TestModelRepo/").replace("\\", "/"); - public static final String MODELS_REPOSITORY_NO_METADATA_ENDPOINT = "https://raw.githubusercontent.com"; + public static final String MODELS_REPOSITORY_NO_METADATA_ENDPOINT = "https://raw.githubusercontent.com/Azure/iot-plugandplay-models/main"; private static final String SERVICE_VERSION_FROM_ENV = Configuration.getGlobalConfiguration().get(AZURE_IOT_MODELSREPOSITORY_TEST_SERVICE_VERSIONS); From 13f1be784c3b7d1d8af7d4d40e712c8d688dc5c5 Mon Sep 17 00:00:00 2001 From: Azad Abbasi Date: Wed, 6 Oct 2021 13:22:04 -0700 Subject: [PATCH 12/16] Update recorded tests --- ...nTests.getModelsEnsureNoDuplicates[1].json | 72 ++++---- ...nTests.getModelsEnsureNoDuplicates[3].json | 136 ++++++++++++++ ...nTests.getModelsEnsureNoDuplicates[4].json | 4 + ...ts.getModelsSingleDtmiDoesNotExist[1].json | 45 ++--- ...ts.getModelsSingleDtmiDoesNotExist[3].json | 68 +++++++ ...ts.getModelsSingleDtmiDoesNotExist[4].json | 4 + ....getModelsSingleDtmiNoDependencies[1].json | 36 ++-- ....getModelsSingleDtmiNoDependencies[3].json | 70 ++++++++ ....getModelsSingleDtmiNoDependencies[4].json | 4 + ...etModelsSingleDtmiWithDependencies[1].json | 36 ++-- ...etModelsSingleDtmiWithDependencies[3].json | 166 ++++++++++++++++++ ...etModelsSingleDtmiWithDependencies[4].json | 4 + ...ithDepsDisableDependencyResolution[1].json | 14 +- ...ithDepsDisableDependencyResolution[3].json | 40 +++++ ...ithDepsDisableDependencyResolution[4].json | 4 + 15 files changed, 602 insertions(+), 101 deletions(-) create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[3].json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[4].json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[3].json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[4].json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[3].json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[4].json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[3].json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[4].json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[3].json create mode 100644 sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[4].json diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[1].json index e60c632ad73fd..91b113ce183c8 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[1].json @@ -3,8 +3,8 @@ "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "7dc7fe26-0ed1-4b3e-a715-eca833f8e803" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "25af01c9-d572-4418-9294-027f46a32981" }, "Response" : { "X-Cache" : "HIT", @@ -12,49 +12,49 @@ "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E179)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "Last-Modified" : "Wed, 06 Oct 2021 18:28:07 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", - "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Content-MD5" : "x6Px49JuRM9EVDNUDRj0qA==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Cache-Control" : "max-age=600", - "Etag" : "\"0x8D983861F20E768\"", - "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", - "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", - "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", - "Age" : "88", + "Etag" : "\"0x8D988F70ADF0EEF\"", + "x-ms-error-code" : "ConditionNotMet", + "Expires" : "Wed, 06 Oct 2021 20:30:37 GMT", + "x-ms-request-id" : "4da670eb-801e-003a-50ef-bab78f000000", + "Body" : "{\n \"commitId\": \"16b04c45d99deb5438de3c5247a966e7596eaa44\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-10-06T18:01:30.072670+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19032\n}", + "Age" : "15", "Content-Type" : "application/json" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fazure%2Fdevicemanagement%2Fdeviceinformation-1.expanded.json", + "Uri" : "https://REDACTED.azure.com/dtmi%2Fazure%2Fdevicemanagement%2Fdeviceinformation-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "ca6f1a0e-34f7-48a0-84b3-e645316a5712" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "c3dde8f2-c996-49a3-87f5-1c9272c9d4c8" }, "Response" : { "X-Cache" : "HIT", "content-length" : "2218", "x-ms-version" : "2018-03-28", - "Server" : "ECAcc (sed/E10D)", + "Server" : "ECAcc (sed/E16F)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", "Last-Modified" : "Wed, 14 Apr 2021 00:08:03 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", "Content-MD5" : "Vw1WdSQoTBOhmiB9XXUwsw==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Etag" : "\"0x8D8FED95F570217\"", - "x-ms-error-code" : "ConditionNotMet", - "x-ms-request-id" : "cd64bea0-001e-001e-6b16-b48ab4000000", + "x-ms-request-id" : "8f0a7681-b01e-0021-1b52-ba22ba000000", "Body" : "[\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Device Information\",\n \"contents\": [\n {\n \"@type\": \"Property\",\n \"name\": \"manufacturer\",\n \"displayName\": \"Manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"model\",\n \"displayName\": \"Device model\",\n \"schema\": \"string\",\n \"description\": \"Device model name or ID. Ex. Surface Book 2.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"swVersion\",\n \"displayName\": \"Software version\",\n \"schema\": \"string\",\n \"description\": \"Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"osName\",\n \"displayName\": \"Operating system name\",\n \"schema\": \"string\",\n \"description\": \"Name of the operating system on the device. Ex. Windows 10 IoT Core.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorArchitecture\",\n \"displayName\": \"Processor architecture\",\n \"schema\": \"string\",\n \"description\": \"Architecture of the processor on the device. Ex. x64 or ARM.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorManufacturer\",\n \"displayName\": \"Processor manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Name of the manufacturer of the processor on the device. Ex. Intel.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalStorage\",\n \"displayName\": \"Total storage\",\n \"schema\": \"double\",\n \"description\": \"Total available storage on the device in kilobytes. Ex. 2048000 kilobytes.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalMemory\",\n \"displayName\": \"Total memory\",\n \"schema\": \"double\",\n \"description\": \"Total available memory on the device in kilobytes. Ex. 256000 kilobytes.\"\n }\n ]\n }\n]", - "Age" : "153814", + "Age" : "67480", "Content-Type" : "application/json" }, "Exception" : null @@ -62,8 +62,8 @@ "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "322d8b05-cd1e-4fd2-af64-0e214771a82e" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "99d53076-3314-4c8c-ac26-f5255a3ce57b" }, "Response" : { "X-Cache" : "HIT", @@ -71,49 +71,49 @@ "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E179)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "Last-Modified" : "Wed, 06 Oct 2021 18:28:07 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", - "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Content-MD5" : "x6Px49JuRM9EVDNUDRj0qA==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Cache-Control" : "max-age=600", - "Etag" : "\"0x8D983861F20E768\"", - "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", - "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", - "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", - "Age" : "88", + "Etag" : "\"0x8D988F70ADF0EEF\"", + "x-ms-error-code" : "ConditionNotMet", + "Expires" : "Wed, 06 Oct 2021 20:30:37 GMT", + "x-ms-request-id" : "4da670eb-801e-003a-50ef-bab78f000000", + "Body" : "{\n \"commitId\": \"16b04c45d99deb5438de3c5247a966e7596eaa44\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-10-06T18:01:30.072670+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19032\n}", + "Age" : "15", "Content-Type" : "application/json" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fazure%2Fdevicemanagement%2Fdeviceinformation-1.expanded.json", + "Uri" : "https://REDACTED.azure.com/dtmi%2Fazure%2Fdevicemanagement%2Fdeviceinformation-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "01b6e25e-dee4-4932-8b41-763658708fee" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "5863f9ee-2fb7-446c-aee2-03167295300f" }, "Response" : { "X-Cache" : "HIT", "content-length" : "2218", "x-ms-version" : "2018-03-28", - "Server" : "ECAcc (sed/E10D)", + "Server" : "ECAcc (sed/E16F)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", "Last-Modified" : "Wed, 14 Apr 2021 00:08:03 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", "Content-MD5" : "Vw1WdSQoTBOhmiB9XXUwsw==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Etag" : "\"0x8D8FED95F570217\"", - "x-ms-error-code" : "ConditionNotMet", - "x-ms-request-id" : "cd64bea0-001e-001e-6b16-b48ab4000000", + "x-ms-request-id" : "8f0a7681-b01e-0021-1b52-ba22ba000000", "Body" : "[\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Device Information\",\n \"contents\": [\n {\n \"@type\": \"Property\",\n \"name\": \"manufacturer\",\n \"displayName\": \"Manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"model\",\n \"displayName\": \"Device model\",\n \"schema\": \"string\",\n \"description\": \"Device model name or ID. Ex. Surface Book 2.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"swVersion\",\n \"displayName\": \"Software version\",\n \"schema\": \"string\",\n \"description\": \"Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"osName\",\n \"displayName\": \"Operating system name\",\n \"schema\": \"string\",\n \"description\": \"Name of the operating system on the device. Ex. Windows 10 IoT Core.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorArchitecture\",\n \"displayName\": \"Processor architecture\",\n \"schema\": \"string\",\n \"description\": \"Architecture of the processor on the device. Ex. x64 or ARM.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorManufacturer\",\n \"displayName\": \"Processor manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Name of the manufacturer of the processor on the device. Ex. Intel.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalStorage\",\n \"displayName\": \"Total storage\",\n \"schema\": \"double\",\n \"description\": \"Total available storage on the device in kilobytes. Ex. 2048000 kilobytes.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalMemory\",\n \"displayName\": \"Total memory\",\n \"schema\": \"double\",\n \"description\": \"Total available memory on the device in kilobytes. Ex. 256000 kilobytes.\"\n }\n ]\n }\n]", - "Age" : "153814", + "Age" : "67480", "Content-Type" : "application/json" }, "Exception" : null diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[3].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[3].json new file mode 100644 index 0000000000000..1988688b1b698 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[3].json @@ -0,0 +1,136 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/%2FAzure%2Fiot-plugandplay-models%2Fmain%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "373d3fb2-3224-4231-82b9-88317026322b" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "117", + "Access-Control-Allow-Origin" : "*", + "Connection" : "keep-alive", + "retry-after" : "0", + "StatusCode" : "301", + "Source-Age" : "3152", + "Date" : "Wed, 06 Oct 2021 20:20:38 GMT", + "Via" : "1.1 varnish", + "X-Timer" : "S1633551639.640685,VS0,VE1", + "Accept-Ranges" : "bytes", + "X-Served-By" : "cache-sea4467-SEA", + "Vary" : "Authorization,Accept-Encoding", + "Expires" : "Wed, 06 Oct 2021 20:25:38 GMT", + "X-Cache-Hits" : "1", + "Body" : "Moved Permanently.\n\n", + "X-Fastly-Request-ID" : "d4b04e5c26caad09bfafe6fc4a34fbb2f9bbd722", + "Content-Type" : "text/html; charset=utf-8", + "Location" : "/Azure/iot-plugandplay-models/main/Azure/iot-plugandplay-models/main/metadata.json", + "X-GitHub-Request-Id" : "3658:1B57:376C8:48218:615DF8C6" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/dtmi%2Fazure%2Fdevicemanagement%2Fdeviceinformation-1.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "fd2bb724-ce53-4876-82d5-dfa44781e212" + }, + "Response" : { + "content-length" : "2212", + "Access-Control-Allow-Origin" : "*", + "retry-after" : "0", + "StatusCode" : "200", + "Source-Age" : "16", + "X-Timer" : "S1633551639.657189,VS0,VE1", + "X-Frame-Options" : "deny", + "Strict-Transport-Security" : "max-age=31536000", + "X-Served-By" : "cache-sea4481-SEA", + "Content-Security-Policy" : "default-src 'none'; style-src 'unsafe-inline'; sandbox", + "X-XSS-Protection" : "1; mode=block", + "Body" : "{\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Device Information\",\n \"contents\": [\n {\n \"@type\": \"Property\",\n \"name\": \"manufacturer\",\n \"displayName\": \"Manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"model\",\n \"displayName\": \"Device model\",\n \"schema\": \"string\",\n \"description\": \"Device model name or ID. Ex. Surface Book 2.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"swVersion\",\n \"displayName\": \"Software version\",\n \"schema\": \"string\",\n \"description\": \"Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"osName\",\n \"displayName\": \"Operating system name\",\n \"schema\": \"string\",\n \"description\": \"Name of the operating system on the device. Ex. Windows 10 IoT Core.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorArchitecture\",\n \"displayName\": \"Processor architecture\",\n \"schema\": \"string\",\n \"description\": \"Architecture of the processor on the device. Ex. x64 or ARM.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorManufacturer\",\n \"displayName\": \"Processor manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Name of the manufacturer of the processor on the device. Ex. Intel.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalStorage\",\n \"displayName\": \"Total storage\",\n \"schema\": \"double\",\n \"description\": \"Total available storage on the device in kilobytes. Ex. 2048000 kilobytes.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalMemory\",\n \"displayName\": \"Total memory\",\n \"schema\": \"double\",\n \"description\": \"Total available memory on the device in kilobytes. Ex. 256000 kilobytes.\"\n }\n ]\n }", + "Content-Type" : "text/plain; charset=utf-8", + "X-GitHub-Request-Id" : "956E:278C:249C9:34469:615DF8C6", + "X-Cache" : "HIT", + "X-Content-Type-Options" : "nosniff", + "Connection" : "keep-alive", + "Date" : "Wed, 06 Oct 2021 20:20:38 GMT", + "Via" : "1.1 varnish", + "Accept-Ranges" : "bytes", + "Cache-Control" : "max-age=300", + "ETag" : "\"7952e5f1274fe59fa4aa27c6ba55a1aebec0d5b2ac12f5c8124bbfb08eae4eee\"", + "Vary" : "Authorization,Accept-Encoding,Origin", + "Expires" : "Wed, 06 Oct 2021 20:25:38 GMT", + "X-Cache-Hits" : "1", + "X-Fastly-Request-ID" : "5df4bd0e445a001660fc9bbc87a07e197269cd3b" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/%2FAzure%2Fiot-plugandplay-models%2Fmain%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "7d8e24f6-1a2f-497e-a2b4-8476009e83b0" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "117", + "Access-Control-Allow-Origin" : "*", + "Connection" : "keep-alive", + "retry-after" : "0", + "StatusCode" : "301", + "Source-Age" : "3152", + "Date" : "Wed, 06 Oct 2021 20:20:38 GMT", + "Via" : "1.1 varnish", + "X-Timer" : "S1633551639.680088,VS0,VE0", + "Accept-Ranges" : "bytes", + "X-Served-By" : "cache-sea4476-SEA", + "Vary" : "Authorization,Accept-Encoding", + "Expires" : "Wed, 06 Oct 2021 20:25:38 GMT", + "X-Cache-Hits" : "3", + "Body" : "Moved Permanently.\n\n", + "X-Fastly-Request-ID" : "6e6bca3cad481da68ff97ac490b38c49e575b967", + "Content-Type" : "text/html; charset=utf-8", + "Location" : "/Azure/iot-plugandplay-models/main/Azure/iot-plugandplay-models/main/metadata.json", + "X-GitHub-Request-Id" : "3658:1B57:376C8:48218:615DF8C6" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/dtmi%2Fazure%2Fdevicemanagement%2Fdeviceinformation-1.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "0d61b93e-98bd-4a7a-9091-d05701c8a0f8" + }, + "Response" : { + "content-length" : "2212", + "Access-Control-Allow-Origin" : "*", + "retry-after" : "0", + "StatusCode" : "200", + "Source-Age" : "16", + "X-Timer" : "S1633551639.692640,VS0,VE1", + "X-Frame-Options" : "deny", + "Strict-Transport-Security" : "max-age=31536000", + "X-Served-By" : "cache-sea4479-SEA", + "Content-Security-Policy" : "default-src 'none'; style-src 'unsafe-inline'; sandbox", + "X-XSS-Protection" : "1; mode=block", + "Body" : "{\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Device Information\",\n \"contents\": [\n {\n \"@type\": \"Property\",\n \"name\": \"manufacturer\",\n \"displayName\": \"Manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"model\",\n \"displayName\": \"Device model\",\n \"schema\": \"string\",\n \"description\": \"Device model name or ID. Ex. Surface Book 2.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"swVersion\",\n \"displayName\": \"Software version\",\n \"schema\": \"string\",\n \"description\": \"Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"osName\",\n \"displayName\": \"Operating system name\",\n \"schema\": \"string\",\n \"description\": \"Name of the operating system on the device. Ex. Windows 10 IoT Core.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorArchitecture\",\n \"displayName\": \"Processor architecture\",\n \"schema\": \"string\",\n \"description\": \"Architecture of the processor on the device. Ex. x64 or ARM.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorManufacturer\",\n \"displayName\": \"Processor manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Name of the manufacturer of the processor on the device. Ex. Intel.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalStorage\",\n \"displayName\": \"Total storage\",\n \"schema\": \"double\",\n \"description\": \"Total available storage on the device in kilobytes. Ex. 2048000 kilobytes.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalMemory\",\n \"displayName\": \"Total memory\",\n \"schema\": \"double\",\n \"description\": \"Total available memory on the device in kilobytes. Ex. 256000 kilobytes.\"\n }\n ]\n }", + "Content-Type" : "text/plain; charset=utf-8", + "X-GitHub-Request-Id" : "956E:278C:249C9:34469:615DF8C6", + "X-Cache" : "HIT", + "X-Content-Type-Options" : "nosniff", + "Connection" : "keep-alive", + "Date" : "Wed, 06 Oct 2021 20:20:38 GMT", + "Via" : "1.1 varnish", + "Accept-Ranges" : "bytes", + "Cache-Control" : "max-age=300", + "ETag" : "\"7952e5f1274fe59fa4aa27c6ba55a1aebec0d5b2ac12f5c8124bbfb08eae4eee\"", + "Vary" : "Authorization,Accept-Encoding,Origin", + "Expires" : "Wed, 06 Oct 2021 20:25:38 GMT", + "X-Cache-Hits" : "1", + "X-Fastly-Request-ID" : "fab5c72ec9b38e981c9a9405ccd9db4ef5f0b69e" + }, + "Exception" : null + } ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[4].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[4].json new file mode 100644 index 0000000000000..ba5f37f8f8555 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsEnsureNoDuplicates[4].json @@ -0,0 +1,4 @@ +{ + "networkCallRecords" : [ ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[1].json index 90166cf65e312..df0d661c890b7 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[1].json @@ -3,8 +3,8 @@ "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "c9391aad-48fb-4676-adad-18d30bbcd39f" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "ef345dbe-e307-4889-a2f4-5578b581d5f4" }, "Response" : { "X-Cache" : "HIT", @@ -12,29 +12,30 @@ "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E179)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "Last-Modified" : "Wed, 06 Oct 2021 18:28:07 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", - "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Content-MD5" : "x6Px49JuRM9EVDNUDRj0qA==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Cache-Control" : "max-age=600", - "Etag" : "\"0x8D983861F20E768\"", - "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", - "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", - "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", - "Age" : "88", + "Etag" : "\"0x8D988F70ADF0EEF\"", + "x-ms-error-code" : "ConditionNotMet", + "Expires" : "Wed, 06 Oct 2021 20:30:37 GMT", + "x-ms-request-id" : "4da670eb-801e-003a-50ef-bab78f000000", + "Body" : "{\n \"commitId\": \"16b04c45d99deb5438de3c5247a966e7596eaa44\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-10-06T18:01:30.072670+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19032\n}", + "Age" : "15", "Content-Type" : "application/json" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Fthermostatddd-1.expanded.json", + "Uri" : "https://REDACTED.azure.com/dtmi%2Fcom%2Fexample%2Fthermostatddd-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "a5a24337-efd8-482e-89cc-630bcfc4358f" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "0d9db165-514f-4943-bc54-253613fa1327" }, "Response" : { "content-length" : "321", @@ -44,21 +45,21 @@ "retry-after" : "0", "StatusCode" : "404", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:06 GMT", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", "Access-Control-Expose-Headers" : "*", "Vary" : "Origin", "x-ms-error-code" : "WebContentNotFound", - "x-ms-request-id" : "2ef2ac7f-401e-00a2-257c-b508e9000000", - "Body" : "WebContentNotFound

The requested content does not exist.

  • HttpStatusCode: 404
  • ErrorCode: WebContentNotFound
  • RequestId : 2ef2ac7f-401e-00a2-257c-b508e9000000
  • TimeStamp : 2021-09-29T21:52:07.4957322Z

", + "x-ms-request-id" : "c9d3efa3-e01e-00b8-2fef-bab6de000000", + "Body" : "WebContentNotFound

The requested content does not exist.

  • HttpStatusCode: 404
  • ErrorCode: WebContentNotFound
  • RequestId : c9d3efa3-e01e-00b8-2fef-bab6de000000
  • TimeStamp : 2021-10-06T20:20:38.0079901Z

", "Content-Type" : "text/html" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Fthermostatddd-1.json", + "Uri" : "https://REDACTED.azure.com/dtmi%2Fcom%2Fexample%2Fthermostatddd-1.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "f12aca18-2bae-41e6-bb41-e72487de135e" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "6a9fbf15-79fe-4873-9013-d457ed632988" }, "Response" : { "content-length" : "321", @@ -68,12 +69,12 @@ "retry-after" : "0", "StatusCode" : "404", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:06 GMT", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", "Access-Control-Expose-Headers" : "*", "Vary" : "Origin", "x-ms-error-code" : "WebContentNotFound", - "x-ms-request-id" : "5250b7e1-501e-006b-317c-b5ffbe000000", - "Body" : "WebContentNotFound

The requested content does not exist.

  • HttpStatusCode: 404
  • ErrorCode: WebContentNotFound
  • RequestId : 5250b7e1-501e-006b-317c-b5ffbe000000
  • TimeStamp : 2021-09-29T21:52:07.5558209Z

", + "x-ms-request-id" : "93e6433d-b01e-000d-42ef-ba4790000000", + "Body" : "WebContentNotFound

The requested content does not exist.

  • HttpStatusCode: 404
  • ErrorCode: WebContentNotFound
  • RequestId : 93e6433d-b01e-000d-42ef-ba4790000000
  • TimeStamp : 2021-10-06T20:20:38.0458965Z

", "Content-Type" : "text/html" }, "Exception" : null diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[3].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[3].json new file mode 100644 index 0000000000000..4971f92c95294 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[3].json @@ -0,0 +1,68 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/%2FAzure%2Fiot-plugandplay-models%2Fmain%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "c1df76ad-7678-4dfb-8ff5-37d956634207" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "117", + "Access-Control-Allow-Origin" : "*", + "Connection" : "keep-alive", + "retry-after" : "0", + "StatusCode" : "301", + "Source-Age" : "3151", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "X-Timer" : "S1633551638.736753,VS0,VE1", + "Accept-Ranges" : "bytes", + "X-Served-By" : "cache-sea4481-SEA", + "Vary" : "Authorization,Accept-Encoding", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-Cache-Hits" : "1", + "Body" : "Moved Permanently.\n\n", + "X-Fastly-Request-ID" : "8e1f2b87ec661ad60631285a5fe0d96514e365d2", + "Content-Type" : "text/html; charset=utf-8", + "Location" : "/Azure/iot-plugandplay-models/main/Azure/iot-plugandplay-models/main/metadata.json", + "X-GitHub-Request-Id" : "3658:1B57:376C8:48218:615DF8C6" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/dtmi%2Fcom%2Fexample%2Fthermostatddd-1.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "fdd06ab2-74ce-4ffd-a880-919642f59d4d" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "14", + "Access-Control-Allow-Origin" : "*", + "X-Content-Type-Options" : "nosniff", + "Connection" : "keep-alive", + "retry-after" : "0", + "StatusCode" : "404", + "Source-Age" : "15", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "X-Timer" : "S1633551638.793259,VS0,VE1", + "X-Frame-Options" : "deny", + "Accept-Ranges" : "bytes", + "Strict-Transport-Security" : "max-age=31536000", + "X-Served-By" : "cache-sea4481-SEA", + "Content-Security-Policy" : "default-src 'none'; style-src 'unsafe-inline'; sandbox", + "Vary" : "Authorization,Accept-Encoding,Origin", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-XSS-Protection" : "1; mode=block", + "X-Cache-Hits" : "1", + "Body" : "404: Not Found", + "X-Fastly-Request-ID" : "4b3fa9f84ad37624375c7db2b6d442ad910de934", + "Content-Type" : "text/plain; charset=utf-8", + "X-GitHub-Request-Id" : "7C18:1911:33727:48D74:615E0506" + }, + "Exception" : null + } ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[4].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[4].json new file mode 100644 index 0000000000000..ba5f37f8f8555 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiDoesNotExist[4].json @@ -0,0 +1,4 @@ +{ + "networkCallRecords" : [ ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[1].json index f01fab5e51c8a..1dcb383a60c15 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[1].json @@ -3,8 +3,8 @@ "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "95e5e01c-6785-4402-bd80-d06d174a5dee" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "00415d68-70ee-473f-b39d-ee1f248ed207" }, "Response" : { "X-Cache" : "HIT", @@ -12,49 +12,49 @@ "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E179)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "Last-Modified" : "Wed, 06 Oct 2021 18:28:07 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", - "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Content-MD5" : "x6Px49JuRM9EVDNUDRj0qA==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Cache-Control" : "max-age=600", - "Etag" : "\"0x8D983861F20E768\"", - "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", - "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", - "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", - "Age" : "88", + "Etag" : "\"0x8D988F70ADF0EEF\"", + "x-ms-error-code" : "ConditionNotMet", + "Expires" : "Wed, 06 Oct 2021 20:30:37 GMT", + "x-ms-request-id" : "4da670eb-801e-003a-50ef-bab78f000000", + "Body" : "{\n \"commitId\": \"16b04c45d99deb5438de3c5247a966e7596eaa44\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-10-06T18:01:30.072670+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19032\n}", + "Age" : "15", "Content-Type" : "application/json" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Fthermostat-1.expanded.json", + "Uri" : "https://REDACTED.azure.com/dtmi%2Fcom%2Fexample%2Fthermostat-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "0ff85bcd-037a-44dd-9cbc-6d975ef85407" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "60edc1e3-fa3e-4f82-a6e6-36844278b264" }, "Response" : { "X-Cache" : "HIT", "content-length" : "2651", "x-ms-version" : "2018-03-28", - "Server" : "ECAcc (sed/E120)", + "Server" : "ECAcc (sed/E132)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", "Last-Modified" : "Wed, 14 Apr 2021 00:07:35 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", "Content-MD5" : "pH51cS5+u5tWh2Krmys7qA==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Etag" : "\"0x8D8FED94ECA13B6\"", - "x-ms-error-code" : "ConditionNotMet", - "x-ms-request-id" : "e422263d-601e-005c-3c16-b40fa1000000", + "x-ms-request-id" : "2e9bccae-e01e-0000-5a52-ba988b000000", "Body" : "[\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:Thermostat;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Thermostat\",\n \"description\": \"Reports current temperature and provides desired temperature control.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"Temperature\"\n ],\n \"name\": \"temperature\",\n \"displayName\": \"Temperature\",\n \"description\": \"Temperature in degrees Celsius.\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\"\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"targetTemperature\",\n \"schema\": \"double\",\n \"displayName\": \"Target Temperature\",\n \"description\": \"Allows to remotely specify the desired target temperature.\",\n \"unit\": \"degreeCelsius\",\n \"writable\": true\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"maxTempSinceLastReboot\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\",\n \"displayName\": \"Max temperature since last reboot.\",\n \"description\": \"Returns the max temperature since last device reboot.\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"getMaxMinReport\",\n \"displayName\": \"Get Max-Min report.\",\n \"description\": \"This command returns the max, min and average temperature from the specified time to the current time.\",\n \"request\": {\n \"name\": \"since\",\n \"displayName\": \"Since\",\n \"description\": \"Period to return the max-min report.\",\n \"schema\": \"dateTime\"\n },\n \"response\": {\n \"name\": \"tempReport\",\n \"displayName\": \"Temperature Report\",\n \"schema\": {\n \"@type\": \"Object\",\n \"fields\": [\n {\n \"name\": \"maxTemp\",\n \"displayName\": \"Max temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"minTemp\",\n \"displayName\": \"Min temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"avgTemp\",\n \"displayName\": \"Average Temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"startTime\",\n \"displayName\": \"Start Time\",\n \"schema\": \"dateTime\"\n },\n {\n \"name\": \"endTime\",\n \"displayName\": \"End Time\",\n \"schema\": \"dateTime\"\n }\n ]\n }\n }\n }\n ]\n }\n]", - "Age" : "153814", + "Age" : "67407", "Content-Type" : "application/json" }, "Exception" : null diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[3].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[3].json new file mode 100644 index 0000000000000..3855d02c7d648 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[3].json @@ -0,0 +1,70 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/%2FAzure%2Fiot-plugandplay-models%2Fmain%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "4cf03b8b-a770-42bc-a551-fc3158b12654" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "117", + "Access-Control-Allow-Origin" : "*", + "Connection" : "keep-alive", + "retry-after" : "0", + "StatusCode" : "301", + "Source-Age" : "3151", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "X-Timer" : "S1633551638.737897,VS0,VE1", + "Accept-Ranges" : "bytes", + "X-Served-By" : "cache-sea4476-SEA", + "Vary" : "Authorization,Accept-Encoding", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-Cache-Hits" : "1", + "Body" : "Moved Permanently.\n\n", + "X-Fastly-Request-ID" : "2d22f0a88716101930a7091385594781d8e367b3", + "Content-Type" : "text/html; charset=utf-8", + "Location" : "/Azure/iot-plugandplay-models/main/Azure/iot-plugandplay-models/main/metadata.json", + "X-GitHub-Request-Id" : "3658:1B57:376C8:48218:615DF8C6" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/dtmi%2Fcom%2Fexample%2Fthermostat-1.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "10ec23fa-79b5-4622-9fd0-552844bc945f" + }, + "Response" : { + "content-length" : "2469", + "Access-Control-Allow-Origin" : "*", + "retry-after" : "0", + "StatusCode" : "200", + "Source-Age" : "15", + "X-Timer" : "S1633551638.814445,VS0,VE1", + "X-Frame-Options" : "deny", + "Strict-Transport-Security" : "max-age=31536000", + "X-Served-By" : "cache-sea4479-SEA", + "Content-Security-Policy" : "default-src 'none'; style-src 'unsafe-inline'; sandbox", + "X-XSS-Protection" : "1; mode=block", + "Body" : "{\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:Thermostat;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Thermostat\",\n \"description\": \"Reports current temperature and provides desired temperature control.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"Temperature\"\n ],\n \"name\": \"temperature\",\n \"displayName\": \"Temperature\",\n \"description\": \"Temperature in degrees Celsius.\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\"\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"targetTemperature\",\n \"schema\": \"double\",\n \"displayName\": \"Target Temperature\",\n \"description\": \"Allows to remotely specify the desired target temperature.\",\n \"unit\": \"degreeCelsius\",\n \"writable\": true\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"maxTempSinceLastReboot\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\",\n \"displayName\": \"Max temperature since last reboot.\",\n \"description\": \"Returns the max temperature since last device reboot.\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"getMaxMinReport\",\n \"displayName\": \"Get Max-Min report.\",\n \"description\": \"This command returns the max, min and average temperature from the specified time to the current time.\",\n \"request\": {\n \"name\": \"since\",\n \"displayName\": \"Since\",\n \"description\": \"Period to return the max-min report.\",\n \"schema\": \"dateTime\"\n },\n \"response\": {\n \"name\": \"tempReport\",\n \"displayName\": \"Temperature Report\",\n \"schema\": {\n \"@type\": \"Object\",\n \"fields\": [\n {\n \"name\": \"maxTemp\",\n \"displayName\": \"Max temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"minTemp\",\n \"displayName\": \"Min temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"avgTemp\",\n \"displayName\": \"Average Temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"startTime\",\n \"displayName\": \"Start Time\",\n \"schema\": \"dateTime\"\n },\n {\n \"name\": \"endTime\",\n \"displayName\": \"End Time\",\n \"schema\": \"dateTime\"\n }\n ]\n }\n }\n }\n ]\n}", + "Content-Type" : "text/plain; charset=utf-8", + "X-GitHub-Request-Id" : "7A10:320C:3A12D:4AC16:615DF8C6", + "X-Cache" : "HIT", + "X-Content-Type-Options" : "nosniff", + "Connection" : "keep-alive", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "Accept-Ranges" : "bytes", + "Cache-Control" : "max-age=300", + "ETag" : "\"0d2c122754b690ebb4106d28683b3bc7be1dced98582291e46df6433d31e464d\"", + "Vary" : "Authorization,Accept-Encoding,Origin", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-Cache-Hits" : "1", + "X-Fastly-Request-ID" : "2c5f259ced15caef70ac53d71618fdfe8db3a8b3" + }, + "Exception" : null + } ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[4].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[4].json new file mode 100644 index 0000000000000..ba5f37f8f8555 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiNoDependencies[4].json @@ -0,0 +1,4 @@ +{ + "networkCallRecords" : [ ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[1].json index ea57f4b8fdca8..1b6744067777d 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[1].json @@ -3,8 +3,8 @@ "Method" : "GET", "Uri" : "https://REDACTED.azure.com/%2Fmetadata.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "84d9acca-021e-4282-95c0-eb64b823ae32" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "572a992d-15f7-4a0c-920c-0775171cff1b" }, "Response" : { "X-Cache" : "HIT", @@ -12,49 +12,49 @@ "x-ms-version" : "2018-03-28", "Server" : "ECAcc (sed/E179)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", - "Last-Modified" : "Wed, 29 Sep 2021 20:17:12 GMT", + "Last-Modified" : "Wed, 06 Oct 2021 18:28:07 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", - "Content-MD5" : "qaVYpz9oxThaeAEdfv7cMg==", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Content-MD5" : "x6Px49JuRM9EVDNUDRj0qA==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Cache-Control" : "max-age=600", - "Etag" : "\"0x8D983861F20E768\"", - "Expires" : "Wed, 29 Sep 2021 22:02:07 GMT", - "x-ms-request-id" : "e18a4033-501e-003f-387c-b53085000000", - "Body" : "{\n \"commitId\": \"3651c9d3e80167f9226baacb145d196a1c0ba446\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-09-29T20:00:57.332025+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19018\n}", - "Age" : "88", + "Etag" : "\"0x8D988F70ADF0EEF\"", + "x-ms-error-code" : "ConditionNotMet", + "Expires" : "Wed, 06 Oct 2021 20:30:37 GMT", + "x-ms-request-id" : "4da670eb-801e-003a-50ef-bab78f000000", + "Body" : "{\n \"commitId\": \"16b04c45d99deb5438de3c5247a966e7596eaa44\",\n \"features\": {\n \"expanded\": true,\n \"index\": true\n },\n \"publishDateUtc\": \"2021-10-06T18:01:30.072670+00:00\",\n \"sourceRepo\": \"Azure/iot-plugandplay-models\",\n \"totalModelCount\": 19032\n}", + "Age" : "15", "Content-Type" : "application/json" }, "Exception" : null }, { "Method" : "GET", - "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Ftemperaturecontroller-1.expanded.json", + "Uri" : "https://REDACTED.azure.com/dtmi%2Fcom%2Fexample%2Ftemperaturecontroller-1.expanded.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "f2fa1841-6f6e-499d-807b-6015ab5d271b" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "761203d7-f656-4862-a5d5-160ef466ea91" }, "Response" : { "X-Cache" : "HIT", "content-length" : "6751", "x-ms-version" : "2018-03-28", - "Server" : "ECAcc (sed/E17F)", + "Server" : "ECAcc (sed/E17B)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", "Last-Modified" : "Wed, 14 Apr 2021 00:07:35 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", "Content-MD5" : "BnZpV2+7Z2t0sxAxOhmBdw==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Etag" : "\"0x8D8FED94EBE03D1\"", - "x-ms-error-code" : "ConditionNotMet", - "x-ms-request-id" : "461deecb-f01e-004d-0e16-b49481000000", + "x-ms-request-id" : "08c2b7cc-301e-0015-4552-baafa3000000", "Body" : "[\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:TemperatureController;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Temperature Controller\",\n \"description\": \"Device with two thermostats and remote reboot.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"DataSize\"\n ],\n \"name\": \"workingSet\",\n \"displayName\": \"Working Set\",\n \"description\": \"Current working set of the device memory in KiB.\",\n \"schema\": \"double\",\n \"unit\": \"kibibyte\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"serialNumber\",\n \"displayName\": \"Serial Number\",\n \"description\": \"Serial number of the device.\",\n \"schema\": \"string\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"reboot\",\n \"displayName\": \"Reboot\",\n \"description\": \"Reboots the device after waiting the number of seconds specified.\",\n \"request\": {\n \"name\": \"delay\",\n \"displayName\": \"Delay\",\n \"description\": \"Number of seconds to wait before rebooting the device.\",\n \"schema\": \"integer\"\n }\n },\n {\n \"@type\": \"Component\",\n \"schema\": \"dtmi:com:example:Thermostat;1\",\n \"name\": \"thermostat1\",\n \"displayName\": \"Thermostat One\",\n \"description\": \"Thermostat One of Two.\"\n },\n {\n \"@type\": \"Component\",\n \"schema\": \"dtmi:com:example:Thermostat;1\",\n \"name\": \"thermostat2\",\n \"displayName\": \"Thermostat Two\",\n \"description\": \"Thermostat Two of Two.\"\n },\n {\n \"@type\": \"Component\",\n \"schema\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"name\": \"deviceInformation\",\n \"displayName\": \"Device Information interface\",\n \"description\": \"Optional interface with basic device hardware information.\"\n }\n ]\n },\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:Thermostat;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Thermostat\",\n \"description\": \"Reports current temperature and provides desired temperature control.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"Temperature\"\n ],\n \"name\": \"temperature\",\n \"displayName\": \"Temperature\",\n \"description\": \"Temperature in degrees Celsius.\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\"\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"targetTemperature\",\n \"schema\": \"double\",\n \"displayName\": \"Target Temperature\",\n \"description\": \"Allows to remotely specify the desired target temperature.\",\n \"unit\": \"degreeCelsius\",\n \"writable\": true\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"maxTempSinceLastReboot\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\",\n \"displayName\": \"Max temperature since last reboot.\",\n \"description\": \"Returns the max temperature since last device reboot.\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"getMaxMinReport\",\n \"displayName\": \"Get Max-Min report.\",\n \"description\": \"This command returns the max, min and average temperature from the specified time to the current time.\",\n \"request\": {\n \"name\": \"since\",\n \"displayName\": \"Since\",\n \"description\": \"Period to return the max-min report.\",\n \"schema\": \"dateTime\"\n },\n \"response\": {\n \"name\": \"tempReport\",\n \"displayName\": \"Temperature Report\",\n \"schema\": {\n \"@type\": \"Object\",\n \"fields\": [\n {\n \"name\": \"maxTemp\",\n \"displayName\": \"Max temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"minTemp\",\n \"displayName\": \"Min temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"avgTemp\",\n \"displayName\": \"Average Temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"startTime\",\n \"displayName\": \"Start Time\",\n \"schema\": \"dateTime\"\n },\n {\n \"name\": \"endTime\",\n \"displayName\": \"End Time\",\n \"schema\": \"dateTime\"\n }\n ]\n }\n }\n }\n ]\n },\n {\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Device Information\",\n \"contents\": [\n {\n \"@type\": \"Property\",\n \"name\": \"manufacturer\",\n \"displayName\": \"Manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"model\",\n \"displayName\": \"Device model\",\n \"schema\": \"string\",\n \"description\": \"Device model name or ID. Ex. Surface Book 2.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"swVersion\",\n \"displayName\": \"Software version\",\n \"schema\": \"string\",\n \"description\": \"Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"osName\",\n \"displayName\": \"Operating system name\",\n \"schema\": \"string\",\n \"description\": \"Name of the operating system on the device. Ex. Windows 10 IoT Core.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorArchitecture\",\n \"displayName\": \"Processor architecture\",\n \"schema\": \"string\",\n \"description\": \"Architecture of the processor on the device. Ex. x64 or ARM.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorManufacturer\",\n \"displayName\": \"Processor manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Name of the manufacturer of the processor on the device. Ex. Intel.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalStorage\",\n \"displayName\": \"Total storage\",\n \"schema\": \"double\",\n \"description\": \"Total available storage on the device in kilobytes. Ex. 2048000 kilobytes.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalMemory\",\n \"displayName\": \"Total memory\",\n \"schema\": \"double\",\n \"description\": \"Total available memory on the device in kilobytes. Ex. 256000 kilobytes.\"\n }\n ]\n }\n]", - "Age" : "153815", + "Age" : "67407", "Content-Type" : "application/json" }, "Exception" : null diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[3].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[3].json new file mode 100644 index 0000000000000..08020e83e1d2d --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[3].json @@ -0,0 +1,166 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/%2FAzure%2Fiot-plugandplay-models%2Fmain%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "944945f9-28df-45ce-95d9-b9a4e0bb757a" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "117", + "Access-Control-Allow-Origin" : "*", + "Connection" : "keep-alive", + "retry-after" : "0", + "StatusCode" : "301", + "Source-Age" : "3151", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "X-Timer" : "S1633551638.738065,VS0,VE1", + "Accept-Ranges" : "bytes", + "X-Served-By" : "cache-sea4425-SEA", + "Vary" : "Authorization,Accept-Encoding", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-Cache-Hits" : "1", + "Body" : "Moved Permanently.\n\n", + "X-Fastly-Request-ID" : "753a5ba57fcb35261a05e41c5c3c56376b90d51a", + "Content-Type" : "text/html; charset=utf-8", + "Location" : "/Azure/iot-plugandplay-models/main/Azure/iot-plugandplay-models/main/metadata.json", + "X-GitHub-Request-Id" : "3658:1B57:376C8:48218:615DF8C6" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/dtmi%2Fcom%2Fexample%2Ftemperaturecontroller-1.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "afd14528-37d5-43f5-b17e-bb71455ec7a1" + }, + "Response" : { + "content-length" : "1762", + "Access-Control-Allow-Origin" : "*", + "retry-after" : "0", + "StatusCode" : "200", + "Source-Age" : "15", + "X-Timer" : "S1633551638.790204,VS0,VE1", + "X-Frame-Options" : "deny", + "Strict-Transport-Security" : "max-age=31536000", + "X-Served-By" : "cache-sea4430-SEA", + "Content-Security-Policy" : "default-src 'none'; style-src 'unsafe-inline'; sandbox", + "X-XSS-Protection" : "1; mode=block", + "Body" : "{\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:TemperatureController;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Temperature Controller\",\n \"description\": \"Device with two thermostats and remote reboot.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"DataSize\"\n ],\n \"name\": \"workingSet\",\n \"displayName\": \"Working Set\",\n \"description\": \"Current working set of the device memory in KiB.\",\n \"schema\": \"double\",\n \"unit\": \"kibibyte\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"serialNumber\",\n \"displayName\": \"Serial Number\",\n \"description\": \"Serial number of the device.\",\n \"schema\": \"string\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"reboot\",\n \"displayName\": \"Reboot\",\n \"description\": \"Reboots the device after waiting the number of seconds specified.\",\n \"request\": {\n \"name\": \"delay\",\n \"displayName\": \"Delay\",\n \"description\": \"Number of seconds to wait before rebooting the device.\",\n \"schema\": \"integer\"\n }\n },\n {\n \"@type\": \"Component\",\n \"schema\": \"dtmi:com:example:Thermostat;1\",\n \"name\": \"thermostat1\",\n \"displayName\": \"Thermostat One\",\n \"description\": \"Thermostat One of Two.\"\n },\n {\n \"@type\": \"Component\",\n \"schema\": \"dtmi:com:example:Thermostat;1\",\n \"name\": \"thermostat2\",\n \"displayName\": \"Thermostat Two\",\n \"description\": \"Thermostat Two of Two.\"\n },\n {\n \"@type\": \"Component\",\n \"schema\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"name\": \"deviceInformation\",\n \"displayName\": \"Device Information interface\",\n \"description\": \"Optional interface with basic device hardware information.\"\n }\n ]\n}", + "Content-Type" : "text/plain; charset=utf-8", + "X-GitHub-Request-Id" : "3088:6400:89E1:16994:615DF8C6", + "X-Cache" : "HIT", + "X-Content-Type-Options" : "nosniff", + "Connection" : "keep-alive", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "Accept-Ranges" : "bytes", + "Cache-Control" : "max-age=300", + "ETag" : "\"276d790fcfc6c0c7637965a33d2bf9cea2a8583f385ee2d1c5d16823814b3094\"", + "Vary" : "Authorization,Accept-Encoding,Origin", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-Cache-Hits" : "1", + "X-Fastly-Request-ID" : "fbebc8be9c92c71f316deaf54b7377c57ffa3158" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/%2FAzure%2Fiot-plugandplay-models%2Fmain%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "63cb65f7-5200-4e35-9a7e-427d41c863dd" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "117", + "Access-Control-Allow-Origin" : "*", + "Connection" : "keep-alive", + "retry-after" : "0", + "StatusCode" : "301", + "Source-Age" : "3151", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "X-Timer" : "S1633551638.806824,VS0,VE0", + "Accept-Ranges" : "bytes", + "X-Served-By" : "cache-sea4476-SEA", + "Vary" : "Authorization,Accept-Encoding", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-Cache-Hits" : "2", + "Body" : "Moved Permanently.\n\n", + "X-Fastly-Request-ID" : "5493b55c016061f5c2732324e8a654246408f1e3", + "Content-Type" : "text/html; charset=utf-8", + "Location" : "/Azure/iot-plugandplay-models/main/Azure/iot-plugandplay-models/main/metadata.json", + "X-GitHub-Request-Id" : "3658:1B57:376C8:48218:615DF8C6" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/dtmi%2Fcom%2Fexample%2Fthermostat-1.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "572b80d5-cff5-49c6-bfb7-7432b1155f1c" + }, + "Response" : { + "content-length" : "2469", + "Access-Control-Allow-Origin" : "*", + "retry-after" : "0", + "StatusCode" : "200", + "Source-Age" : "15", + "X-Timer" : "S1633551638.827640,VS0,VE1", + "X-Frame-Options" : "deny", + "Strict-Transport-Security" : "max-age=31536000", + "X-Served-By" : "cache-sea4425-SEA", + "Content-Security-Policy" : "default-src 'none'; style-src 'unsafe-inline'; sandbox", + "X-XSS-Protection" : "1; mode=block", + "Body" : "{\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:Thermostat;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Thermostat\",\n \"description\": \"Reports current temperature and provides desired temperature control.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"Temperature\"\n ],\n \"name\": \"temperature\",\n \"displayName\": \"Temperature\",\n \"description\": \"Temperature in degrees Celsius.\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\"\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"targetTemperature\",\n \"schema\": \"double\",\n \"displayName\": \"Target Temperature\",\n \"description\": \"Allows to remotely specify the desired target temperature.\",\n \"unit\": \"degreeCelsius\",\n \"writable\": true\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"maxTempSinceLastReboot\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\",\n \"displayName\": \"Max temperature since last reboot.\",\n \"description\": \"Returns the max temperature since last device reboot.\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"getMaxMinReport\",\n \"displayName\": \"Get Max-Min report.\",\n \"description\": \"This command returns the max, min and average temperature from the specified time to the current time.\",\n \"request\": {\n \"name\": \"since\",\n \"displayName\": \"Since\",\n \"description\": \"Period to return the max-min report.\",\n \"schema\": \"dateTime\"\n },\n \"response\": {\n \"name\": \"tempReport\",\n \"displayName\": \"Temperature Report\",\n \"schema\": {\n \"@type\": \"Object\",\n \"fields\": [\n {\n \"name\": \"maxTemp\",\n \"displayName\": \"Max temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"minTemp\",\n \"displayName\": \"Min temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"avgTemp\",\n \"displayName\": \"Average Temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"startTime\",\n \"displayName\": \"Start Time\",\n \"schema\": \"dateTime\"\n },\n {\n \"name\": \"endTime\",\n \"displayName\": \"End Time\",\n \"schema\": \"dateTime\"\n }\n ]\n }\n }\n }\n ]\n}", + "Content-Type" : "text/plain; charset=utf-8", + "X-GitHub-Request-Id" : "7A10:320C:3A12D:4AC16:615DF8C6", + "X-Cache" : "HIT", + "X-Content-Type-Options" : "nosniff", + "Connection" : "keep-alive", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "Accept-Ranges" : "bytes", + "Cache-Control" : "max-age=300", + "ETag" : "\"0d2c122754b690ebb4106d28683b3bc7be1dced98582291e46df6433d31e464d\"", + "Vary" : "Authorization,Accept-Encoding,Origin", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-Cache-Hits" : "1", + "X-Fastly-Request-ID" : "c293bc980713d9739478bdfc73afb537758f0ba5" + }, + "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/%2FAzure%2Fiot-plugandplay-models%2Fmain%2Fmetadata.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "73b90be1-2ca8-4552-ba51-b5a0ed23d254" + }, + "Response" : { + "X-Cache" : "HIT", + "content-length" : "117", + "Access-Control-Allow-Origin" : "*", + "Connection" : "keep-alive", + "retry-after" : "0", + "StatusCode" : "301", + "Source-Age" : "3151", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "X-Timer" : "S1633551638.839463,VS0,VE0", + "Accept-Ranges" : "bytes", + "X-Served-By" : "cache-sea4430-SEA", + "Vary" : "Authorization,Accept-Encoding", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-Cache-Hits" : "1", + "Body" : "Moved Permanently.\n\n", + "X-Fastly-Request-ID" : "c70431723262afd1fdf226a53fe090cb47db2fa8", + "Content-Type" : "text/html; charset=utf-8", + "Location" : "/Azure/iot-plugandplay-models/main/Azure/iot-plugandplay-models/main/metadata.json", + "X-GitHub-Request-Id" : "3658:1B57:376C8:48218:615DF8C6" + }, + "Exception" : null + } ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[4].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[4].json new file mode 100644 index 0000000000000..ba5f37f8f8555 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[4].json @@ -0,0 +1,4 @@ +{ + "networkCallRecords" : [ ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[1].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[1].json index bd9a808e3413a..1f05d86e39471 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[1].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[1].json @@ -1,30 +1,30 @@ { "networkCallRecords" : [ { "Method" : "GET", - "Uri" : "https://REDACTED.azure.com/%2Fdtmi%2Fcom%2Fexample%2Fthermostat-1.json", + "Uri" : "https://REDACTED.azure.com/dtmi%2Fcom%2Fexample%2Fthermostat-1.json", "Headers" : { - "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (16.0.1; Windows 10; 10.0)", - "x-ms-client-request-id" : "9905c36a-b2ab-4747-9660-197dad311446" + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "1430d25e-3dd9-430d-b1b7-7ea24f5fd6a5" }, "Response" : { "X-Cache" : "HIT", "content-length" : "2469", "x-ms-version" : "2018-03-28", - "Server" : "ECAcc (sed/E107)", + "Server" : "ECAcc (sed/E154)", "Access-Control-Allow-Methods" : "GET, HEAD, OPTIONS", "Last-Modified" : "Wed, 14 Apr 2021 00:07:35 GMT", "retry-after" : "0", "StatusCode" : "200", "Access-Control-Allow-Headers" : "*", - "Date" : "Wed, 29 Sep 2021 21:52:07 GMT", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", "Content-MD5" : "U0VZgOgpfb6bwvG5UDVZuw==", "Accept-Ranges" : "bytes", "Access-Control-Expose-Headers" : "*", "Etag" : "\"0x8D8FED94ED5FC94\"", "x-ms-error-code" : "ConditionNotMet", - "x-ms-request-id" : "22c4d7b0-d01e-0073-1816-b4178d000000", + "x-ms-request-id" : "8b667ceb-b01e-00a5-2757-b6d9e7000000", "Body" : "{\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:Thermostat;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Thermostat\",\n \"description\": \"Reports current temperature and provides desired temperature control.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"Temperature\"\n ],\n \"name\": \"temperature\",\n \"displayName\": \"Temperature\",\n \"description\": \"Temperature in degrees Celsius.\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\"\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"targetTemperature\",\n \"schema\": \"double\",\n \"displayName\": \"Target Temperature\",\n \"description\": \"Allows to remotely specify the desired target temperature.\",\n \"unit\": \"degreeCelsius\",\n \"writable\": true\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"maxTempSinceLastReboot\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\",\n \"displayName\": \"Max temperature since last reboot.\",\n \"description\": \"Returns the max temperature since last device reboot.\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"getMaxMinReport\",\n \"displayName\": \"Get Max-Min report.\",\n \"description\": \"This command returns the max, min and average temperature from the specified time to the current time.\",\n \"request\": {\n \"name\": \"since\",\n \"displayName\": \"Since\",\n \"description\": \"Period to return the max-min report.\",\n \"schema\": \"dateTime\"\n },\n \"response\": {\n \"name\": \"tempReport\",\n \"displayName\": \"Temperature Report\",\n \"schema\": {\n \"@type\": \"Object\",\n \"fields\": [\n {\n \"name\": \"maxTemp\",\n \"displayName\": \"Max temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"minTemp\",\n \"displayName\": \"Min temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"avgTemp\",\n \"displayName\": \"Average Temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"startTime\",\n \"displayName\": \"Start Time\",\n \"schema\": \"dateTime\"\n },\n {\n \"name\": \"endTime\",\n \"displayName\": \"End Time\",\n \"schema\": \"dateTime\"\n }\n ]\n }\n }\n }\n ]\n}", - "Age" : "153814", + "Age" : "505072", "Content-Type" : "application/json" }, "Exception" : null diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[3].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[3].json new file mode 100644 index 0000000000000..011ac367502b4 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[3].json @@ -0,0 +1,40 @@ +{ + "networkCallRecords" : [ { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/dtmi%2Fcom%2Fexample%2Fthermostat-1.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "9e54d0ce-4794-472b-bcb3-6f776c62d69c" + }, + "Response" : { + "content-length" : "2469", + "Access-Control-Allow-Origin" : "*", + "retry-after" : "0", + "StatusCode" : "200", + "Source-Age" : "15", + "X-Timer" : "S1633551638.735210,VS0,VE1", + "X-Frame-Options" : "deny", + "Strict-Transport-Security" : "max-age=31536000", + "X-Served-By" : "cache-sea4430-SEA", + "Content-Security-Policy" : "default-src 'none'; style-src 'unsafe-inline'; sandbox", + "X-XSS-Protection" : "1; mode=block", + "Body" : "{\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:com:example:Thermostat;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Thermostat\",\n \"description\": \"Reports current temperature and provides desired temperature control.\",\n \"contents\": [\n {\n \"@type\": [\n \"Telemetry\",\n \"Temperature\"\n ],\n \"name\": \"temperature\",\n \"displayName\": \"Temperature\",\n \"description\": \"Temperature in degrees Celsius.\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\"\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"targetTemperature\",\n \"schema\": \"double\",\n \"displayName\": \"Target Temperature\",\n \"description\": \"Allows to remotely specify the desired target temperature.\",\n \"unit\": \"degreeCelsius\",\n \"writable\": true\n },\n {\n \"@type\": [\n \"Property\",\n \"Temperature\"\n ],\n \"name\": \"maxTempSinceLastReboot\",\n \"schema\": \"double\",\n \"unit\": \"degreeCelsius\",\n \"displayName\": \"Max temperature since last reboot.\",\n \"description\": \"Returns the max temperature since last device reboot.\"\n },\n {\n \"@type\": \"Command\",\n \"name\": \"getMaxMinReport\",\n \"displayName\": \"Get Max-Min report.\",\n \"description\": \"This command returns the max, min and average temperature from the specified time to the current time.\",\n \"request\": {\n \"name\": \"since\",\n \"displayName\": \"Since\",\n \"description\": \"Period to return the max-min report.\",\n \"schema\": \"dateTime\"\n },\n \"response\": {\n \"name\": \"tempReport\",\n \"displayName\": \"Temperature Report\",\n \"schema\": {\n \"@type\": \"Object\",\n \"fields\": [\n {\n \"name\": \"maxTemp\",\n \"displayName\": \"Max temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"minTemp\",\n \"displayName\": \"Min temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"avgTemp\",\n \"displayName\": \"Average Temperature\",\n \"schema\": \"double\"\n },\n {\n \"name\": \"startTime\",\n \"displayName\": \"Start Time\",\n \"schema\": \"dateTime\"\n },\n {\n \"name\": \"endTime\",\n \"displayName\": \"End Time\",\n \"schema\": \"dateTime\"\n }\n ]\n }\n }\n }\n ]\n}", + "Content-Type" : "text/plain; charset=utf-8", + "X-GitHub-Request-Id" : "7A10:320C:3A12D:4AC16:615DF8C6", + "X-Cache" : "HIT", + "X-Content-Type-Options" : "nosniff", + "Connection" : "keep-alive", + "Date" : "Wed, 06 Oct 2021 20:20:37 GMT", + "Via" : "1.1 varnish", + "Accept-Ranges" : "bytes", + "Cache-Control" : "max-age=300", + "ETag" : "\"0d2c122754b690ebb4106d28683b3bc7be1dced98582291e46df6433d31e464d\"", + "Vary" : "Authorization,Accept-Encoding,Origin", + "Expires" : "Wed, 06 Oct 2021 20:25:37 GMT", + "X-Cache-Hits" : "1", + "X-Fastly-Request-ID" : "7343f212515edee8dfd161a8a65c274ab6988010" + }, + "Exception" : null + } ], + "variables" : [ ] +} \ No newline at end of file diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[4].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[4].json new file mode 100644 index 0000000000000..ba5f37f8f8555 --- /dev/null +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDepsDisableDependencyResolution[4].json @@ -0,0 +1,4 @@ +{ + "networkCallRecords" : [ ], + "variables" : [ ] +} \ No newline at end of file From 4dc8d23e30384caafe69308f43f4be8bd5bd5e98 Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Thu, 7 Oct 2021 11:53:18 -0700 Subject: [PATCH 13/16] Refactoring and test fix --- .../implementation/FileModelFetcher.java | 2 +- .../implementation/RepositoryHandler.java | 142 ++++++++---------- ...etModelsSingleDtmiWithDependencies[3].json | 38 ++++- 3 files changed, 98 insertions(+), 84 deletions(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java index b74873dd85099..1361a0413eb43 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/FileModelFetcher.java @@ -97,7 +97,7 @@ public Mono fetchMetadataAsync(URI repositoryUri, Context c } catch (IOException e) { logger.error(String.format(StatusStrings.ERROR_FETCHING_METADATA_CONTENT + " Error: %s.", path.toString(), e.getMessage())); - return Mono.empty(); + return Mono.error(new AzureException(e)); } } diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index df6af51d548be..c5f1db25386db 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -3,25 +3,26 @@ package com.azure.iot.modelsrepository.implementation; -import com.azure.core.exception.AzureException; import com.azure.core.util.Context; +import com.azure.core.util.CoreUtils; import com.azure.core.util.logging.ClientLogger; +import com.azure.core.util.logging.LogLevel; import com.azure.iot.modelsrepository.DtmiConventions; import com.azure.iot.modelsrepository.ModelDependencyResolution; -import com.azure.iot.modelsrepository.implementation.models.FetchMetadataResult; import com.azure.iot.modelsrepository.implementation.models.FetchModelResult; import com.azure.iot.modelsrepository.implementation.models.ModelMetadata; +import com.fasterxml.jackson.core.JsonProcessingException; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.net.URI; +import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Map; -import java.util.Queue; import java.util.List; -import java.util.LinkedList; import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; public final class RepositoryHandler { @@ -50,92 +51,76 @@ public Mono> processAsync(String dtmi, ModelDependencyResolu public Mono> processAsync(Iterable dtmis, ModelDependencyResolution resolutionOptions, Context context) { + List modelsToProcess = prepareWork(dtmis); - Map processedModels = new HashMap<>(); - Queue modelsToProcess = prepareWork(dtmis); - - return processAsync(modelsToProcess, resolutionOptions, context, processedModels) - .last() - .map(IntermediateFetchModelResult::getMap); - } - - private Flux processAsync( - Queue remainingWork, - ModelDependencyResolution resolutionOption, - Context context, - Map currentResults) { - - if (remainingWork.isEmpty()) { - return Flux.empty(); - } - - logger.info(String.format(StatusStrings.PROCESSING_DTMIS, remainingWork.peek())); - - return isFromExpanded(resolutionOption, context) - .flatMap(tryExpanded -> { - logger.info("Try from expanded is " + tryExpanded); - return modelFetcher.fetchModelAsync(remainingWork.peek(), repositoryUri, tryExpanded, context); - }) - .map(result -> new IntermediateFetchModelResult(result, currentResults)) - .expandDeep(customType -> { - if (remainingWork.isEmpty()) { - return Flux.empty(); - } - - Map results = customType.getMap(); - FetchModelResult response = customType.getFetchModelResult(); - String targetDtmi = remainingWork.poll(); + return isExpandedAvailable(resolutionOptions, context) + .flatMapMany(tryExpanded -> processAsync(tryExpanded, modelsToProcess, resolutionOptions, context)) + .collectList() + .flatMap(results -> { + Map processedModels = new HashMap<>(); - if (response.isFromExpanded()) { - try { - Map expanded = new ModelsQuery(response.getDefinition()).listToMap(); - for (Map.Entry item : expanded.entrySet()) { - if (!results.containsKey(item.getKey())) { - results.put(item.getKey(), item.getValue()); + try { + for (FetchModelResult result : results) { + ModelsQuery modelsQuery = new ModelsQuery(result.getDefinition()); + if (result.isFromExpanded()) { + Map expanded = modelsQuery.listToMap(); + for (Map.Entry item : expanded.entrySet()) { + processedModels.putIfAbsent(item.getKey(), item.getValue()); } + } else { + ModelMetadata metadata = modelsQuery.parseModel(); + processedModels.put(metadata.getId(), result.getDefinition()); } - - return processAsync(remainingWork, resolutionOption, context, results); - } catch (Exception e) { - return Mono.error(e); } + } catch (JsonProcessingException ex) { + return Mono.error(ex); } - try { - ModelMetadata metadata = new ModelsQuery(response.getDefinition()).parseModel(); + return Mono.just(processedModels); + }); + } - if (resolutionOption == ModelDependencyResolution.ENABLED) { - List dependencies = metadata.getDependencies(); + private Flux processAsync(boolean tryExpanded, List dtmis, + ModelDependencyResolution resolution, Context context) { + return Flux.concat(dtmis.stream().map(dtmi -> processDtmi(tryExpanded, dtmi, resolution, context)) + .collect(Collectors.toList())); + } - if (dependencies.size() > 0) { - logger.info(StatusStrings.DISCOVERED_DEPENDENCIES, String.join("\", \"", dependencies)); - } + private Flux processDtmi(boolean tryExpanded, String dtmi, ModelDependencyResolution resolution, + Context context) { + return modelFetcher.fetchModelAsync(dtmi, repositoryUri, tryExpanded, context) + .flatMapMany(response -> { + // If the model was pre-computed, already expanded, processing of it is done. + if (response.isFromExpanded()) { + return Flux.just(response); + } - remainingWork.addAll(dependencies); - } + // If resolving dependencies isn't supported processing completes once the model response is returned. + if (resolution != ModelDependencyResolution.ENABLED) { + return Flux.just(response); + } - String parsedDtmi = metadata.getId(); - if (!parsedDtmi.equals(targetDtmi)) { - logger.error(String.format(StatusStrings.INCORRECT_DTMI_CASING, targetDtmi, parsedDtmi)); - String errorMessage = String.format(StatusStrings.GENERIC_GET_MODELS_ERROR, targetDtmi) + String.format(StatusStrings.INCORRECT_DTMI_CASING, targetDtmi, parsedDtmi); + try { + ModelMetadata metadata = new ModelsQuery(response.getDefinition()).parseModel(); + List dependencies = metadata.getDependencies(); - return Mono.error(new AzureException(errorMessage)); + if (!CoreUtils.isNullOrEmpty(dependencies)) { + logger.log(LogLevel.INFORMATIONAL, () -> + String.format(StatusStrings.DISCOVERED_DEPENDENCIES, String.join("\", \"", dependencies))); + return processAsync(tryExpanded, dependencies, resolution, context).concatWith(Flux.just(response)); } - - results.put(targetDtmi, response.getDefinition()); - return processAsync(remainingWork, resolutionOption, context, results); - + return Flux.just(response); } catch (Exception e) { return Mono.error(e); } }); } - private Queue prepareWork(Iterable dtmis) { - Queue modelsToProcess = new LinkedList<>(); + private List prepareWork(Iterable dtmis) { + List modelsToProcess = new ArrayList<>(); for (String dtmi : dtmis) { if (!DtmiConventions.isValidDtmi(dtmi)) { - logger.logExceptionAsError(new IllegalArgumentException(String.format(StatusStrings.INVALID_DTMI_FORMAT_S, dtmi))); + logger.log(LogLevel.ERROR, () -> String.format(StatusStrings.INVALID_DTMI_FORMAT_S, dtmi)); } modelsToProcess.add(dtmi); @@ -144,7 +129,7 @@ private Queue prepareWork(Iterable dtmis) { return modelsToProcess; } - private Mono isFromExpanded(ModelDependencyResolution resolutionOption, Context context) { + private Mono isExpandedAvailable(ModelDependencyResolution resolutionOption, Context context) { // If ModelDependencyResolution.Enabled is requested the client will first attempt to fetch // metadata.json content from the target repository. The metadata object includes supported features // of the repository. @@ -153,17 +138,10 @@ private Mono isFromExpanded(ModelDependencyResolution resolutionOption, // If the model expanded form does not exist fall back to computing model dependencies just-in-time. if (resolutionOption == ModelDependencyResolution.ENABLED) { return modelFetcher.fetchMetadataAsync(repositoryUri, context) - .onErrorResume(error -> Mono.just(new FetchMetadataResult())) - .flatMap(result -> { - Boolean tryFromExpanded = false; - if (result != null) { - logger.error("got me some results: " + result); - tryFromExpanded = result != null && result.getDefinition() != null - && result.getDefinition().getFeatures() != null - && result.getDefinition().getFeatures().isExpanded(); - } - return Mono.just(tryFromExpanded); - }); + .map(result -> result.getDefinition() != null + && result.getDefinition().getFeatures() != null + && result.getDefinition().getFeatures().isExpanded()) + .onErrorReturn(false); } return Mono.just(false); diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[3].json b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[3].json index 08020e83e1d2d..74573950aa227 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[3].json +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/test/resources/session-records/ModelRepositoryIntegrationTests.getModelsSingleDtmiWithDependencies[3].json @@ -161,6 +161,42 @@ "X-GitHub-Request-Id" : "3658:1B57:376C8:48218:615DF8C6" }, "Exception" : null + }, { + "Method" : "GET", + "Uri" : "https://REDACTED.githubusercontent.com/Azure/iot-plugandplay-models/main/dtmi%2Fazure%2Fdevicemanagement%2Fdeviceinformation-1.json", + "Headers" : { + "User-Agent" : "azsdk-java-azure-iot-modelsrepository/1.0.0-beta.2 (11.0.7; Windows 10; 10.0)", + "x-ms-client-request-id" : "0d61b93e-98bd-4a7a-9091-d05701c8a0f8" + }, + "Response" : { + "content-length" : "2212", + "Access-Control-Allow-Origin" : "*", + "retry-after" : "0", + "StatusCode" : "200", + "Source-Age" : "16", + "X-Timer" : "S1633551639.692640,VS0,VE1", + "X-Frame-Options" : "deny", + "Strict-Transport-Security" : "max-age=31536000", + "X-Served-By" : "cache-sea4479-SEA", + "Content-Security-Policy" : "default-src 'none'; style-src 'unsafe-inline'; sandbox", + "X-XSS-Protection" : "1; mode=block", + "Body" : "{\n \"@context\": \"dtmi:dtdl:context;2\",\n \"@id\": \"dtmi:azure:DeviceManagement:DeviceInformation;1\",\n \"@type\": \"Interface\",\n \"displayName\": \"Device Information\",\n \"contents\": [\n {\n \"@type\": \"Property\",\n \"name\": \"manufacturer\",\n \"displayName\": \"Manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Company name of the device manufacturer. This could be the same as the name of the original equipment manufacturer (OEM). Ex. Contoso.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"model\",\n \"displayName\": \"Device model\",\n \"schema\": \"string\",\n \"description\": \"Device model name or ID. Ex. Surface Book 2.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"swVersion\",\n \"displayName\": \"Software version\",\n \"schema\": \"string\",\n \"description\": \"Version of the software on your device. This could be the version of your firmware. Ex. 1.3.45\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"osName\",\n \"displayName\": \"Operating system name\",\n \"schema\": \"string\",\n \"description\": \"Name of the operating system on the device. Ex. Windows 10 IoT Core.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorArchitecture\",\n \"displayName\": \"Processor architecture\",\n \"schema\": \"string\",\n \"description\": \"Architecture of the processor on the device. Ex. x64 or ARM.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"processorManufacturer\",\n \"displayName\": \"Processor manufacturer\",\n \"schema\": \"string\",\n \"description\": \"Name of the manufacturer of the processor on the device. Ex. Intel.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalStorage\",\n \"displayName\": \"Total storage\",\n \"schema\": \"double\",\n \"description\": \"Total available storage on the device in kilobytes. Ex. 2048000 kilobytes.\"\n },\n {\n \"@type\": \"Property\",\n \"name\": \"totalMemory\",\n \"displayName\": \"Total memory\",\n \"schema\": \"double\",\n \"description\": \"Total available memory on the device in kilobytes. Ex. 256000 kilobytes.\"\n }\n ]\n }", + "Content-Type" : "text/plain; charset=utf-8", + "X-GitHub-Request-Id" : "956E:278C:249C9:34469:615DF8C6", + "X-Cache" : "HIT", + "X-Content-Type-Options" : "nosniff", + "Connection" : "keep-alive", + "Date" : "Wed, 06 Oct 2021 20:20:38 GMT", + "Via" : "1.1 varnish", + "Accept-Ranges" : "bytes", + "Cache-Control" : "max-age=300", + "ETag" : "\"7952e5f1274fe59fa4aa27c6ba55a1aebec0d5b2ac12f5c8124bbfb08eae4eee\"", + "Vary" : "Authorization,Accept-Encoding,Origin", + "Expires" : "Wed, 06 Oct 2021 20:25:38 GMT", + "X-Cache-Hits" : "1", + "X-Fastly-Request-ID" : "fab5c72ec9b38e981c9a9405ccd9db4ef5f0b69e" + }, + "Exception" : null } ], "variables" : [ ] -} \ No newline at end of file +} From a0af7d76e709326a4cfa869d97d4910aa9fb722c Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Thu, 7 Oct 2021 12:04:34 -0700 Subject: [PATCH 14/16] Add javadoc --- .../com/azure/iot/modelsrepository/DtmiConventions.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java index 02ad3095603da..d7ef2159403d2 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java @@ -74,6 +74,13 @@ public static URI getModelUri(String dtmi, URI repositoryUri, boolean expanded) } } + /** + * Generates the model path. + * + * @param dtmi DigitalTwin Model Id. + * @param expanded Is model from precomputed values + * @return The model path. + */ public static String getModelPath(String dtmi, boolean expanded) { String dtmiPath = dtmiToPath(dtmi); From a753f57e516fcb497aedf8bc5dfa22cd3525e238 Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Thu, 7 Oct 2021 12:29:26 -0700 Subject: [PATCH 15/16] Remove commented code --- .../java/com/azure/iot/modelsrepository/DtmiConventions.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java index d7ef2159403d2..06e62c6bb16e7 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/DtmiConventions.java @@ -41,7 +41,6 @@ public static boolean isValidDtmi(String dtmi) { if (dtmi == null || dtmi.isEmpty()) { return false; } - //return true; return VALID_DTMI_PATTERN.matcher(dtmi).matches(); } From c452a2e15229c31617983fb43c4fbd647292c4f2 Mon Sep 17 00:00:00 2001 From: Avin Agrawal Date: Thu, 7 Oct 2021 14:54:48 -0700 Subject: [PATCH 16/16] Address comments and add some javadocs --- .../implementation/RepositoryHandler.java | 14 +++++++------- .../implementation/models/FetchMetadataResult.java | 2 +- .../implementation/models/FetchModelResult.java | 2 +- .../implementation/models/ModelMetadata.java | 2 +- .../models/ModelsRepositoryMetadata.java | 11 +++++++++-- .../implementation/models/RepositoryFeatures.java | 4 ++++ 6 files changed, 23 insertions(+), 12 deletions(-) diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java index c5f1db25386db..b713b58afbc83 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/RepositoryHandler.java @@ -24,7 +24,10 @@ import java.util.Map; import java.util.stream.Collectors; - +/** + * The {@link RepositoryHandler} is responsible for processing fetched models + * and generates processed results which are sent back to the client. + */ public final class RepositoryHandler { private final URI repositoryUri; @@ -49,8 +52,7 @@ public Mono> processAsync(String dtmi, ModelDependencyResolu return processAsync(Collections.singletonList(dtmi), resolutionOptions, context); } - public Mono> processAsync(Iterable dtmis, ModelDependencyResolution - resolutionOptions, Context context) { + public Mono> processAsync(Iterable dtmis, ModelDependencyResolution resolutionOptions, Context context) { List modelsToProcess = prepareWork(dtmis); return isExpandedAvailable(resolutionOptions, context) @@ -80,14 +82,12 @@ public Mono> processAsync(Iterable dtmis, ModelDepen }); } - private Flux processAsync(boolean tryExpanded, List dtmis, - ModelDependencyResolution resolution, Context context) { + private Flux processAsync(boolean tryExpanded, List dtmis, ModelDependencyResolution resolution, Context context) { return Flux.concat(dtmis.stream().map(dtmi -> processDtmi(tryExpanded, dtmi, resolution, context)) .collect(Collectors.toList())); } - private Flux processDtmi(boolean tryExpanded, String dtmi, ModelDependencyResolution resolution, - Context context) { + private Flux processDtmi(boolean tryExpanded, String dtmi, ModelDependencyResolution resolution, Context context) { return modelFetcher.fetchModelAsync(dtmi, repositoryUri, tryExpanded, context) .flatMapMany(response -> { // If the model was pre-computed, already expanded, processing of it is done. diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java index cb88c8c679416..aa902d0180541 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchMetadataResult.java @@ -8,7 +8,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; /** - * The FetchMetadataResult class is used for storing the result of the + * The {@link FetchMetadataResult} class is used for storing the result of the * fetch repository metadata operation. It contains the metadata definition * and path */ diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchModelResult.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchModelResult.java index 559a0dc364c2a..d11f423de78d4 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchModelResult.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/FetchModelResult.java @@ -9,7 +9,7 @@ import java.util.Locale; /** - * The FetchModelResult class has the purpose of containing key elements of + * The {@link FetchModelResult} class has the purpose of containing key elements of * an IModelFetcher Fetch() operation including model definition, path and whether * it was from an expanded (pre-calculated) fetch. */ diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelMetadata.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelMetadata.java index 832ebfe6f3ca8..cf4739d9bbb64 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelMetadata.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelMetadata.java @@ -8,7 +8,7 @@ import java.util.List; /** - * ModelMetadata is designated to store KPIs from model parsing. + * {@link ModelMetadata} is designated to store KPIs from model parsing. */ public class ModelMetadata { private final String id; diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java index 38c6ed055af91..c0403a51b9192 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/ModelsRepositoryMetadata.java @@ -3,6 +3,10 @@ package com.azure.iot.modelsrepository.implementation.models; +/** + * {@link ModelsRepositoryMetadata} is designated to store + * information about models repository. + */ public class ModelsRepositoryMetadata { private final String commitId; @@ -11,8 +15,11 @@ public class ModelsRepositoryMetadata { private final Integer totalModelCount; private final RepositoryFeatures features; - public ModelsRepositoryMetadata(String commitId, String publishDateUtc, - String sourceRepo, Integer totalModelCount, RepositoryFeatures features) { + public ModelsRepositoryMetadata(String commitId, + String publishDateUtc, + String sourceRepo, + Integer totalModelCount, + RepositoryFeatures features) { this.commitId = commitId; this.publishDateUtc = publishDateUtc; this.sourceRepo = sourceRepo; diff --git a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java index dd7372d5730f7..8d58c8ec14056 100644 --- a/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java +++ b/sdk/modelsrepository/azure-iot-modelsrepository/src/main/java/com/azure/iot/modelsrepository/implementation/models/RepositoryFeatures.java @@ -3,6 +3,10 @@ package com.azure.iot.modelsrepository.implementation.models; +/** + * {@link RepositoryFeatures} is designated to store + * attributes which apply to all models in the repository + */ public class RepositoryFeatures { private final boolean expanded; private final boolean index;