Пример #1
0
        public async Task DockerFileChangeContextTest()
        {
            using var projectDirectory = CopyTestProjectDirectory("dockerfile");

            File.Move(Path.Combine(projectDirectory.DirectoryPath, "backend", "Dockerfile"), Path.Combine(projectDirectory.DirectoryPath, "Dockerfile"));

            var content = @"
name: frontend-backend
services:
- name: backend
  dockerFile: Dockerfile
  dockerFileContext: backend/
  bindings:
    - containerPort: 80
      protocol: http
- name: backend2
  dockerFile: ./Dockerfile
  dockerFileContext: ./backend
  bindings:
    - containerPort: 80
      protocol: http
- name: frontend
  project: frontend/frontend.csproj";

            var projectFile = Path.Combine(projectDirectory.DirectoryPath, "tye.yaml");
            await File.WriteAllTextAsync(projectFile, content);

            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, new FileInfo(projectFile));

            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                AllowAutoRedirect = false
            };

            var client = new HttpClient(new RetryHandler(handler));

            await RunHostingApplication(application, new HostOptions(), async (app, uri) =>
            {
                var frontendUri = await GetServiceUrl(client, uri, "frontend");
                var backendUri  = await GetServiceUrl(client, uri, "backend");
                var backend2Uri = await GetServiceUrl(client, uri, "backend2");

                var backendResponse  = await client.GetAsync(backendUri);
                var backend2Response = await client.GetAsync(backend2Uri);
                var frontendResponse = await client.GetAsync(frontendUri);

                Assert.True(backendResponse.IsSuccessStatusCode);
                Assert.True(backend2Response.IsSuccessStatusCode);
                Assert.True(frontendResponse.IsSuccessStatusCode);
            });
        }
Пример #2
0
        public async Task DockerNamedVolumeTest()
        {
            using var projectDirectory = CopyTestProjectDirectory("volume-test");
            var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));

            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            // Add a volume
            var project = ((ProjectServiceBuilder)application.Services[0]);
            // Remove the existing volume so we can generate a random one for this test to avoid conflicts
            var volumeName = "tye_docker_volumes_test" + Guid.NewGuid().ToString().Substring(0, 10);

            project.Volumes.Clear();
            project.Volumes.Add(new VolumeBuilder(source: null, name: volumeName, "/data"));

            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                AllowAutoRedirect = false
            };

            var client = new HttpClient(new RetryHandler(handler));
            var args   = new[] { "--docker" };

            await RunHostingApplication(application, args, async (app, serviceApi) =>
            {
                var serviceUri = await GetServiceUrl(client, serviceApi, "volume-test");

                Assert.NotNull(serviceUri);

                var response = await client.GetAsync(serviceUri);

                Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

                await client.PostAsync(serviceUri, new StringContent("Things saved to the volume!"));

                Assert.Equal("Things saved to the volume!", await client.GetStringAsync(serviceUri));
            });

            await RunHostingApplication(application, args, async (app, serviceApi) =>
            {
                var serviceUri = await GetServiceUrl(client, serviceApi, "volume-test");

                Assert.NotNull(serviceUri);

                // The volume has data persisted
                Assert.Equal("Things saved to the volume!", await client.GetStringAsync(serviceUri));
            });

            // Delete the volume
            await ProcessUtil.RunAsync("docker", $"volume rm {volumeName}");
        }
Пример #3
0
        public async Task WrongProjectPathProducesCorrectErrorMessage()
        {
            using var projectDirectory = TestHelpers.CopyTestProjectDirectory("frontend-backend");
            var projectFile   = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye-wrong-projectpath.yaml"));
            var outputContext = new OutputContext(_sink, Verbosity.Debug);

            var exception = await Assert.ThrowsAsync <CommandException>(async() =>
                                                                        await ApplicationFactory.CreateAsync(outputContext, projectFile));

            var wrongProjectPath = Path.Combine(projectDirectory.DirectoryPath, "backend1");

            Assert.Equal($"Failed to locate directory: '{wrongProjectPath}'.", exception.Message);
        }
Пример #4
0
        public async Task FrontendBackendWatchRunTest()
        {
            using var projectDirectory = CopyTestProjectDirectory("frontend-backend");

            var projectFile   = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                AllowAutoRedirect = false
            };

            var client = new HttpClient(new RetryHandler(handler));

            await RunHostingApplication(application, new HostOptions()
            {
                Watch = true
            }, async (app, uri) =>
            {
                // make sure both are running
                var frontendUri = await GetServiceUrl(client, uri, "frontend");
                var backendUri  = await GetServiceUrl(client, uri, "backend");

                var backendResponse  = await client.GetAsync(backendUri);
                var frontendResponse = await client.GetAsync(frontendUri);

                Assert.True(backendResponse.IsSuccessStatusCode);
                Assert.True(frontendResponse.IsSuccessStatusCode);

                var startupPath = Path.Combine(projectDirectory.DirectoryPath, "frontend", "Startup.cs");
                File.AppendAllText(startupPath, "\n");

                const int retries = 10;
                for (var i = 0; i < retries; i++)
                {
                    var logs = await client.GetStringAsync(new Uri(uri, $"/api/v1/logs/frontend"));

                    // "Application Started" should be logged twice due to the file change
                    if (logs.IndexOf("Application started") != logs.LastIndexOf("Application started"))
                    {
                        return;
                    }

                    await Task.Delay(5000);
                }

                throw new Exception("Failed to relaunch project with dotnet watch");
            });
        }
