public async Task FetchLocalRepository(bool fetchExpanded)
        {
            // Casing is irrelevant for fetchers as they grab content based on file-path
            // which will always be lowercase. Casing IS important for the resolve flow
            // and is covered by tests there.
            string targetDtmi = "dtmi:com:example:temperaturecontroller;1";

            ResolverClientOptions options = fetchExpanded ?
                                            new ResolverClientOptions(DependencyResolutionOption.TryFromExpanded) :
                                            new ResolverClientOptions();

            string            expectedPath = DtmiConventions.DtmiToQualifiedPath(targetDtmi, _localUri.AbsolutePath, fetchExpanded);
            LocalModelFetcher localFetcher = new LocalModelFetcher(_logger.Object, options);
            string            fetcherPath  = localFetcher.GetPath(targetDtmi, _localUri, fetchExpanded);

            Assert.AreEqual(fetcherPath, expectedPath);

            // Resolution correctness is covered in ResolverIntegrationTests
            FetchResult fetchResult = await localFetcher.FetchAsync(targetDtmi, _localUri);

            Assert.True(!string.IsNullOrEmpty(fetchResult.Definition));
            Assert.True(!string.IsNullOrEmpty(fetchResult.Path));
            Assert.AreEqual(fetchResult.FromExpanded, fetchExpanded);

            _logger.ValidateLog(StandardStrings.FetchingContent(fetcherPath), LogLevel.Trace, Times.Once());
        }
        public ModelsRepositoryMetadata FetchMetadata(Uri repositoryUri, CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(FileModelFetcher)}.{nameof(FetchMetadata)}");
            scope.Start();

            string metadataPath = DtmiConventions.GetMetadataUri(repositoryUri).LocalPath;

            try
            {
                cancellationToken.ThrowIfCancellationRequested();
                if (File.Exists(metadataPath))
                {
                    string content = File.ReadAllText(metadataPath, Encoding.UTF8);
                    return(JsonSerializer.Deserialize <ModelsRepositoryMetadata>(content));
                }
            }
            catch (OperationCanceledException ex)
            {
                scope.Failed(ex);
                throw;
            }
            catch (Exception ex)
            {
                // Exceptions thrown from fetching Repository Metadata should not be terminal.
                scope.Failed(ex);
            }

            ModelsRepositoryEventSource.Instance.FailureProcessingRepositoryMetadata(metadataPath);
            return(null);
        }
示例#3
0
        public static void RemoveMetadataFromLocalRepository()
        {
            string metadataFilePath = DtmiConventions.GetMetadataUri(new Uri(TestLocalModelsRepository)).LocalPath;

            if (File.Exists(metadataFilePath))
            {
                File.Delete(metadataFilePath);
            }
        }
        public void FetchLocalRepositoryModelDoesNotExist()
        {
            string            targetDtmi   = "dtmi:com:example:thermojax;1";
            LocalModelFetcher localFetcher = new LocalModelFetcher(_logger.Object, new ResolverClientOptions());

            Assert.ThrowsAsync <FileNotFoundException>(async() => await localFetcher.FetchAsync(targetDtmi, _localUri));

            string expectedModelPath = DtmiConventions.DtmiToQualifiedPath(targetDtmi, _localUri.AbsolutePath);

            _logger.ValidateLog(StandardStrings.ErrorAccessLocalRepositoryModel(expectedModelPath), LogLevel.Warning, Times.Once());
        }
示例#5
0
        public void GetModelInvalidDtmiDependencyThrowsException()
        {
            const string dtmi           = "dtmi:com:example:invalidmodel;1";
            const string invalidDep     = "dtmi:azure:fakeDeviceManagement:FakeDeviceInformation;2";
            string       invalidDepPath = DtmiConventions.GetModelUri(invalidDep, new Uri(ModelsRepositoryTestBase.TestLocalModelsRepository)).LocalPath;
            string       expectedExMsg  = $"{string.Format(StandardStrings.GenericGetModelsError, invalidDep)} {string.Format(StandardStrings.ErrorFetchingModelContent, invalidDepPath)}";

            ModelsRepositoryClient client = GetClient(ModelsRepositoryTestBase.ClientType.Local);
            Func <Task>            act    = async() => await client.GetModelAsync(dtmi);

            act.Should().Throw <RequestFailedException>().WithMessage(expectedExMsg);
        }
        private static Queue <string> PrepareWork(string dtmi, Uri repositoryUri, bool tryExpanded)
        {
            Queue <string> work = new Queue <string>();

            if (tryExpanded)
            {
                work.Enqueue(DtmiConventions.GetModelUri(dtmi, repositoryUri, true).AbsoluteUri);
            }

            work.Enqueue(DtmiConventions.GetModelUri(dtmi, repositoryUri, false).AbsoluteUri);

            return(work);
        }
