Browse Source

Added tags to yaml definition to be used in CLI run filter (#528)

* fixed unit test: Services_UnrecognizedKey

* TyeAssert - duplicated check removed

* YAML service.tags added to parser and unit tests

* filter services by tags - run argument + ApplicationFactory filter

* filter ingress by tags

* Make tags work for all scenarios

Co-authored-by: Justin Kotalik <jukotali@microsoft.com>
jkotalik/fixAzureFunctions
Krzysztof Koziarski 6 years ago
committed by GitHub
parent
commit
c9561a408f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      src/Microsoft.Tye.Core/ApplicationFactory.cs
  2. 32
      src/Microsoft.Tye.Core/ApplicationFactoryFilter.cs
  3. 1
      src/Microsoft.Tye.Core/ConfigModel/ConfigIngress.cs
  4. 2
      src/Microsoft.Tye.Core/ConfigModel/ConfigService.cs
  5. 17
      src/Microsoft.Tye.Core/Serialization/ConfigIngressParser.cs
  6. 19
      src/Microsoft.Tye.Core/Serialization/ConfigServiceParser.cs
  7. 2
      src/Microsoft.Tye.Core/Serialization/YamlParser.cs
  8. 16
      src/Microsoft.Tye.Core/StandardOptions.cs
  9. 5
      src/tye/BuildHost.cs
  10. 5
      src/tye/GenerateHost.cs
  11. 5
      src/tye/Program.BuildCommand.cs
  12. 11
      src/tye/Program.DeployCommand.cs
  13. 5
      src/tye/Program.GenerateCommand.cs
  14. 7
      src/tye/Program.PushCommand.cs
  15. 16
      src/tye/Program.RunCommand.cs
  16. 5
      src/tye/Program.UndeployCommand.cs
  17. 8
      src/tye/UndeployHost.cs
  18. 16
      test/Test.Infrastructure/TyeAssert.cs
  19. 97
      test/UnitTests/TyeDeserializationTests.cs

15
src/Microsoft.Tye.Core/ApplicationFactory.cs

@ -4,7 +4,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -15,7 +14,7 @@ namespace Microsoft.Tye
{ {
public static class ApplicationFactory public static class ApplicationFactory
{ {
public static async Task<ApplicationBuilder> CreateAsync(OutputContext output, FileInfo source) public static async Task<ApplicationBuilder> CreateAsync(OutputContext output, FileInfo source, ApplicationFactoryFilter? filter = null)
{ {
if (source is null) if (source is null)
{ {
@ -71,7 +70,11 @@ namespace Microsoft.Tye
root.Extensions.Add(extension); root.Extensions.Add(extension);
} }
foreach (var configService in config.Services) var services = filter?.ServicesFilter != null ?
config.Services.Where(filter.ServicesFilter).ToList() :
config.Services;
foreach (var configService in services)
{ {
ServiceBuilder service; ServiceBuilder service;
if (root.Services.Any(s => s.Name == configService.Name)) if (root.Services.Any(s => s.Name == configService.Name))
@ -320,7 +323,11 @@ namespace Microsoft.Tye
} }
} }
foreach (var configIngress in config.Ingress) var ingresses = filter?.IngressFilter != null ?
config.Ingress.Where(filter.IngressFilter).ToList() :
config.Ingress;
foreach (var configIngress in ingresses)
{ {
var ingress = new IngressBuilder(configIngress.Name!); var ingress = new IngressBuilder(configIngress.Name!);
ingress.Replicas = configIngress.Replicas ?? 1; ingress.Replicas = configIngress.Replicas ?? 1;

32
src/Microsoft.Tye.Core/ApplicationFactoryFilter.cs

@ -0,0 +1,32 @@
// 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.Linq;
using Microsoft.Tye.ConfigModel;
namespace Microsoft.Tye
{
public class ApplicationFactoryFilter
{
public Func<ConfigService, bool>? ServicesFilter { get; set; }
public Func<ConfigIngress, bool>? IngressFilter { get; set; }
public static ApplicationFactoryFilter? GetApplicationFactoryFilter(string[] tags)
{
ApplicationFactoryFilter? filter = null;
if (tags != null && tags.Any())
{
filter = new ApplicationFactoryFilter
{
ServicesFilter = service => tags.Any(b => service.Tags.Contains(b)),
IngressFilter = service => tags.Any(b => service.Tags.Contains(b))
};
}
return filter;
}
}
}

1
src/Microsoft.Tye.Core/ConfigModel/ConfigIngress.cs

@ -14,5 +14,6 @@ namespace Microsoft.Tye.ConfigModel
public int? Replicas { get; set; } public int? Replicas { get; set; }
public List<ConfigIngressRule> Rules { get; set; } = new List<ConfigIngressRule>(); public List<ConfigIngressRule> Rules { get; set; } = new List<ConfigIngressRule>();
public List<ConfigIngressBinding> Bindings { get; set; } = new List<ConfigIngressBinding>(); public List<ConfigIngressBinding> Bindings { get; set; } = new List<ConfigIngressBinding>();
public List<string> Tags { get; set; } = new List<string>();
} }
} }

2
src/Microsoft.Tye.Core/ConfigModel/ConfigService.cs

@ -4,7 +4,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Tye;
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
namespace Microsoft.Tye.ConfigModel namespace Microsoft.Tye.ConfigModel
@ -37,6 +36,7 @@ namespace Microsoft.Tye.ConfigModel
[YamlMember(Alias = "env")] [YamlMember(Alias = "env")]
public List<ConfigConfigurationSource> Configuration { get; set; } = new List<ConfigConfigurationSource>(); public List<ConfigConfigurationSource> Configuration { get; set; } = new List<ConfigConfigurationSource>();
public List<BuildProperty> BuildProperties { get; set; } = new List<BuildProperty>(); public List<BuildProperty> BuildProperties { get; set; } = new List<BuildProperty>();
public List<string> Tags { get; set; } = new List<string>();
public ConfigProbe? Liveness { get; set; } public ConfigProbe? Liveness { get; set; }
public ConfigProbe? Readiness { get; set; } public ConfigProbe? Readiness { get; set; }
} }

17
src/Microsoft.Tye.Core/Serialization/ConfigIngressParser.cs

@ -59,6 +59,14 @@ namespace Tye.Serialization
} }
HandleIngressBindings((child.Value as YamlSequenceNode)!, configIngress.Bindings); HandleIngressBindings((child.Value as YamlSequenceNode)!, configIngress.Bindings);
break; break;
case "tags":
if (child.Value.NodeType != YamlNodeType.Sequence)
{
throw new TyeYamlException(child.Value.Start, CoreStrings.FormatExpectedYamlSequence(key));
}
HandleIngressTags((child.Value as YamlSequenceNode)!, configIngress.Tags);
break;
default: default:
throw new TyeYamlException(child.Key.Start, CoreStrings.FormatUnrecognizedKey(key)); throw new TyeYamlException(child.Key.Start, CoreStrings.FormatUnrecognizedKey(key));
} }
@ -137,5 +145,14 @@ namespace Tye.Serialization
} }
} }
} }
private static void HandleIngressTags(YamlSequenceNode yamlSequenceNode, List<string> tags)
{
foreach (var child in yamlSequenceNode!.Children)
{
var tag = YamlParser.GetScalarValue(child);
tags.Add(tag);
}
}
} }
} }