Пример #5
0
        public async Task MultiProjectPurgeTest()
        {
            var projectDirectory = new DirectoryInfo(Path.Combine(TestHelpers.GetSolutionRootDirectory("tye"), "samples", "multi-project"));

            using var tempDirectory = TempDirectory.Create();
            DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath);

            var projectFile   = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "tye.yaml"));
            var tyeDir        = new DirectoryInfo(Path.Combine(tempDirectory.DirectoryPath, ".tye"));
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            var host = new TyeHost(application.ToHostingApplication(), Array.Empty <string>())
            {
                Sink = _sink,
            };

            try
            {
                await TestHelpers.StartHostAndWaitForReplicasToStart(host);

                try
                {
                    var pids       = GetAllAppPids(host.Application);
                    var containers = GetAllContainerIds(host.Application);

                    Assert.True(Directory.Exists(tyeDir.FullName));
                    Assert.Subset(new HashSet <int>(GetAllPids()), new HashSet <int>(pids));
                    Assert.Subset(new HashSet <string>(await DockerAssert.GetRunningContainersIdsAsync(_output)),
                                  new HashSet <string>(containers));

                    await TestHelpers.PurgeHostAndWaitForGivenReplicasToStop(host,
                                                                             GetAllReplicasNames(host.Application));

                    var runningPids = new HashSet <int>(GetAllPids());
                    Assert.True(pids.All(pid => !runningPids.Contains(pid)));
                    var runningContainers =
                        new HashSet <string>(await DockerAssert.GetRunningContainersIdsAsync(_output));
                    Assert.True(containers.All(c => !runningContainers.Contains(c)));
                }
                finally
                {
                    await host.StopAsync();
                }
            }
            finally
            {
                host.Dispose();
                Assert.False(Directory.Exists(tyeDir.FullName));
            }
        }
Пример #6
0
        public async Task DoubleNestingWorks()
        {
            using var projectDirectory = TestHelpers.CopyTestProjectDirectory(Path.Combine("multirepo"));
            var content  = @"
name: VotingSample
services:
- name: vote
  include: vote/tye.yaml
- name: results
  include: results/tye.yaml";
            var yamlFile = Path.Combine(projectDirectory.DirectoryPath, "tye.yaml");
            await File.WriteAllTextAsync(yamlFile, content);

            // Debug targets can be null if not specified, so make sure calling host.Start does not throw.
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var projectFile   = new FileInfo(yamlFile);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            Assert.Equal(5, application.Services.Count);

            var vote = application.Services.Single(s => s.Name == "vote");

            Assert.Equal(2, vote.Dependencies.Count);
            Assert.Contains("worker", vote.Dependencies);
            Assert.Contains("redis", vote.Dependencies);

            var results = application.Services.Single(s => s.Name == "results");

            Assert.Single(results.Dependencies);
            Assert.Contains("worker", results.Dependencies);

            var worker = application.Services.Single(s => s.Name == "worker");

            Assert.Equal(2, worker.Dependencies.Count);
            Assert.Contains("redis", worker.Dependencies);
            Assert.Contains("postgres", worker.Dependencies);

            var redis = application.Services.Single(s => s.Name == "redis");

            Assert.Equal(3, redis.Dependencies.Count);
            Assert.Contains("postgres", redis.Dependencies);
            Assert.Contains("worker", redis.Dependencies);
            Assert.Contains("vote", redis.Dependencies);

            var postgres = application.Services.Single(s => s.Name == "postgres");

            Assert.Equal(2, postgres.Dependencies.Count);
            Assert.Contains("worker", postgres.Dependencies);
            Assert.Contains("redis", postgres.Dependencies);
        }