示例#7
0
        public static async Task <int> RepoExpand(DirectoryInfo localRepo)
        {
            if (localRepo == null)
            {
                localRepo = new DirectoryInfo(Path.GetFullPath("."));
            }

            var repoProvider = new RepoProvider(localRepo.FullName);

            if (!localRepo.Exists)
            {
                Outputs.WriteError($"Invalid target repository directory: {localRepo.FullName}.");
                return(ReturnCodes.InvalidArguments);
            }

            foreach (string file in Directory.EnumerateFiles(localRepo.FullName, "*.json",
                                                             new EnumerationOptions {
                RecurseSubdirectories = true
            }))
            {
                if (file.ToLower().EndsWith(".expanded.json"))
                {
                    continue;
                }

                try
                {
                    var    modelFile = new FileInfo(file);
                    string dtmi      = ParsingUtils.GetRootId(modelFile);

                    if (string.IsNullOrEmpty(dtmi))
                    {
                        continue;
                    }
                    List <string> expandedModel = await repoProvider.ExpandModel(dtmi);

                    string formattedJson = Outputs.FormatExpandedListAsJson(expandedModel);

                    string createPath = DtmiConventions.GetModelUri(dtmi, new Uri(localRepo.FullName), true).AbsolutePath;
                    Outputs.WriteToFile(createPath, formattedJson);
                    Outputs.WriteOut($"Created: {createPath}");
                }
                catch (Exception e)
                {
                    Outputs.WriteError($"Failure expanding model file: {file}, {e.Message}");
                    return(ReturnCodes.ProcessingError);
                }
            }

            return(ReturnCodes.Success);
        }
示例#8
0
        public static void AddMetadataToLocalRepository(bool supportsExpanded = true)
        {
            var metadata = new ModelsRepositoryMetadata();

            metadata.Features.Expanded = supportsExpanded;
            string metadataFilePath = DtmiConventions.GetMetadataUri(new Uri(TestLocalModelsRepository)).LocalPath;

            var options = new JsonSerializerOptions {
                WriteIndented = true
            };
            string metadataJsonString = JsonSerializer.Serialize(metadata, options);

            File.WriteAllText(metadataFilePath, metadataJsonString);
        }
        public static void IsValidDtmi()
        {
            #region Snippet:ModelsRepositorySamplesDtmiConventionsIsValidDtmi

            // This snippet shows how to validate a given DTMI string is well-formed.

            // Returns true
            DtmiConventions.IsValidDtmi("dtmi:com:example:Thermostat;1");

            // Returns false
            DtmiConventions.IsValidDtmi("dtmi:com:example:Thermostat");

            #endregion Snippet:ModelsRepositorySamplesDtmiConventionsIsValidDtmi
        }
        public FetchModelResult FetchModel(string dtmi, Uri repositoryUri, bool tryFromExpanded, CancellationToken cancellationToken = default)
        {
            using DiagnosticScope scope = _clientDiagnostics.CreateScope($"{nameof(FileModelFetcher)}.{nameof(FetchModel)}");
            scope.Start();

            try
            {
                var work = new Queue <string>();

                if (tryFromExpanded)
                {
                    work.Enqueue(DtmiConventions.GetModelUri(dtmi, repositoryUri, true).LocalPath);
                }

                work.Enqueue(DtmiConventions.GetModelUri(dtmi, repositoryUri, false).LocalPath);

                string fnfError = string.Empty;
                while (work.Count != 0)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    string tryContentPath = work.Dequeue();
                    ModelsRepositoryEventSource.Instance.FetchingModelContent(tryContentPath);

                    if (File.Exists(tryContentPath))
                    {
                        return(new FetchModelResult
                        {
                            Definition = File.ReadAllText(tryContentPath, Encoding.UTF8),
                            Path = tryContentPath
                        });
                    }

                    ModelsRepositoryEventSource.Instance.ErrorFetchingModelContent(tryContentPath);
                    fnfError = string.Format(CultureInfo.InvariantCulture, StandardStrings.ErrorFetchingModelContent, tryContentPath);
                }

                throw new RequestFailedException(
                          $"{string.Format(CultureInfo.InvariantCulture, StandardStrings.GenericGetModelsError, dtmi)} {fnfError}",
                          new FileNotFoundException(fnfError));
            }
            catch (Exception ex)
            {
                scope.Failed(ex);
                throw;
            }
        }
        public static void Import(string modelContent, DirectoryInfo repository)
        {
            string rootId     = ParsingUtils.GetRootId(modelContent);
            string createPath = DtmiConventions.GetModelUri(rootId, new Uri(repository.FullName)).AbsolutePath;

            Outputs.WriteOut($"- Importing model \"{rootId}\"...");
            if (File.Exists(createPath))
            {
                Outputs.WriteOut(
                    $"- Skipping \"{rootId}\". Model file already exists in repository.",
                    ConsoleColor.DarkCyan);
                return;
            }

            (new FileInfo(createPath)).Directory.Create();
            Outputs.WriteToFile(createPath, modelContent);
        }