19
src/Microsoft.Tye.Core/Serialization/ConfigServiceParser.cs

@ -3,8 +3,6 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Microsoft.Build.Evaluation;
using Microsoft.Tye.ConfigModel; using Microsoft.Tye.ConfigModel;
using YamlDotNet.RepresentationModel; using YamlDotNet.RepresentationModel;
@ -131,6 +129,14 @@ namespace Tye.Serialization
service.Readiness = new ConfigProbe(); service.Readiness = new ConfigProbe();
HandleServiceProbe((YamlMappingNode)child.Value, service.Readiness!); HandleServiceProbe((YamlMappingNode)child.Value, service.Readiness!);
break; break;
case "tags":
if (child.Value.NodeType != YamlNodeType.Sequence)
{
throw new TyeYamlException(child.Value.Start, CoreStrings.FormatExpectedYamlSequence(key));
}
HandleServiceTags((child.Value as YamlSequenceNode)!, service.Tags);
break;
default: default:
throw new TyeYamlException(child.Key.Start, CoreStrings.FormatUnrecognizedKey(key)); throw new TyeYamlException(child.Key.Start, CoreStrings.FormatUnrecognizedKey(key));
} }
@ -444,5 +450,14 @@ namespace Tye.Serialization
} }
} }
} }
private static void HandleServiceTags(YamlSequenceNode yamlSequenceNode, List<string> tags)
{
foreach (var child in yamlSequenceNode!.Children)
{
var tag = YamlParser.GetScalarValue(child);
tags.Add(tag);
}
}
} }
} }