Пример #7
0
        public async Task FrontendDockerBackendProject()
        {
            using var projectDirectory = CopyTestProjectDirectory("frontend-backend");

            var projectFile   = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            // Transform the backend into a docker image for testing
            var project = (ProjectServiceBuilder)application.Services.First(s => s.Name == "frontend");

            application.Services.Remove(project);

            var outputFileName = project.AssemblyName + ".dll";
            var container      = new ContainerServiceBuilder(project.Name, $"mcr.microsoft.com/dotnet/core/aspnet:{project.TargetFrameworkVersion}")
            {
                IsAspNet = true
            };

            container.Dependencies.UnionWith(project.Dependencies);
            container.Volumes.Add(new VolumeBuilder(project.PublishDir, name: null, target: "/app"));
            container.Args = $"dotnet /app/{outputFileName} {project.Args}";
            // We're not setting up the dev cert here
            container.Bindings.AddRange(project.Bindings.Where(b => b.Protocol != "https"));

            await ProcessUtil.RunAsync("dotnet", $"publish \"{project.ProjectFile.FullName}\" /nologo", outputDataReceived : _sink.WriteLine, errorDataReceived : _sink.WriteLine);

            application.Services.Add(container);

            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                AllowAutoRedirect = false
            };

            var client = new HttpClient(new RetryHandler(handler));

            await RunHostingApplication(application, new HostOptions(), async (app, uri) =>
            {
                var frontendUri = await GetServiceUrl(client, uri, "frontend");
                var backendUri  = await GetServiceUrl(client, uri, "backend");

                var backendResponse  = await client.GetAsync(backendUri);
                var frontendResponse = await client.GetAsync(frontendUri);

                Assert.True(backendResponse.IsSuccessStatusCode);
                Assert.True(frontendResponse.IsSuccessStatusCode);
            });
        }
Пример #8
0
        public async Task MultipleProjectGenerateTest()
        {
            await DockerAssert.DeleteDockerImagesAsync(output, "test/backend");

            await DockerAssert.DeleteDockerImagesAsync(output, "test/frontend");

            await DockerAssert.DeleteDockerImagesAsync(output, "test/worker");

            var projectName = "multi-project";
            var environment = "production";

            var projectDirectory = new DirectoryInfo(Path.Combine(TestHelpers.GetSolutionRootDirectory("tye"), "samples", projectName));

            using var tempDirectory = TempDirectory.Create();
            DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath);

            var projectFile = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "tye.yaml"));

            var outputContext = new OutputContext(sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            // Need to add docker registry for generate
            application.Registry = new ContainerRegistry("test");

            try
            {
                await GenerateHost.ExecuteGenerateAsync(outputContext, application, environment, interactive : false);

                // name of application is the folder
                var content         = File.ReadAllText(Path.Combine(tempDirectory.DirectoryPath, $"{projectName}-generate-{environment}.yaml"));
                var expectedContent = File.ReadAllText($"testassets/generate/{projectName}.yaml");

                Assert.Equal(expectedContent.NormalizeNewLines(), content.NormalizeNewLines());

                await DockerAssert.AssertImageExistsAsync(output, "test/backend");

                await DockerAssert.AssertImageExistsAsync(output, "test/frontend");

                await DockerAssert.AssertImageExistsAsync(output, "test/worker");
            }
            finally
            {
                await DockerAssert.AssertImageExistsAsync(output, "test/backend");

                await DockerAssert.AssertImageExistsAsync(output, "test/frontend");

                await DockerAssert.AssertImageExistsAsync(output, "test/worker");
            }
        }
Пример #9
0
        public async Task ServiceWithoutLivenessShouldDefaultToHealthyTests()
        {
            using var projectDirectory = CopyTestProjectDirectory("health-checks");

            var projectFile   = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye-readiness.yaml"));
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            await using var host = new TyeHost(application.ToHostingApplication(), new HostOptions())
                        {
                            Sink = _sink,
                        };

            await StartHostAndWaitForReplicasToStart(host, new[] { "health-readiness" }, ReplicaState.Healthy);
        }
Пример #10
0
        public async Task MultipleProjectGenerateTest()
        {
            await DockerAssert.DeleteDockerImagesAsync(output, "test/backend");

            await DockerAssert.DeleteDockerImagesAsync(output, "test/frontend");

            await DockerAssert.DeleteDockerImagesAsync(output, "test/worker");

            var projectName = "multi-project";
            var environment = "production";

            using var projectDirectory = CopyTestProjectDirectory(projectName);

            var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));

            var outputContext = new OutputContext(sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            // Need to add docker registry for generate
            application.Registry = new ContainerRegistry("test");

            try
            {
                await GenerateHost.ExecuteGenerateAsync(outputContext, application, environment, interactive : false);

                // name of application is the folder
                var content = await File.ReadAllTextAsync(Path.Combine(projectDirectory.DirectoryPath, $"{projectName}-generate-{environment}.yaml"));

                var expectedContent = await File.ReadAllTextAsync($"testassets/generate/{projectName}.yaml");

                YamlAssert.Equals(expectedContent, content, output);

                await DockerAssert.AssertImageExistsAsync(output, "test/backend");

                await DockerAssert.AssertImageExistsAsync(output, "test/frontend");

                await DockerAssert.AssertImageExistsAsync(output, "test/worker");
            }
            finally
            {
                await DockerAssert.AssertImageExistsAsync(output, "test/backend");

                await DockerAssert.AssertImageExistsAsync(output, "test/frontend");

                await DockerAssert.AssertImageExistsAsync(output, "test/worker");
            }
        }