示例#12
0
        public static string EnsureValidModelFilePath(string modelFilePath, string modelContent, string repository)
        {
            if (RepoProvider.IsRelativePath(repository))
            {
                repository = Path.GetFullPath(repository);
            }

            string rootId             = ParsingUtils.GetRootId(modelContent);
            Uri    targetModelPathUri = DtmiConventions.GetModelUri(rootId, new Uri(repository));
            Uri    modelFilePathUri   = new Uri(modelFilePath);

            if (targetModelPathUri.AbsolutePath != modelFilePathUri.AbsolutePath)
            {
                return(Path.GetFullPath(targetModelPathUri.AbsolutePath));
            }

            return(null);
        }
示例#13
0
        public async static Task ImportAsync(string modelContent, DirectoryInfo repository)
        {
            string rootId     = new Parsing(null).GetRootId(modelContent);
            string createPath = DtmiConventions.DtmiToQualifiedPath(rootId, repository.FullName);

            Outputs.WriteOut($"- Importing model \"{rootId}\"...");
            if (File.Exists(createPath))
            {
                Outputs.WriteOut(
                    $"Skipping \"{rootId}\". Model file already exists in repository.",
                    ConsoleColor.DarkCyan);
                return;
            }

            UTF8Encoding utf8WithoutBom = new UTF8Encoding(false);

            (new FileInfo(createPath)).Directory.Create();
            await File.WriteAllTextAsync(createPath, modelContent, utf8WithoutBom);
        }
        // [TestCase(true)] - TODO: Uncomment when consistent remote repo available.
        public async Task FetchRemoteRepository(bool fetchExpanded)
        {
            string targetDtmi = "dtmi:com:example:temperaturecontroller;1";

            RemoteModelFetcher remoteFetcher = new RemoteModelFetcher(_logger.Object, new ResolverClientOptions());
            string             expectedPath  = DtmiConventions.DtmiToQualifiedPath(targetDtmi, _remoteUri.AbsoluteUri, fetchExpanded);
            string             fetcherPath   = remoteFetcher.GetPath(targetDtmi, _remoteUri, fetchExpanded);

            Assert.AreEqual(fetcherPath, expectedPath);

            // Resolution correctness is covered in ResolverIntegrationTests
            FetchResult fetchResult = await remoteFetcher.FetchAsync(targetDtmi, _remoteUri);

            Assert.True(!string.IsNullOrEmpty(fetchResult.Definition));
            Assert.True(!string.IsNullOrEmpty(fetchResult.Path));
            Assert.AreEqual(fetchResult.FromExpanded, fetchExpanded);

            _logger.ValidateLog($"{StandardStrings.FetchingContent(fetcherPath)}", LogLevel.Trace, Times.Once());
        }