2
src/Microsoft.Tye.Core/Serialization/YamlParser.cs

@ -62,12 +62,14 @@ namespace Tye.Serialization
service.Bindings ??= new List<ConfigServiceBinding>(); service.Bindings ??= new List<ConfigServiceBinding>();
service.Configuration ??= new List<ConfigConfigurationSource>(); service.Configuration ??= new List<ConfigConfigurationSource>();
service.Volumes ??= new List<ConfigVolume>(); service.Volumes ??= new List<ConfigVolume>();
service.Tags ??= new List<string>();
} }
foreach (var ingress in app.Ingress) foreach (var ingress in app.Ingress)
{ {
ingress.Bindings ??= new List<ConfigIngressBinding>(); ingress.Bindings ??= new List<ConfigIngressBinding>();
ingress.Rules ??= new List<ConfigIngressRule>(); ingress.Rules ??= new List<ConfigIngressRule>();
ingress.Tags ??= new List<string>();
} }
return app; return app;

16
src/Microsoft.Tye.Core/StandardOptions.cs

@ -30,6 +30,22 @@ namespace Microsoft.Tye
} }
} }
public static Option Tags
{
get
{
return new Option("--tags", "--filter")
{
Argument = new Argument<List<string>>("tags")
{
Arity = ArgumentArity.OneOrMore
},
Description = "Filter the group of running services by tag.",
Required = false
};
}
}
public static Option Force public static Option Force
{ {
get get

5
src/tye/BuildHost.cs

@ -11,10 +11,11 @@ namespace Microsoft.Tye
{ {
public static class BuildHost public static class BuildHost
{ {
public static async Task BuildAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive) public static async Task BuildAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive, string[] tags)
{ {
var output = new OutputContext(console, verbosity); var output = new OutputContext(console, verbosity);
var application = await ApplicationFactory.CreateAsync(output, path); var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(tags);
var application = await ApplicationFactory.CreateAsync(output, path, filter);
if (application.Services.Count == 0) if (application.Services.Count == 0)
{ {
throw new CommandException($"No services found in \"{application.Source.Name}\""); throw new CommandException($"No services found in \"{application.Source.Name}\"");

5
src/tye/GenerateHost.cs

@ -13,12 +13,13 @@ namespace Microsoft.Tye
{ {
public static class GenerateHost public static class GenerateHost
{ {
public static async Task GenerateAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive, string ns) public static async Task GenerateAsync(IConsole console, FileInfo path, Verbosity verbosity, bool interactive, string ns, string[] tags)
{ {
var output = new OutputContext(console, verbosity); var output = new OutputContext(console, verbosity);
output.WriteInfoLine("Loading Application Details..."); output.WriteInfoLine("Loading Application Details...");
var application = await ApplicationFactory.CreateAsync(output, path); var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(tags);
var application = await ApplicationFactory.CreateAsync(output, path, filter);
if (application.Services.Count == 0) if (application.Services.Count == 0)
{ {
throw new CommandException($"No services found in \"{application.Source.Name}\""); throw new CommandException($"No services found in \"{application.Source.Name}\"");

5
src/tye/Program.BuildCommand.cs

@ -21,9 +21,10 @@ namespace Microsoft.Tye
CommonArguments.Path_Required, CommonArguments.Path_Required,
StandardOptions.Interactive, StandardOptions.Interactive,
StandardOptions.Verbosity, StandardOptions.Verbosity,
StandardOptions.Tags
}; };
command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, bool>((console, path, verbosity, interactive) => command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, bool, string[]>((console, path, verbosity, interactive, tags) =>
{ {
// Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654
if (path is null) if (path is null)
@ -31,7 +32,7 @@ namespace Microsoft.Tye
throw new CommandException("No project or solution file was found."); throw new CommandException("No project or solution file was found.");
} }
return BuildHost.BuildAsync(console, path, verbosity, interactive); return BuildHost.BuildAsync(console, path, verbosity, interactive, tags);
}); });
return command; return command;

11
src/tye/Program.DeployCommand.cs

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.CommandLine; using System.CommandLine;
using System.CommandLine.Invocation; using System.CommandLine.Invocation;
using System.IO; using System.IO;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Tye.ConfigModel; using Microsoft.Tye.ConfigModel;
@ -23,6 +24,7 @@ namespace Microsoft.Tye
StandardOptions.Interactive, StandardOptions.Interactive,
StandardOptions.Verbosity, StandardOptions.Verbosity,
StandardOptions.Namespace, StandardOptions.Namespace,
StandardOptions.Tags,
}; };
command.AddOption(new Option(new[] { "-f", "--force" }) command.AddOption(new Option(new[] { "-f", "--force" })
@ -31,7 +33,7 @@ namespace Microsoft.Tye
Required = false Required = false
}); });
command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, bool, bool, string>(async (console, path, verbosity, interactive, force, @namespace) => command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, bool, bool, string, string[]>(async (console, path, verbosity, interactive, force, @namespace, tags) =>
{ {
// Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654
if (path is null) if (path is null)
@ -42,12 +44,15 @@ namespace Microsoft.Tye
var output = new OutputContext(console, verbosity); var output = new OutputContext(console, verbosity);
output.WriteInfoLine("Loading Application Details..."); output.WriteInfoLine("Loading Application Details...");
var application = await ApplicationFactory.CreateAsync(output, path);
var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(tags);
var application = await ApplicationFactory.CreateAsync(output, path, filter);
if (application.Services.Count == 0) if (application.Services.Count == 0)
{ {
throw new CommandException($"No services found in \"{application.Source.Name}\""); throw new CommandException($"No services found in \"{application.Source.Name}\"");
} }
if (!String.IsNullOrEmpty(@namespace)) if (!string.IsNullOrEmpty(@namespace))
{ {
application.Namespace = @namespace; application.Namespace = @namespace;
} }

5
src/tye/Program.GenerateCommand.cs

@ -22,13 +22,14 @@ namespace Microsoft.Tye
StandardOptions.Interactive, StandardOptions.Interactive,
StandardOptions.Verbosity, StandardOptions.Verbosity,
StandardOptions.Namespace, StandardOptions.Namespace,
StandardOptions.Tags
}; };
// This is a super-secret VIP-only command! It's useful for testing, but we're // This is a super-secret VIP-only command! It's useful for testing, but we're
// not documenting it right now. // not documenting it right now.
command.IsHidden = true; command.IsHidden = true;
command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, bool, string>((console, path, verbosity, interactive, @namespace) => command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, bool, string, string[]>((console, path, verbosity, interactive, @namespace, tags) =>
{ {
// Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654
if (path is null) if (path is null)
@ -36,7 +37,7 @@ namespace Microsoft.Tye
throw new CommandException("No project or solution file was found."); throw new CommandException("No project or solution file was found.");
} }
return GenerateHost.GenerateAsync(console, path, verbosity, interactive, @namespace); return GenerateHost.GenerateAsync(console, path, verbosity, interactive, @namespace, tags);
}); });
return command; return command;

7
src/tye/Program.PushCommand.cs

@ -18,6 +18,7 @@ namespace Microsoft.Tye
CommonArguments.Path_Required, CommonArguments.Path_Required,
StandardOptions.Interactive, StandardOptions.Interactive,
StandardOptions.Verbosity, StandardOptions.Verbosity,
StandardOptions.Tags
}; };
command.AddOption(new Option(new[] { "-f", "--force" }) command.AddOption(new Option(new[] { "-f", "--force" })
@ -26,7 +27,7 @@ namespace Microsoft.Tye
Required = false Required = false
}); });
command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, bool, bool>(async (console, path, verbosity, interactive, force) => command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, bool, bool, string[]>(async (console, path, verbosity, interactive, force, tags) =>
{ {
// Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654
if (path is null) if (path is null)
@ -37,7 +38,9 @@ namespace Microsoft.Tye
var output = new OutputContext(console, verbosity); var output = new OutputContext(console, verbosity);
output.WriteInfoLine("Loading Application Details..."); output.WriteInfoLine("Loading Application Details...");
var application = await ApplicationFactory.CreateAsync(output, path); var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(tags);
var application = await ApplicationFactory.CreateAsync(output, path, filter);
if (application.Services.Count == 0) if (application.Services.Count == 0)
{ {
throw new CommandException($"No services found in \"{application.Source.Name}\""); throw new CommandException($"No services found in \"{application.Source.Name}\"");

16
src/tye/Program.RunCommand.cs

@ -3,15 +3,13 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System;
using System.Collections.Generic;
using System.CommandLine; using System.CommandLine;
using System.CommandLine.Invocation; using System.CommandLine.Invocation;
using System.CommandLine.IO;
using System.IO; using System.IO;
using System.Linq;
using System.Threading; using System.Threading;
using Microsoft.Tye.ConfigModel;
using Microsoft.Tye.Extensions;
using Microsoft.Tye.Hosting; using Microsoft.Tye.Hosting;
using Microsoft.Tye.Hosting.Diagnostics;
namespace Microsoft.Tye namespace Microsoft.Tye
{ {
@ -76,8 +74,7 @@ namespace Microsoft.Tye
Description = "Watches for code changes for all dotnet projects.", Description = "Watches for code changes for all dotnet projects.",
Required = false Required = false
}, },
StandardOptions.Tags,
StandardOptions.Verbosity, StandardOptions.Verbosity,
}; };
@ -92,7 +89,10 @@ namespace Microsoft.Tye
var output = new OutputContext(args.Console, args.Verbosity); var output = new OutputContext(args.Console, args.Verbosity);
output.WriteInfoLine("Loading Application Details..."); output.WriteInfoLine("Loading Application Details...");
var application = await ApplicationFactory.CreateAsync(output, args.Path);
var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(args.Tags);
var application = await ApplicationFactory.CreateAsync(output, args.Path, filter);
if (application.Services.Count == 0) if (application.Services.Count == 0)
{ {
throw new CommandException($"No services found in \"{application.Source.Name}\""); throw new CommandException($"No services found in \"{application.Source.Name}\"");
@ -170,6 +170,8 @@ namespace Microsoft.Tye
public Verbosity Verbosity { get; set; } public Verbosity Verbosity { get; set; }
public bool Watch { get; set; } public bool Watch { get; set; }
public string[] Tags { get; set; } = Array.Empty<string>();
} }
} }
} }

5
src/tye/Program.UndeployCommand.cs

@ -22,6 +22,7 @@ namespace Microsoft.Tye
StandardOptions.Namespace, StandardOptions.Namespace,
StandardOptions.Interactive, StandardOptions.Interactive,
StandardOptions.Verbosity, StandardOptions.Verbosity,
StandardOptions.Tags,
new Option(new[]{ "--what-if", }, "print what would be deleted without making changes") new Option(new[]{ "--what-if", }, "print what would be deleted without making changes")
{ {
@ -29,7 +30,7 @@ namespace Microsoft.Tye
}, },
}; };
command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, string, bool, bool>((console, path, verbosity, @namespace, interactive, whatIf) => command.Handler = CommandHandler.Create<IConsole, FileInfo, Verbosity, string, bool, bool, string[]>((console, path, verbosity, @namespace, interactive, whatIf, tags) =>
{ {
// Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654 // Workaround for https://github.com/dotnet/command-line-api/issues/723#issuecomment-593062654
if (path is null) if (path is null)
@ -37,7 +38,7 @@ namespace Microsoft.Tye
throw new CommandException("No project or solution file was found."); throw new CommandException("No project or solution file was found.");
} }
return UndeployHost.UndeployAsync(console, path, verbosity, @namespace, interactive, whatIf); return UndeployHost.UndeployAsync(console, path, verbosity, @namespace, interactive, whatIf, tags);
}); });
return command; return command;