Пример #11
0
        public async Task Generate_Ingress()
        {
            var applicationName = "apps-with-ingress";
            var environment     = "production";

            await DockerAssert.DeleteDockerImagesAsync(output, "appa");

            await DockerAssert.DeleteDockerImagesAsync(output, "appa");

            using var projectDirectory = TestHelpers.CopyTestProjectDirectory(applicationName);

            var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));

            var outputContext = new OutputContext(sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            try
            {
                await GenerateHost.ExecuteGenerateAsync(outputContext, application, environment, interactive : false);

                // name of application is the folder
                var content = await File.ReadAllTextAsync(Path.Combine(projectDirectory.DirectoryPath, $"{applicationName}-generate-{environment}.yaml"));

                if (await KubectlDetector.GetKubernetesServerVersion(outputContext) >= new Version(1, 19))
                {
                    var expectedContent = await File.ReadAllTextAsync($"testassets/generate/{applicationName}.1.19.yaml");

                    YamlAssert.Equals(expectedContent, content, output);
                }
                else
                {
                    var expectedContent = await File.ReadAllTextAsync($"testassets/generate/{applicationName}.1.18.yaml");

                    YamlAssert.Equals(expectedContent, content, output);
                }

                await DockerAssert.AssertImageExistsAsync(output, "appa");

                await DockerAssert.AssertImageExistsAsync(output, "appb");
            }
            finally
            {
                await DockerAssert.DeleteDockerImagesAsync(output, "appa");

                await DockerAssert.DeleteDockerImagesAsync(output, "appb");
            }
        }
Пример #12
0
        public async Task IngressRunTest()
        {
            using var projectDirectory = CopyTestProjectDirectory("apps-with-ingress");

            var projectFile   = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                AllowAutoRedirect = false
            };

            var client = new HttpClient(new RetryHandler(handler));

            await RunHostingApplication(application, Array.Empty <string>(), async (app, uri) =>
            {
                var ingressUri = await GetServiceUrl(client, uri, "ingress");
                var appAUri    = await GetServiceUrl(client, uri, "appA");
                var appBUri    = await GetServiceUrl(client, uri, "appB");

                var appAResponse = await client.GetAsync(appAUri);
                var appBResponse = await client.GetAsync(appBUri);

                Assert.True(appAResponse.IsSuccessStatusCode);
                Assert.True(appBResponse.IsSuccessStatusCode);

                var responseA = await client.GetAsync(ingressUri + "/A");
                var responseB = await client.GetAsync(ingressUri + "/B");

                Assert.StartsWith("Hello from Application A", await responseA.Content.ReadAsStringAsync());
                Assert.StartsWith("Hello from Application B", await responseB.Content.ReadAsStringAsync());

                var requestA          = new HttpRequestMessage(HttpMethod.Get, ingressUri);
                requestA.Headers.Host = "a.example.com";
                var requestB          = new HttpRequestMessage(HttpMethod.Get, ingressUri);
                requestB.Headers.Host = "b.example.com";

                responseA = await client.SendAsync(requestA);
                responseB = await client.SendAsync(requestB);

                Assert.StartsWith("Hello from Application A", await responseA.Content.ReadAsStringAsync());
                Assert.StartsWith("Hello from Application B", await responseB.Content.ReadAsStringAsync());
            });
        }
Пример #13
0
        public async Task TargetFrameworkFromCliArgsDoesNotOverrideSingleTFM()
        {
            using var projectDirectory = TestHelpers.CopyTestProjectDirectory(Path.Combine("single-project"));
            var yamlFile = Path.Combine(projectDirectory.DirectoryPath, "tye.yaml");

            // Debug targets can be null if not specified, so make sure calling host.Start does not throw.
            var outputContext      = new OutputContext(_sink, Verbosity.Debug);
            var projectFile        = new FileInfo(yamlFile);
            var applicationBuilder = await ApplicationFactory.CreateAsync(outputContext, projectFile, "net5.0");

            Assert.Single(applicationBuilder.Services);
            var service = applicationBuilder.Services.Single(s => s.Name == "test-project");

            var containsTargetFramework = ((DotnetProjectServiceBuilder)service).BuildProperties.TryGetValue("TargetFramework", out var targetFramework);

            Assert.False(containsTargetFramework);
        }
