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 void ResolveInvalidDtmiFormatThrowsException(string dtmi)
        {
            string            expectedExMsg = $"{StandardStrings.GenericResolverError(dtmi)}{StandardStrings.InvalidDtmiFormat(dtmi)}";
            ResolverException re            = Assert.ThrowsAsync <ResolverException>(async() => await _localClient.ResolveAsync(dtmi));

            Assert.AreEqual(re.Message, expectedExMsg);
        }
예제 #3
0
        public async Task <FetchResult> FetchAsync(string dtmi, Uri repositoryUri, CancellationToken cancellationToken = default)
        {
            Queue <string> work = new Queue <string>();

            if (_tryExpanded)
            {
                work.Enqueue(GetPath(dtmi, repositoryUri, true));
            }

            work.Enqueue(GetPath(dtmi, repositoryUri, false));

            string remoteFetchError = string.Empty;

            while (work.Count != 0 && !cancellationToken.IsCancellationRequested)
            {
                string tryContentPath = work.Dequeue();
                _logger.LogTrace(StandardStrings.FetchingContent(tryContentPath));

                string content = await EvaluatePathAsync(tryContentPath, cancellationToken);

                if (!string.IsNullOrEmpty(content))
                {
                    return(new FetchResult()
                    {
                        Definition = content,
                        Path = tryContentPath
                    });
                }

                remoteFetchError = StandardStrings.ErrorAccessRemoteRepositoryModel(tryContentPath);
                _logger.LogWarning(remoteFetchError);
            }

            throw new RequestFailedException(remoteFetchError);
        }
        public void ResolveWithWrongCasingThrowsException(string dtmi)
        {
            string expectedExMsg =
                $"{StandardStrings.GenericResolverError("dtmi:com:example:thermostat;1")}" +
                $"{StandardStrings.IncorrectDtmiCasing("dtmi:com:example:thermostat;1", "dtmi:com:example:Thermostat;1")}";

            ResolverException re = Assert.ThrowsAsync <ResolverException>(async() => await _localClient.ResolveAsync(dtmi));

            Assert.AreEqual(re.Message, expectedExMsg);
        }
        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());
        }
        public void FetchLocalRepositoryDoesNotExist()
        {
            string targetDtmi = "dtmi:com:example:thermostat;1";

            Uri invalidFileUri             = new Uri("file://totally/fake/path/please");
            LocalModelFetcher localFetcher = new LocalModelFetcher(_logger.Object, new ResolverClientOptions());

            Assert.ThrowsAsync <DirectoryNotFoundException>(async() => await localFetcher.FetchAsync(targetDtmi, invalidFileUri));

            _logger.ValidateLog(StandardStrings.ErrorAccessLocalRepository(invalidFileUri.AbsolutePath), LogLevel.Error, Times.Once());
        }
        // [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());
        }
        public FetchResult Fetch(string dtmi, Uri repositoryUri, CancellationToken cancellationToken = default)
        {
            string registryPath = repositoryUri.AbsolutePath;

            if (!Directory.Exists(registryPath))
            {
                string dnfError = StandardStrings.ErrorAccessLocalRepository(registryPath);
                _logger.LogError(dnfError);
                throw new DirectoryNotFoundException(dnfError);
            }

            Queue <string> work = new Queue <string>();

            if (_tryExpanded)
            {
                work.Enqueue(GetPath(dtmi, repositoryUri, true));
            }

            work.Enqueue(GetPath(dtmi, repositoryUri, false));

            string fnfError = string.Empty;

            while (work.Count != 0 && !cancellationToken.IsCancellationRequested)
            {
                string tryContentPath = work.Dequeue();
                _logger.LogTrace(StandardStrings.FetchingContent(tryContentPath));

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

                fnfError = StandardStrings.ErrorAccessLocalRepositoryModel(tryContentPath);
                _logger.LogWarning(fnfError);
            }

            throw new FileNotFoundException(fnfError);
        }
예제 #9
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);
        }
        public void ParserValidationResolveFromLocalRepoErrorOnParserCallbackDtmiCasing()
        {
            ModelParser parser           = new ModelParser();
            string      TestRegistryPath = TestHelpers.TestLocalModelRepository;

            // This model references another model with invalid casing.
            string modelPath = $"{TestRegistryPath}/dtmi/company/demodevice-1.json";

            // Shows how to quickly integrate the resolver client with the parser.
            ResolverClient client = new ResolverClient(TestRegistryPath);

            parser.DtmiResolver = client.ParserDtmiResolver;

            // Parser will throw on validation errors

            ResolverException e =
                Assert.ThrowsAsync <ResolverException>(async() => await parser.ParseAsync(new string[] { File.ReadAllText(modelPath) }));

            Assert.AreEqual(e.Message,
                            $"{StandardStrings.GenericResolverError("dtmi:azure:deviceManagement:DeviceInformation;1")}" +
                            $"{StandardStrings.IncorrectDtmiCasing("dtmi:azure:deviceManagement:DeviceInformation;1","dtmi:azure:DeviceManagement:DeviceInformation;1")}");
        }