You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
6.1 KiB
143 lines
6.1 KiB
// Licensed to the .NET Foundation under one or more agreements.
|
|
// The .NET Foundation licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net.Http;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Tye;
|
|
using Microsoft.Tye.Hosting;
|
|
using Microsoft.Tye.Hosting.Model;
|
|
using Microsoft.Tye.Hosting.Model.V1;
|
|
using Test.Infrastructure;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
using static Test.Infrastructure.TestHelpers;
|
|
|
|
namespace E2ETest
|
|
{
|
|
public class ReplicaStoppingTests
|
|
{
|
|
private readonly ITestOutputHelper _output;
|
|
private readonly TestOutputLogEventSink _sink;
|
|
private readonly JsonSerializerOptions _options;
|
|
|
|
private static readonly ReplicaState?[] startedOrHigher = new ReplicaState?[] { ReplicaState.Started, ReplicaState.Healthy, ReplicaState.Ready };
|
|
private static readonly ReplicaState?[] stoppedOrLower = new ReplicaState?[] { ReplicaState.Stopped, ReplicaState.Removed };
|
|
|
|
public ReplicaStoppingTests(ITestOutputHelper output)
|
|
{
|
|
_output = output;
|
|
_sink = new TestOutputLogEventSink(output);
|
|
|
|
_options = new JsonSerializerOptions()
|
|
{
|
|
PropertyNameCaseInsensitive = true,
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
WriteIndented = true,
|
|
};
|
|
|
|
_options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task MultiProjectStoppingTests()
|
|
{
|
|
using var projectDirectory = CopyTestProjectDirectory("health-checks");
|
|
|
|
var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye-none.yaml"));
|
|
var outputContext = new OutputContext(_sink, Verbosity.Debug);
|
|
var application = await ApplicationFactory.CreateAsync(outputContext, projectFile);
|
|
|
|
await RunHostingApplication(application, new HostOptions(), async (host, uri) =>
|
|
{
|
|
var replicaToStop = host.Application.Services["health-none"].Replicas.First();
|
|
Assert.Contains(replicaToStop.Value.State, startedOrHigher);
|
|
|
|
var replicasToRestart = new[] { replicaToStop.Key };
|
|
var restOfReplicas = host.Application.Services.SelectMany(s => s.Value.Replicas).Select(r => r.Value.Name).Where(r => r != replicaToStop.Key).ToArray();
|
|
|
|
Assert.True(await DoOperationAndWaitForReplicasToRestart(host, replicasToRestart.ToHashSet(), restOfReplicas.ToHashSet(), TimeSpan.FromSeconds(30), _ =>
|
|
{
|
|
replicaToStop.Value.StoppingTokenSource!.Cancel();
|
|
return Task.CompletedTask;
|
|
}));
|
|
|
|
Assert.Contains(replicaToStop.Value.State, stoppedOrLower);
|
|
Assert.True(host.Application.Services.SelectMany(s => s.Value.Replicas).All(r => startedOrHigher.Contains(r.Value.State)));
|
|
});
|
|
}
|
|
|
|
[ConditionalFact]
|
|
[SkipIfDockerNotRunning]
|
|
public async Task MultiProjectDockerStoppingTests()
|
|
{
|
|
using var projectDirectory = CopyTestProjectDirectory("multi-project");
|
|
|
|
var projectFile = new FileInfo(Path.Combine(projectDirectory.DirectoryPath, "tye.yaml"));
|
|
var outputContext = new OutputContext(_sink, Verbosity.Debug);
|
|
var application = await ApplicationFactory.CreateAsync(outputContext, projectFile);
|
|
|
|
await RunHostingApplication(application, new HostOptions() { Docker = true }, async (host, uri) =>
|
|
{
|
|
var replicaToStop = host.Application.Services["frontend"].Replicas.First();
|
|
Assert.Contains(replicaToStop.Value.State, startedOrHigher);
|
|
|
|
var replicasToRestart = new[] { replicaToStop.Key };
|
|
var restOfReplicas = host.Application.Services.SelectMany(s => s.Value.Replicas).Select(r => r.Value.Name).Where(r => r != replicaToStop.Key).ToArray();
|
|
|
|
Assert.True(await DoOperationAndWaitForReplicasToRestart(host, replicasToRestart.ToHashSet(), restOfReplicas.ToHashSet(), TimeSpan.FromSeconds(1), _ =>
|
|
{
|
|
replicaToStop.Value.StoppingTokenSource!.Cancel();
|
|
return Task.CompletedTask;
|
|
}));
|
|
|
|
Assert.Contains(replicaToStop.Value.State, startedOrHigher); // when a container restarts, it assumes the same replica
|
|
Assert.True(host.Application.Services.SelectMany(s => s.Value.Replicas).All(r => startedOrHigher.Contains(r.Value.State)));
|
|
});
|
|
}
|
|
|
|
private async Task RunHostingApplication(ApplicationBuilder application, HostOptions options, Func<TyeHost, Uri, Task> execute)
|
|
{
|
|
await using var host = new TyeHost(application.ToHostingApplication(), options)
|
|
{
|
|
Sink = _sink,
|
|
};
|
|
|
|
try
|
|
{
|
|
await StartHostAndWaitForReplicasToStart(host);
|
|
|
|
var uri = new Uri(host.Addresses!.First());
|
|
|
|
await execute(host, uri!);
|
|
}
|
|
finally
|
|
{
|
|
if (host.DashboardWebApplication != null)
|
|
{
|
|
var uri = new Uri(host.Addresses!.First());
|
|
|
|
using var client = new HttpClient();
|
|
|
|
foreach (var s in host.Application.Services.Values)
|
|
{
|
|
var logs = await client.GetStringAsync(new Uri(uri, $"/api/v1/logs/{s.Description.Name}"));
|
|
|
|
_output.WriteLine($"Logs for service: {s.Description.Name}");
|
|
_output.WriteLine(logs);
|
|
|
|
var description = await client.GetStringAsync(new Uri(uri, $"/api/v1/services/{s.Description.Name}"));
|
|
|
|
_output.WriteLine($"Service defintion: {s.Description.Name}");
|
|
_output.WriteLine(description);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|