Пример #14
0
        public async Task DockerNetworkAssignmentForNonExistingNetworkTest()
        {
            using var projectDirectory = CopyTestProjectDirectory("frontend-backend");

            var projectFile   = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            var dockerNetwork = "tye_docker_network_test" + Guid.NewGuid().ToString().Substring(0, 10);

            application.Network = dockerNetwork;

            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                AllowAutoRedirect = false
            };

            var client = new HttpClient(new RetryHandler(handler));

            await RunHostingApplication(
                application,
                new HostOptions()
            {
                Docker = true,
            },
                async (app, uri) =>
            {
                // Make sure we're running containers
                Assert.True(app.Services.All(s => s.Value.Description.RunInfo is DockerRunInfo));

                foreach (var serviceBuilder in application.Services)
                {
                    var serviceUri      = await GetServiceUrl(client, uri, serviceBuilder.Name);
                    var serviceResponse = await client.GetAsync(serviceUri);
                    Assert.True(serviceResponse.IsSuccessStatusCode);

                    var serviceResult = await client.GetStringAsync($"{uri}api/v1/services/{serviceBuilder.Name}");
                    var service       = JsonSerializer.Deserialize <V1Service>(serviceResult, _options);

                    Assert.NotNull(service);

                    Assert.NotEqual(dockerNetwork, service.Replicas.FirstOrDefault().Value.DockerNetwork);
                }
            });
        }
Пример #15
0
        public async Task NullDebugTargetsDoesNotThrow()
        {
            using var projectDirectory = CopyTestProjectDirectory(Path.Combine("single-project", "test-project"));

            var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "test-project.csproj"));

            // Debug targets can be null if not specified, so make sure calling host.Start does not throw.
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            await using var host = new TyeHost(application.ToHostingApplication(), Array.Empty <string>())
                        {
                            Sink = _sink,
                        };

            await host.StartAsync();
        }
Пример #16
0
        public async Task TyeBuild_SinglePhase_ExistingDockerfileWithBuildArgsMultiArgs()
        {
            var projectName = "single-phase-dockerfile-multi-args";
            var environment = "production";
            var imageName   = "test/web";

            await DockerAssert.DeleteDockerImagesAsync(output, imageName);

            using var projectDirectory = CopyTestProjectDirectory(projectName);
            Assert.True(File.Exists(Path.Combine(projectDirectory.DirectoryPath, "Dockerfile")), "Dockerfile should exist.");

            var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));

            var outputContext = new OutputContext(sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            application.Registry = new ContainerRegistry("test");

            try
            {
                await BuildHost.ExecuteBuildAsync(outputContext, application, environment, interactive : false);

                Assert.Single(application.Services.Single().Outputs.OfType <DockerImageOutput>());
                var builder   = (DockerFileServiceBuilder)application.Services.First();
                var valuePair = builder.BuildArgs.ElementAt(0);

                Assert.Equal(3, builder.BuildArgs.Count);
                Assert.Equal("pat", valuePair.Key);
                Assert.Equal("thisisapat", valuePair.Value);

                valuePair = builder.BuildArgs.ElementAt(1);
                Assert.Equal("number_of_replicas", valuePair.Key);
                Assert.Equal("2", valuePair.Value);

                valuePair = builder.BuildArgs.ElementAt(2);
                Assert.Equal("number_of_shards", valuePair.Key);
                Assert.Equal("5", valuePair.Value);

                await DockerAssert.AssertImageExistsAsync(output, imageName);
            }
            finally
            {
                await DockerAssert.DeleteDockerImagesAsync(output, imageName);
            }
        }
Пример #17
0
        public async Task CyclesStopImmediately()
        {
            using var projectDirectory = TestHelpers.CopyTestProjectDirectory(Path.Combine("single-project"));
            var content  = @"
name: single-project
services:
- name: test-project
  include: tye.yaml";
            var yamlFile = Path.Combine(projectDirectory.DirectoryPath, "tye.yaml");

            await File.WriteAllTextAsync(yamlFile, content);

            // Debug targets can be null if not specified, so make sure calling host.Start does not throw.
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, new FileInfo(yamlFile));

            Assert.Empty(application.Services);
        }
Пример #18
0
        public async Task TargetFrameworkFromCliArgsOverwriteYaml()
        {
            using var projectDirectory = TestHelpers.CopyTestProjectDirectory(Path.Combine("multi-targetframeworks"));
            var yamlFile = Path.Combine(projectDirectory.DirectoryPath, "tye-with-netcoreapp21.yaml");

            // Debug targets can be null if not specified, so make sure calling host.Start does not throw.
            var outputContext      = new OutputContext(_sink, Verbosity.Debug);
            var projectFile        = new FileInfo(yamlFile);
            var applicationBuilder = await ApplicationFactory.CreateAsync(outputContext, projectFile, "netcoreapp3.1");

            Assert.Single(applicationBuilder.Services);
            var service = applicationBuilder.Services.Single(s => s.Name == "multi-targetframeworks");

            var containsTargetFramework = ((DotnetProjectServiceBuilder)service).BuildProperties.TryGetValue("TargetFramework", out var targetFramework);

            Assert.True(containsTargetFramework);
            Assert.Equal("netcoreapp3.1", targetFramework);
        }