示例#15
0
        public void DtmiToQualifiedPath(string dtmi, string repository, string expectedPath)
        {
            if (string.IsNullOrEmpty(expectedPath))
            {
                Action act = () => DtmiConventions.DtmiToQualifiedPath(dtmi, repository);
                act.Should().Throw <ArgumentException>().WithMessage(string.Format(StandardStrings.InvalidDtmiFormat, dtmi));
                return;
            }

            string modelPath = DtmiConventions.DtmiToQualifiedPath(dtmi, repository);

            modelPath.Should().Be(expectedPath);

            string expectedExpandedPath = expectedPath.Replace(
                ModelsRepositoryConstants.JsonFileExtension, ModelsRepositoryConstants.ExpandedJsonFileExtension);
            string expandedModelPath = DtmiConventions.DtmiToQualifiedPath(dtmi, repository, true);

            expandedModelPath.Should().Be(expectedExpandedPath);
        }
        public static string EnsureValidModelFilePath(string modelFilePath, string modelContent, string repository)
        {
            if (IsRelativePath(repository))
            {
                repository = Path.GetFullPath(repository);
            }

            string rootId             = new Parsing(null).GetRootId(modelContent);
            string modelPath          = Path.GetFullPath(DtmiConventions.DtmiToQualifiedPath(rootId, repository));
            Uri    targetModelPathUri = new Uri(modelPath);
            Uri    modelFilePathUri   = new Uri(modelFilePath);

            if (targetModelPathUri.AbsolutePath != modelFilePathUri.AbsolutePath)
            {
                return(Path.GetFullPath(targetModelPathUri.AbsolutePath));
            }

            return(null);
        }
示例#17
0
        public void DtmiToQualifiedPath(string dtmi, string expectedPath, string repository)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                repository = repository.Replace("\\", "/");
            }

            if (string.IsNullOrEmpty(expectedPath))
            {
                ArgumentException re = Assert.Throws<ArgumentException>(() => DtmiConventions.DtmiToQualifiedPath(dtmi, repository));
                Assert.AreEqual(re.Message, StandardStrings.InvalidDtmiFormat(dtmi));
                return;
            }

            string modelPath = DtmiConventions.DtmiToQualifiedPath(dtmi, repository);
            Assert.AreEqual($"{repository}/{expectedPath}", modelPath);

            string expandedModelPath = DtmiConventions.DtmiToQualifiedPath(dtmi, repository, true);
            Assert.AreEqual($"{repository}/{expectedPath.Replace(".json", ".expanded.json")}", expandedModelPath);
        }
示例#18
0
        public void GetModelUri(string dtmi, string repository, string expectedUri)
        {
            var repositoryUri = new Uri(repository);

            if (string.IsNullOrEmpty(expectedUri))
            {
                Action act = () => DtmiConventions.GetModelUri(dtmi, repositoryUri);
                act.Should().Throw <ArgumentException>().WithMessage(string.Format(StandardStrings.InvalidDtmiFormat, dtmi));
                return;
            }

            Uri modelUri = DtmiConventions.GetModelUri(dtmi, repositoryUri);

            modelUri.AbsoluteUri.Should().Be(expectedUri);

            string expectedExpandedUri = expectedUri.Replace(
                ModelsRepositoryConstants.JsonFileExtension, ModelsRepositoryConstants.ExpandedJsonFileExtension);

            Uri expandedModelUri = DtmiConventions.GetModelUri(dtmi, repositoryUri, true);

            expandedModelUri.Should().Be(expectedExpandedUri);
        }
        private static FileInfo ImportModel(JsonElement modelItem, string fileName, DirectoryInfo repository, ILogger logger)
        {
            //Do DTMI verification
            var rootId = Validations.GetRootId(modelItem, fileName);

            if (!ResolverClient.IsValidDtmi(rootId.GetString()))
            {
                throw new InvalidDTMIException(rootId);
            }
            if (!Validations.ValidateDTMIs(modelItem, fileName, logger))
            {
                throw new InvalidDTMIException(fileName);
            }

            // write file to repository location
            var newPath = DtmiConventions.DtmiToQualifiedPath(rootId.GetString(), repository.FullName);

            // TODO: consistent paths. Use global arg formatters.
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                newPath = newPath.Replace("\\", "/");
            }

            if (!File.Exists(newPath))
            {
                CheckCreateDirectory(newPath);
                logger.LogTrace($"Writing new file to '{newPath}'. ");
                File.WriteAllText(newPath, modelItem.ToString(), Encoding.UTF8);
            }
            else
            {
                throw new IOException($"File '{newPath}' already exists. Please remove prior to execution.");
            }

            //return file info
            return(new FileInfo(newPath));
        }
        public static void GetModelUri()
        {
            #region Snippet:ModelsRepositorySamplesDtmiConventionsGetModelUri

            // This snippet shows obtaining a fully qualified path to a model file.

            // Local repository example
            Uri    localRepositoryUri      = new Uri("file:///path/to/repository/");
            string fullyQualifiedModelPath =
                DtmiConventions.GetModelUri("dtmi:com:example:Thermostat;1", localRepositoryUri).AbsolutePath;

            // Prints '/path/to/repository/dtmi/com/example/thermostat-1.json'
            Console.WriteLine(fullyQualifiedModelPath);

            // Remote repository example
            Uri remoteRepositoryUri = new Uri("https://contoso.com/models/");
            fullyQualifiedModelPath =
                DtmiConventions.GetModelUri("dtmi:com:example:Thermostat;1", remoteRepositoryUri).AbsoluteUri;

            // Prints 'https://contoso.com/models/dtmi/com/example/thermostat-1.json'
            Console.WriteLine(fullyQualifiedModelPath);

            #endregion Snippet:ModelsRepositorySamplesDtmiConventionsGetModelUri
        }
