Skip to content

Commit

Permalink
Swap Test-Proxy to System.CommandLine, implement config subcomm…
Browse files Browse the repository at this point in the history
…ands (#6010)

* Swap Test-Proxy to utilize System.CommandLine instead of CommandLineParser for argument parsing
* Add new 'config' verb that can be used to interact in various ways with an assets.json
* Add tests for new argument parsing
  • Loading branch information
scbedd authored Apr 21, 2023
1 parent 19662d4 commit 704f39c
Show file tree
Hide file tree
Showing 23 changed files with 794 additions and 181 deletions.
260 changes: 260 additions & 0 deletions tools/test-proxy/Azure.Sdk.Tools.TestProxy.Tests/InvocationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
using System;
using System.CommandLine;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Azure.Sdk.Tools.TestProxy.CommandOptions;
using Xunit;

namespace Azure.Sdk.Tools.TestProxy.Tests
{
public class InvocationTests
{


[Theory]
[InlineData("start", "-i", "-d")]
[InlineData("start")]
[InlineData("start", "--insecure", "-d")]
[InlineData("start", "--dump")]
[InlineData("start", "--dump", "--", "--urls", "https://localhost:8002")]
public async Task TestBasicServerInvocations(params string[] input)
{
var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

Assert.True(obj is StartOptions);
Assert.Equal(0, exitCode);

if (input.Contains("-i")|| input.Contains("--insecure"))
{
Assert.True(((StartOptions)obj).Insecure);
}
else
{
Assert.False(((StartOptions)obj).Insecure);
}

if (input.Contains("--dump") || input.Contains("-d"))
{
Assert.True(((StartOptions)obj).Dump);
}
else
{
Assert.False(((StartOptions)obj).Dump);
}
}

[Fact]
public async Task TestServerInvocationsHonorUnmatched()
{
string[] input = new string[] { "start", "--dump", "--", "--urls", "https://localhost:8002" };

var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

Assert.True(obj is StartOptions);
Assert.Equal(new string[] { "--urls", "https://localhost:8002" }, ((StartOptions)obj).AdditionalArgs);
Assert.Equal(0, exitCode);
}

[Fact]
public async Task TestConfig()
{
string[] input = new string[] { "config" };

var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

Assert.True(obj is ConfigOptions);
Assert.Equal(0, exitCode);
}

[Fact]
public async Task TestConfigShow()
{
string[] input = new string[] { "config", "show", "-a", "path/to/assets.json" };

var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

Assert.True(obj is ConfigShowOptions);
Assert.Equal("path/to/assets.json", ((ConfigShowOptions)obj).AssetsJsonPath);
Assert.Equal(0, exitCode);
}

[Fact]
public async Task TestConfigCreate()
{
string[] input = new string[] { "config", "create", "-a", "path/to/assets.json" };

var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

Assert.True(obj is ConfigCreateOptions);
Assert.Equal("path/to/assets.json", ((ConfigCreateOptions)obj).AssetsJsonPath);
Assert.Equal(0, exitCode);
}

[Fact]
public async Task TestConfigLocate()
{
string[] input = new string[] { "config", "locate", "-a", "path/to/assets.json" };

var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

Assert.True(obj is ConfigLocateOptions);
Assert.Equal("path/to/assets.json", ((ConfigLocateOptions)obj).AssetsJsonPath);
Assert.Equal(0, exitCode);
}

[Theory]
[InlineData("config", "invalid-verb")]
[InlineData("totally-invalid-verb")]

public async Task TestInvalidVerbCombinations(params string[] input)
{
var output = new StringWriter();
System.Console.SetOut(output);
var obj = string.Empty;
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = "Invoked";

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

Assert.NotEqual("Invoked", obj);
Assert.Equal(1, exitCode);
}

[Theory]
[InlineData("push", "-a", "path/to/assets.json")]

public async Task TestPushOptions(params string[] input)
{
var output = new StringWriter();
System.Console.SetOut(output);
var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

Assert.True(obj is PushOptions);
Assert.Equal("path/to/assets.json", ((PushOptions)obj).AssetsJsonPath);
Assert.Equal(0, exitCode);
}

[Theory]
[InlineData("restore", "-a", "path/to/assets.json")]

public async Task TestRestoreOptions(params string[] input)
{
var output = new StringWriter();
System.Console.SetOut(output);
var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

Assert.True(obj is RestoreOptions);
Assert.Equal("path/to/assets.json", ((RestoreOptions)obj).AssetsJsonPath);
Assert.Equal(0, exitCode);
}

[Theory]
[InlineData("reset", "-a", "path/to/assets.json")]
[InlineData("reset", "-y", "-a", "path/to/assets.json")]
public async Task TestResetOptions(params string[] input)
{
var output = new StringWriter();
System.Console.SetOut(output);
var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);

if (input.Contains("--yes") || input.Contains("-y"))
{
Assert.True(((ResetOptions)obj).ConfirmReset);
}
else
{
Assert.False(((ResetOptions)obj).ConfirmReset);
}

Assert.True(obj is ResetOptions);
Assert.Equal("path/to/assets.json", ((ResetOptions)obj).AssetsJsonPath);
Assert.Equal(0, exitCode);
}


[Fact]
public async Task TestPushOptionsErrorsWithNoPath()
{
string[] input = new string[] { "push" };

var output = new StringWriter();
System.Console.SetOut(output);
var obj = new object();
var rootCommand = OptionsGenerator.GenerateCommandLineOptions((DefaultOptions) =>
{
obj = DefaultOptions;

return Task.CompletedTask;
});
var exitCode = await rootCommand.InvokeAsync(input);
Assert.Equal(1, exitCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.CommandLine;
using System.CommandLine.Binding;

namespace Azure.Sdk.Tools.TestProxy.CommandOptions
{
/// <summary>
/// CLICommandOptions contain options common to all CLI Commands (Push, Reset, Restore)
/// </summary>
public class CLICommandOptions : DefaultOptions
{
public string AssetsJsonPath { get; set; }
}

public class CLICommandOptionsBinder : BinderBase<CLICommandOptions>
{
private readonly Option<string> _storageLocationOption;
private readonly Option<string> _storagePluginOption;
private readonly Option<string> _assetsJsonPathOption;

public CLICommandOptionsBinder(Option<string> storageLocationOption, Option<string> storagePluginOption, Option<string> assetsJsonPathOption)
{
_storageLocationOption = storageLocationOption;
_storagePluginOption = storagePluginOption;
_assetsJsonPathOption = assetsJsonPathOption;
}

protected override CLICommandOptions GetBoundValue(BindingContext bindingContext) =>
new CLICommandOptions
{
StorageLocation = bindingContext.ParseResult.GetValueForOption(_storageLocationOption),
StoragePlugin = bindingContext.ParseResult.GetValueForOption(_storagePluginOption),
AssetsJsonPath = bindingContext.ParseResult.GetValueForOption(_assetsJsonPathOption)
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.CommandLine;
using System.CommandLine.Binding;

namespace Azure.Sdk.Tools.TestProxy.CommandOptions
{
/// <summary>
/// Any unique options to the push command will reside here.
/// </summary>
public class ConfigCreateOptions : CLICommandOptions
{
}

public class ConfigCreateOptionsBinder : BinderBase<ConfigCreateOptions>
{
private readonly Option<string> _storageLocationOption;
private readonly Option<string> _storagePluginOption;
private readonly Option<string> _assetsJsonPathOption;

public ConfigCreateOptionsBinder(Option<string> storageLocationOption, Option<string> storagePluginOption, Option<string> assetsJsonPathOption)
{
_storageLocationOption = storageLocationOption;
_storagePluginOption = storagePluginOption;
_assetsJsonPathOption = assetsJsonPathOption;
}

protected override ConfigCreateOptions GetBoundValue(BindingContext bindingContext) =>
new ConfigCreateOptions
{
StorageLocation = bindingContext.ParseResult.GetValueForOption(_storageLocationOption),
StoragePlugin = bindingContext.ParseResult.GetValueForOption(_storagePluginOption),
AssetsJsonPath = bindingContext.ParseResult.GetValueForOption(_assetsJsonPathOption)
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System.CommandLine;
using System.CommandLine.Binding;

namespace Azure.Sdk.Tools.TestProxy.CommandOptions
{
/// <summary>
/// Any unique options to the push command will reside here.
/// </summary>
public class ConfigLocateOptions : CLICommandOptions
{
}

public class ConfigLocateOptionsBinder : BinderBase<ConfigLocateOptions>
{
private readonly Option<string> _storageLocationOption;
private readonly Option<string> _storagePluginOption;
private readonly Option<string> _assetsJsonPathOption;

public ConfigLocateOptionsBinder(Option<string> storageLocationOption, Option<string> storagePluginOption, Option<string> assetsJsonPathOption)
{
_storageLocationOption = storageLocationOption;
_storagePluginOption = storagePluginOption;
_assetsJsonPathOption = assetsJsonPathOption;
}

protected override ConfigLocateOptions GetBoundValue(BindingContext bindingContext) =>
new ConfigLocateOptions
{
StorageLocation = bindingContext.ParseResult.GetValueForOption(_storageLocationOption),
StoragePlugin = bindingContext.ParseResult.GetValueForOption(_storagePluginOption),
AssetsJsonPath = bindingContext.ParseResult.GetValueForOption(_assetsJsonPathOption)
};
}
}
Loading

0 comments on commit 704f39c

Please sign in to comment.