Пример #19
0
        public async Task ThrowIfNoSpecificTargetFramework()
        {
            using var projectDirectory = TestHelpers.CopyTestProjectDirectory(Path.Combine("multi-targetframeworks"));
            var yamlFile = Path.Combine(projectDirectory.DirectoryPath, "tye-no-buildproperties.yaml");

            // Debug targets can be null if not specified, so make sure calling host.Start does not throw.
            var outputContext      = new OutputContext(_sink, Verbosity.Debug);
            var projectFile        = new FileInfo(yamlFile);
            var applicationBuilder = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            Assert.Single(applicationBuilder.Services);
            var service = applicationBuilder.Services.Single(s => s.Name == "multi-targetframeworks");

            var containsTargetFramework = ((DotnetProjectServiceBuilder)service).BuildProperties.TryGetValue("TargetFramework", out var targetFramework);

            Assert.False(containsTargetFramework);

            Assert.Throws <InvalidOperationException>(() => applicationBuilder.ToHostingApplication());
        }
Пример #20
0
        public async Task MultipleProjectBuildTest()
        {
            await DockerAssert.DeleteDockerImagesAsync(output, "test/backend");

            await DockerAssert.DeleteDockerImagesAsync(output, "test/frontend");

            await DockerAssert.DeleteDockerImagesAsync(output, "test/worker");

            var projectName = "multi-project";
            var environment = "production";

            var projectDirectory = new DirectoryInfo(Path.Combine(TestHelpers.GetSolutionRootDirectory("tye"), "samples", projectName));

            using var tempDirectory = TempDirectory.Create();
            DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath);

            var projectFile = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "tye.yaml"));

            var outputContext = new OutputContext(sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            application.Registry = new ContainerRegistry("test");

            try
            {
                await BuildHost.ExecuteBuildAsync(outputContext, application, environment, interactive : false);

                await DockerAssert.AssertImageExistsAsync(output, "test/backend");

                await DockerAssert.AssertImageExistsAsync(output, "test/frontend");

                await DockerAssert.AssertImageExistsAsync(output, "test/worker");
            }
            finally
            {
                await DockerAssert.AssertImageExistsAsync(output, "test/backend");

                await DockerAssert.AssertImageExistsAsync(output, "test/frontend");

                await DockerAssert.AssertImageExistsAsync(output, "test/worker");
            }
        }
Пример #21
0
        public async Task FrontendBackendRunTestWithDocker()
        {
            var projectDirectory = new DirectoryInfo(Path.Combine(TestHelpers.GetSolutionRootDirectory("tye"), "samples", "frontend-backend"));

            using var tempDirectory = TempDirectory.Create(preferUserDirectoryOnMacOS: true);
            DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath);

            var projectFile   = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "tye.yaml"));
            var outputContext = new OutputContext(sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            using var host = new TyeHost(application.ToHostingApplication(), new[] { "--docker" })
                  {
                      Sink = sink,
                  };

            await host.StartAsync();

            try
            {
                // Make sure we're runningn containers
                Assert.True(host.Application.Services.All(s => s.Value.Description.RunInfo is DockerRunInfo));

                var handler = new HttpClientHandler
                {
                    ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                    AllowAutoRedirect = false
                };

                var client = new HttpClient(new RetryHandler(handler));

                var dashboardUri = new Uri(host.DashboardWebApplication !.Addresses.First());

                await CheckServiceIsUp(host.Application, client, "backend", dashboardUri, timeout : TimeSpan.FromSeconds(60));
                await CheckServiceIsUp(host.Application, client, "frontend", dashboardUri, timeout : TimeSpan.FromSeconds(60));
            }
            finally
            {
                await host.StopAsync();
            }
        }
Пример #22
0
        public async Task FrontendBackendRunTestWithDockerAndBuildConfigurationAsProperty(string buildConfiguration)
        {
            using var projectDirectory = CopyTestProjectDirectory("frontend-backend");

            var projectFile   = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, $"tye-{buildConfiguration.ToLower()}-configuration.yaml"));
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                AllowAutoRedirect = false
            };

            var client = new HttpClient(new RetryHandler(handler));

            await RunHostingApplication(application, new HostOptions()
            {
                Docker = true,
            }, async (app, uri) =>
            {
                // Make sure we're running containers
                Assert.True(app.Services.All(s => s.Value.Description.RunInfo is DockerRunInfo));

                var frontendUri = await GetServiceUrl(client, uri, "frontend");
                var backendUri  = await GetServiceUrl(client, uri, "backend");

                var backendResponse  = await client.GetAsync(backendUri);
                var frontendResponse = await client.GetAsync(frontendUri);

                Assert.True(backendResponse.IsSuccessStatusCode);
                Assert.True(frontendResponse.IsSuccessStatusCode);

                Assert.True(app.Services.All(s => s.Value.Description.RunInfo != null && ((DockerRunInfo)s.Value.Description.RunInfo).VolumeMappings.Count > 0));

                var outputFileInfos = app.Services.Select(s => new FileInfo((s.Value?.Description?.RunInfo as DockerRunInfo)?.VolumeMappings[0].Source ?? throw new InvalidOperationException())).ToList();

                Assert.True(outputFileInfos.All(f => f.Directory?.Parent?.Parent?.Name == buildConfiguration));
            });
        }