8
src/tye/UndeployHost.cs

@ -17,7 +17,7 @@ namespace Microsoft.Tye
{ {
public static class UndeployHost public static class UndeployHost
{ {
public static async Task UndeployAsync(IConsole console, FileInfo path, Verbosity verbosity, string @namespace, bool interactive, bool whatIf) public static async Task UndeployAsync(IConsole console, FileInfo path, Verbosity verbosity, string @namespace, bool interactive, bool whatIf, string[] tags)
{ {
var watch = System.Diagnostics.Stopwatch.StartNew(); var watch = System.Diagnostics.Stopwatch.StartNew();
@ -25,8 +25,8 @@ namespace Microsoft.Tye
output.WriteInfoLine("Loading Application Details..."); output.WriteInfoLine("Loading Application Details...");
// We don't need to know anything about the services, just the application name. var filter = ApplicationFactoryFilter.GetApplicationFactoryFilter(tags);
var application = ConfigFactory.FromFile(path); var application = await ApplicationFactory.CreateAsync(output, path, filter);
if (!string.IsNullOrEmpty(@namespace)) if (!string.IsNullOrEmpty(@namespace))
{ {
application.Namespace = @namespace; application.Namespace = @namespace;
@ -41,7 +41,7 @@ namespace Microsoft.Tye
output.WriteAlwaysLine($"Time Elapsed: {elapsedTime.Hours:00}:{elapsedTime.Minutes:00}:{elapsedTime.Seconds:00}:{elapsedTime.Milliseconds / 10:00}"); output.WriteAlwaysLine($"Time Elapsed: {elapsedTime.Hours:00}:{elapsedTime.Minutes:00}:{elapsedTime.Seconds:00}:{elapsedTime.Milliseconds / 10:00}");
} }
public static async Task ExecuteUndeployAsync(OutputContext output, ConfigApplication application, string @namespace, bool interactive, bool whatIf) public static async Task ExecuteUndeployAsync(OutputContext output, ApplicationBuilder application, string @namespace, bool interactive, bool whatIf)
{ {
var config = KubernetesClientConfiguration.BuildDefaultConfig(); var config = KubernetesClientConfiguration.BuildDefaultConfig();

16
test/Test.Infrastructure/TyeAssert.cs

@ -44,6 +44,7 @@ namespace Test.Infrastructure
Assert.NotNull(otherBinding); Assert.NotNull(otherBinding);
} }
Assert.Equal(otherIngress.Tags, ingress.Tags);
} }
foreach (var service in actual.Services) foreach (var service in actual.Services)
@ -61,20 +62,7 @@ namespace Test.Infrastructure
Assert.Equal(otherService.Project, service.Project); Assert.Equal(otherService.Project, service.Project);
Assert.Equal(otherService.Replicas, service.Replicas); Assert.Equal(otherService.Replicas, service.Replicas);
Assert.Equal(otherService.WorkingDirectory, service.WorkingDirectory); Assert.Equal(otherService.WorkingDirectory, service.WorkingDirectory);
Assert.Equal(otherService.Tags, service.Tags);
foreach (var binding in service.Bindings)
{
var otherBinding = otherService.Bindings
.Where(o => o.Name == binding.Name
&& o.Port == binding.Port
&& o.Protocol == binding.Protocol
&& o.ConnectionString == binding.ConnectionString
&& o.ContainerPort == binding.ContainerPort
&& o.Host == binding.Host)
.Single();
Assert.NotNull(otherBinding);
}
foreach (var binding in service.Bindings) foreach (var binding in service.Bindings)
{ {

97
test/UnitTests/TyeDeserializationTests.cs

@ -46,6 +46,9 @@ ingress:
- host: b.example.com - host: b.example.com
service: appB service: appB
replicas: 2 replicas: 2
tags:
- tagA
- tagC
services: services:
- name: appA - name: appA
project: ApplicationA/ApplicationA.csproj project: ApplicationA/ApplicationA.csproj
@ -53,6 +56,9 @@ services:
- name: Configuration - name: Configuration
- value: Debug - value: Debug
replicas: 2 replicas: 2
tags:
- tagA
- tagC
external: false external: false
image: abc image: abc
build: false build: false
@ -66,8 +72,8 @@ services:
value: ""test2"" value: ""test2""
volumes: volumes:
- name: volume - name: volume
source: /data source: /data
target: /data target: /data
bindings: bindings:
- name: test - name: test
port: 4444 port: 4444
@ -77,7 +83,10 @@ services:
protocol: http protocol: http
- name: appB - name: appB
project: ApplicationB/ApplicationB.csproj project: ApplicationB/ApplicationB.csproj
replicas: 2"; replicas: 2
tags:
- tagB
- tagD";
using var parser = new YamlParser(input); using var parser = new YamlParser(input);
var app = parser.ParseConfigApplication(); var app = parser.ParseConfigApplication();
@ -115,10 +124,14 @@ ingress:
[Fact] [Fact]
public void ServicesSetCorrectly() public void ServicesSetCorrectly()
{ {
var input = @"services: var input = @"
services:
- name: appA - name: appA
project: ApplicationA/ApplicationA.csproj project: ApplicationA/ApplicationA.csproj
replicas: 2 replicas: 2
tags:
- A
- B
external: false external: false
image: abc image: abc
build: false build: false
@ -132,8 +145,8 @@ ingress:
value: ""test2"" value: ""test2""
volumes: volumes:
- name: volume - name: volume
source: /data source: /data
target: /data target: /data
bindings: bindings:
- name: test - name: test
port: 4444 port: 4444
@ -143,7 +156,10 @@ ingress:
protocol: http protocol: http
- name: appB - name: appB
project: ApplicationB/ApplicationB.csproj project: ApplicationB/ApplicationB.csproj
replicas: 2"; replicas: 2
tags:
- tC
- tD";
using var parser = new YamlParser(input); using var parser = new YamlParser(input);
var actual = parser.ParseConfigApplication(); var actual = parser.ParseConfigApplication();
@ -436,6 +452,38 @@ services:
Assert.Contains(CoreStrings.FormatUnrecognizedKey("abc"), exception.Message); Assert.Contains(CoreStrings.FormatUnrecognizedKey("abc"), exception.Message);
} }
[Fact]
public void Ingress_Tags_MustBeSequence()
{
using var parser = new YamlParser(
@"ingress:
- name: ingress
tags: abc");
var exception = Assert.Throws<TyeYamlException>(() => parser.ParseConfigApplication());
Assert.Contains(CoreStrings.FormatExpectedYamlSequence("tags"), exception.Message);
}
[Fact]
public void Ingress_Tags_SetCorrectly()
{
var input = @"
ingress:
- name: ingress
tags:
- tagA
- with space
- ""C.X""
";
using var parser = new YamlParser(input);
var actual = parser.ParseConfigApplication();
var expected = _deserializer.Deserialize<ConfigApplication>(new StringReader(input));
TyeAssert.Equal(expected, actual);
}
[Fact] [Fact]
public void Services_External_MustBeBool() public void Services_External_MustBeBool()
{ {
@ -497,16 +545,47 @@ services:
Assert.Contains(CoreStrings.FormatExpectedYamlSequence("env"), exception.Message); Assert.Contains(CoreStrings.FormatExpectedYamlSequence("env"), exception.Message);
} }
[Fact]
public void Services_Tags_MustBeSequence()
{
using var parser = new YamlParser(
@"services:
- name: ingress
tags: abc");
var exception = Assert.Throws<TyeYamlException>(() => parser.ParseConfigApplication());
Assert.Contains(CoreStrings.FormatExpectedYamlSequence("tags"), exception.Message);
}
[Fact]
public void Services_Tags_SetCorrectly()
{
var input = @"
services:
- name: ingress
tags:
- tagA
- with space
- ""C.X""
";
using var parser = new YamlParser(input);
var actual = parser.ParseConfigApplication();
var expected = _deserializer.Deserialize<ConfigApplication>(new StringReader(input));
TyeAssert.Equal(expected, actual);
}
[Fact] [Fact]
public void Services_UnrecognizedKey() public void Services_UnrecognizedKey()
{ {
using var parser = new YamlParser( using var parser = new YamlParser(
@"services: @"services:
- name: ingress - name: ingress
env: abc"); xyz: abc");
var exception = Assert.Throws<TyeYamlException>(() => parser.ParseConfigApplication()); var exception = Assert.Throws<TyeYamlException>(() => parser.ParseConfigApplication());
Assert.Contains(CoreStrings.FormatExpectedYamlSequence("env"), exception.Message); Assert.Contains(CoreStrings.FormatUnrecognizedKey("xyz"), exception.Message);
} }
[Theory] [Theory]

Loading…
Cancel
Save