示例#21
0
        public static void GetDtmiToQualifiedPath()
        {
            #region Snippet:ModelsRepositorySamplesDtmiConventionsGetDtmiToQualifiedPath

            // This snippet shows obtaining a fully qualified path to a model file.

            // Local repository example
            string localRepository         = "/path/to/repository";
            string fullyQualifiedModelPath =
                DtmiConventions.DtmiToQualifiedPath("dtmi:com:example:Thermostat;1", localRepository);

            // Prints '/path/to/repository/dtmi/com/example/thermostat-1.json'
            Console.WriteLine(fullyQualifiedModelPath);

            // Remote repository example
            string remoteRepository = "https://contoso.com/models";
            fullyQualifiedModelPath =
                DtmiConventions.DtmiToQualifiedPath("dtmi:com:example:Thermostat;1", remoteRepository);

            // Prints 'https://contoso.com/models/dtmi/com/example/thermostat-1.json'
            Console.WriteLine(fullyQualifiedModelPath);

            #endregion Snippet:ModelsRepositorySamplesDtmiConventionsGetDtmiToQualifiedPath
        }
        public void DtmiToQualifiedPath(string dtmi, string expectedPath, string repository)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                repository = repository.Replace("\\", "/");
            }

            if (string.IsNullOrEmpty(expectedPath))
            {
                Action act = () => DtmiConventions.DtmiToQualifiedPath(dtmi, repository);
                act.Should().Throw <ArgumentException>().WithMessage(string.Format(StandardStrings.InvalidDtmiFormat, dtmi));
                return;
            }

            string modelPath = DtmiConventions.DtmiToQualifiedPath(dtmi, repository);

            modelPath.Should().Be($"{repository}/{expectedPath}");

            string expandedModelPath = DtmiConventions.DtmiToQualifiedPath(dtmi, repository, true);

            expandedModelPath
            .Should()
            .Be($"{repository}/{expectedPath.Replace(ModelsRepositoryConstants.JsonFileExtension, ModelsRepositoryConstants.ExpandedJsonFileExtension)}");
        }
示例#23
0
        private static string GetPath(string dtmi, Uri repositoryUri, bool expanded = false)
        {
            string registryPath = repositoryUri.AbsolutePath;

            return(DtmiConventions.DtmiToQualifiedPath(dtmi, registryPath, expanded));
        }
示例#24
0
        public void GetMetadataUri(string repository, string expectedUri)
        {
            Uri metadataUri = DtmiConventions.GetMetadataUri(new Uri(repository));

            metadataUri.AbsoluteUri.Should().Be(expectedUri);
        }
示例#25
0
 public void IsValidDtmi(string dtmi, bool expected)
 {
     DtmiConventions.IsValidDtmi(dtmi).Should().Be(expected);
 }
示例#26
0
 public void DtmiToPath(string dtmi, string expectedPath)
 {
     DtmiConventions.DtmiToPath(dtmi).Should().Be(expectedPath);
 }
示例#27
0
 public void DtmiToPath(string dtmi, string expectedPath)
 {
     Assert.AreEqual(expectedPath, DtmiConventions.DtmiToPath(dtmi));
 }
示例#28
0
        private static string GetPath(string dtmi, Uri repositoryUri, bool expanded = false)
        {
            string absoluteUri = repositoryUri.AbsoluteUri;

            return(DtmiConventions.DtmiToQualifiedPath(dtmi, absoluteUri, expanded));
        }