Пример #23
0
        public async Task DockerHostVolumeTest()
        {
            using var projectDirectory = CopyTestProjectDirectory("volume-test");
            var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));

            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            // Add a volume
            var project = (ProjectServiceBuilder)application.Services[0];

            using var tempDir = TempDirectory.Create(preferUserDirectoryOnMacOS: true);

            project.Volumes.Clear();
            project.Volumes.Add(new VolumeBuilder(source: tempDir.DirectoryPath, name: null, target: "/data"));

            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                AllowAutoRedirect = false
            };

            await File.WriteAllTextAsync(Path.Combine(tempDir.DirectoryPath, "file.txt"), "This content came from the host");

            var client  = new HttpClient(new RetryHandler(handler));
            var options = new HostOptions()
            {
                Docker = true,
            };

            await RunHostingApplication(application, options, async (app, serviceApi) =>
            {
                var serviceUri = await GetServiceUrl(client, serviceApi, "volume-test");

                Assert.NotNull(serviceUri);

                // The volume has data the host mapped data
                Assert.Equal("This content came from the host", await client.GetStringAsync(serviceUri));
            });
        }
Пример #24
0
        public async Task EnvironmentVariablesOnlySetForDirectDependencies()
        {
            using var projectDirectory = TestHelpers.CopyTestProjectDirectory(Path.Combine("multirepo"));
            var yamlFile = Path.Combine(projectDirectory.DirectoryPath, "results", "tye.yaml");

            // Debug targets can be null if not specified, so make sure calling host.Start does not throw.
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, new FileInfo(yamlFile));

            var app        = application.ToHostingApplication();
            var dictionary = new Dictionary <string, string>();

            app.PopulateEnvironment(app.Services["results"], (s1, s2) => dictionary[s1] = s2);

            // Just the WORKER is defined.
            Assert.Equal(8, dictionary.Count);

            Assert.Equal("http", dictionary["SERVICE__WORKER__PROTOCOL"]);
            // No POSTGRES or REDIS
            Assert.False(dictionary.ContainsKey("SERVICE__POSTGRES__PROTOCOL"));
            Assert.False(dictionary.ContainsKey("SERVICE__REDIS__PROTOCOL"));
        }
Пример #25
0
        public async Task ServicWithoutLivenessShouldBecomeReadyWhenReadyTests()
        {
            using var projectDirectory = CopyTestProjectDirectory("health-checks");

            var projectFile   = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye-readiness.yaml"));
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            await using var host = new TyeHost(application.ToHostingApplication(), new HostOptions())
                        {
                            Sink = _sink,
                        };

            await StartHostAndWaitForReplicasToStart(host, new[] { "health-readiness" }, ReplicaState.Healthy);

            var replicas = host.Application.Services["health-readiness"].Replicas.Select(r => r.Value).ToList();

            Assert.True(await DoOperationAndWaitForReplicasToChangeState(host, ReplicaState.Ready, replicas.Count, replicas.Select(r => r.Name).ToHashSet(), null, TimeSpan.Zero, async _ =>
            {
                await Task.WhenAll(replicas.Select(r => SetHealthyReadyInReplica(r, ready: true)));
            }));
        }
Пример #26
0
        public async Task DockerBaseImageAndTagTest()
        {
            using var projectDirectory = CopyTestProjectDirectory(Path.Combine("frontend-backend", "backend"));

            var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "backend-baseimage.csproj"));

            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            // Transform the backend into a docker image for testing
            var project = (ProjectServiceBuilder)application.Services.First(s => s.Name == "backend-baseimage");

            // check ContainerInfo values
            Assert.True(string.Equals(project.ContainerInfo !.BaseImageName, "mcr.microsoft.com/dotnet/core/sdk"));
            Assert.True(string.Equals(project.ContainerInfo !.BaseImageTag, "3.1-buster"));

            // check projectInfo values
            var projectRunInfo = new ProjectRunInfo(project);

            Assert.True(string.Equals(projectRunInfo !.ContainerBaseImage, project.ContainerInfo.BaseImageName));
            Assert.True(string.Equals(projectRunInfo !.ContainerBaseTag, project.ContainerInfo.BaseImageTag));
        }
Пример #27
0
        public async Task NullDebugTargetsDoesNotThrow()
        {
            var projectDirectory = new DirectoryInfo(Path.Combine(TestHelpers.GetSolutionRootDirectory("tye"), "samples", "single-project", "test-project"));

            using var tempDirectory = TempDirectory.Create();
            DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath);

            var projectFile = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "test-project.csproj"));

            // Debug targets can be null if not specified, so make sure calling host.Start does not throw.
            var outputContext = new OutputContext(sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            using var host = new TyeHost(application.ToHostingApplication(), Array.Empty <string>())
                  {
                      Sink = sink,
                  };

            await host.StartAsync();

            await host.StopAsync();
        }
Пример #28
0
        public async Task Generate_DirectDependencyForEnvVars()
        {
            var applicationName = "multirepo";
            var projectName     = "results";
            var otherProject    = "worker";
            var environment     = "production";

            await DockerAssert.DeleteDockerImagesAsync(output, projectName);

            await DockerAssert.DeleteDockerImagesAsync(output, otherProject);

            using var projectDirectory = TestHelpers.CopyTestProjectDirectory(applicationName);

            var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "results", "tye.yaml"));

            var outputContext = new OutputContext(sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            try
            {
                await GenerateHost.ExecuteGenerateAsync(outputContext, application, environment, interactive : false);

                // name of application is the folder
                var content = await File.ReadAllTextAsync(Path.Combine(projectDirectory.DirectoryPath, "results", $"VotingSample-generate-{environment}.yaml"));

                var expectedContent = await File.ReadAllTextAsync($"testassets/generate/{applicationName}.yaml");

                YamlAssert.Equals(expectedContent, content, output);
                await DockerAssert.AssertImageExistsAsync(output, projectName);

                await DockerAssert.AssertImageExistsAsync(output, otherProject);
            }
            finally
            {
                await DockerAssert.DeleteDockerImagesAsync(output, projectName);

                await DockerAssert.DeleteDockerImagesAsync(output, otherProject);
            }
        }
Пример #29
0
        public async Task MultiRepo_WorksWithCloning()
        {
            using var projectDirectory = TempDirectory.Create(preferUserDirectoryOnMacOS: true);

            var content  = @"
name: VotingSample
services:
- name: vote
  repository: https://github.com/jkotalik/TyeMultiRepoVoting
- name: results
  repository: https://github.com/jkotalik/TyeMultiRepoResults";
            var yamlFile = Path.Combine(projectDirectory.DirectoryPath, "tye.yaml");
            await File.WriteAllTextAsync(yamlFile, content);

            // Debug targets can be null if not specified, so make sure calling host.Start does not throw.
            var outputContext = new OutputContext(_sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, new FileInfo(yamlFile));

            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                AllowAutoRedirect = false
            };

            var client = new HttpClient(new RetryHandler(handler));

            await RunHostingApplication(application, new HostOptions(), async (app, uri) =>
            {
                var votingUri = await GetServiceUrl(client, uri, "vote");
                var workerUri = await GetServiceUrl(client, uri, "worker");

                var votingResponse = await client.GetAsync(votingUri);
                var workerResponse = await client.GetAsync(workerUri);

                Assert.True(votingResponse.IsSuccessStatusCode);
                Assert.Equal(HttpStatusCode.NotFound, workerResponse.StatusCode);
            });
        }
Пример #30
0
        public async Task FrontendBackendRunTest()
        {
            var projectDirectory = new DirectoryInfo(Path.Combine(TestHelpers.GetSolutionRootDirectory("tye"), "samples", "frontend-backend"));

            using var tempDirectory = TempDirectory.Create();
            DirectoryCopy.Copy(projectDirectory.FullName, tempDirectory.DirectoryPath);

            var projectFile   = new FileInfo(Path.Combine(tempDirectory.DirectoryPath, "tye.yaml"));
            var outputContext = new OutputContext(sink, Verbosity.Debug);
            var application   = await ApplicationFactory.CreateAsync(outputContext, projectFile);

            using var host = new TyeHost(application.ToHostingApplication(), Array.Empty <string>())
                  {
                      Sink = sink,
                  };

            await host.StartAsync();

            try
            {
                var handler = new HttpClientHandler
                {
                    ServerCertificateCustomValidationCallback = (a, b, c, d) => true,
                    AllowAutoRedirect = false
                };

                var client = new HttpClient(new RetryHandler(handler));

                var dashboardUri = new Uri(host.DashboardWebApplication !.Addresses.First());

                await CheckServiceIsUp(host.Application, client, "backend", dashboardUri);
                await CheckServiceIsUp(host.Application, client, "frontend", dashboardUri);
            }
            finally
            {
                await host.StopAsync();
            }
        }