diff --git a/examples/lib/loginService.sh b/examples/lib/loginService.sh
new file mode 100644
index 000000000000..86fd58f2aaec
--- /dev/null
+++ b/examples/lib/loginService.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+azure account add --spn --appid "$spn" --secret "$secret" -t "$tenant" -s "$subscription"
\ No newline at end of file
diff --git a/examples/lib/loginUser.sh b/examples/lib/loginUser.sh
new file mode 100644
index 000000000000..fd442b568070
--- /dev/null
+++ b/examples/lib/loginUser.sh
@@ -0,0 +1,2 @@
+#!/bin/bash
+azure account add -u "$azureUser" -p "$password" -s "$subscription"
\ No newline at end of file
diff --git a/examples/resource-management/01-ResourceGroups.sh b/examples/resource-management/01-ResourceGroups.sh
index f03dc815d7ec..8673f807ea0b 100644
--- a/examples/resource-management/01-ResourceGroups.sh
+++ b/examples/resource-management/01-ResourceGroups.sh
@@ -3,13 +3,13 @@ set -e
printf "\n=== Managing Resource Groups in Azure ===\n"
printf "\n1. Creating a new resource group: %s and location: %s.\n" "$groupName" "$location"
-azure group create --name "$groupName" --location "$location"
+azure group create -n "$groupName" --location "$location"
printf "\n2. Updating the group %s with tags.\n" "$groupName"
-azure group set --name "$groupName" --tags "[{\"Value\":\"testval\",\"Name\":\"testtag\"}]"
+azure group set -n "$groupName" --tags "[{\"Value\":\"testval\",\"Name\":\"testtag\"}]"
printf "\n3. Get information about resource group : %s.\n" "$groupName"
-resourceGroupInfo=`azure group get --name $groupName`
+resourceGroupInfo=`azure group get -n $groupName`
printf "\nValidating resource group name is: %s\n" "$groupName"
[ $(echo $resourceGroupInfo | jq '.ResourceGroupName' --raw-output) == "$groupName" ]
@@ -18,4 +18,4 @@ printf "\n4. Listing all resource groups in the subscription.\n"
azure group get
printf "\n5. Removing resource group: %s.\n" "$groupName"
-azure group remove --name "$groupName" --force
\ No newline at end of file
+azure group remove -n "$groupName" -f
\ No newline at end of file
diff --git a/src/CLU/CLUCoreCLR.sln b/src/CLU/CLUCoreCLR.sln
index bf8dbefe8ea0..9d3937fc16f3 100644
--- a/src/CLU/CLUCoreCLR.sln
+++ b/src/CLU/CLUCoreCLR.sln
@@ -39,13 +39,7 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.CLU", "Microsoft.
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.CLU.Test", "Microsoft.CLU.Test\Microsoft.CLU.Test.xproj", "{91422B55-28A5-48DE-BCA0-30C3E30FFB1C}"
EndProject
-Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Azure.Commands.Compute", "Microsoft.Azure.Commands.Compute\Microsoft.Azure.Commands.Compute.xproj", "{04F9968A-5662-4508-BEE2-31F56848FCBA}"
- ProjectSection(ProjectDependencies) = postProject
- {99B1290D-A073-4907-8018-51C714431778} = {99B1290D-A073-4907-8018-51C714431778}
- {3910613E-4ED2-49E2-8CCF-966D586665AC} = {3910613E-4ED2-49E2-8CCF-966D586665AC}
- {81A48E48-89A7-4B93-8207-4F8FA6DC251B} = {81A48E48-89A7-4B93-8207-4F8FA6DC251B}
- {45B05B68-516F-4D74-897F-56D12894946C} = {45B05B68-516F-4D74-897F-56D12894946C}
- EndProjectSection
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Commands.Common.ScenarioTest", "Commands.Common.ScenarioTest\Commands.Common.ScenarioTest.xproj", "{B1D3CB1F-C0CA-401F-8146-B2E9C1EF460F}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Azure.Commands.Compute.Test", "Microsoft.Azure.Commands.Compute.Test\Microsoft.Azure.Commands.Compute.Test.xproj", "{13C34370-51A4-4726-81B8-BE0996FC9CFF}"
ProjectSection(ProjectDependencies) = postProject
@@ -55,6 +49,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Azure.Commands.Co
{04F9968A-5662-4508-BEE2-31F56848FCBA} = {04F9968A-5662-4508-BEE2-31F56848FCBA}
EndProjectSection
EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Azure.Commands.Compute", "Microsoft.Azure.Commands.Compute\Microsoft.Azure.Commands.Compute.xproj", "{04F9968A-5662-4508-BEE2-31F56848FCBA}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -133,14 +129,18 @@ Global
{91422B55-28A5-48DE-BCA0-30C3E30FFB1C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91422B55-28A5-48DE-BCA0-30C3E30FFB1C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91422B55-28A5-48DE-BCA0-30C3E30FFB1C}.Release|Any CPU.Build.0 = Release|Any CPU
- {04F9968A-5662-4508-BEE2-31F56848FCBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {04F9968A-5662-4508-BEE2-31F56848FCBA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {04F9968A-5662-4508-BEE2-31F56848FCBA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {04F9968A-5662-4508-BEE2-31F56848FCBA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B1D3CB1F-C0CA-401F-8146-B2E9C1EF460F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B1D3CB1F-C0CA-401F-8146-B2E9C1EF460F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B1D3CB1F-C0CA-401F-8146-B2E9C1EF460F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B1D3CB1F-C0CA-401F-8146-B2E9C1EF460F}.Release|Any CPU.Build.0 = Release|Any CPU
{13C34370-51A4-4726-81B8-BE0996FC9CFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{13C34370-51A4-4726-81B8-BE0996FC9CFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{13C34370-51A4-4726-81B8-BE0996FC9CFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{13C34370-51A4-4726-81B8-BE0996FC9CFF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {04F9968A-5662-4508-BEE2-31F56848FCBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {04F9968A-5662-4508-BEE2-31F56848FCBA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {04F9968A-5662-4508-BEE2-31F56848FCBA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {04F9968A-5662-4508-BEE2-31F56848FCBA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/CLU/Commands.Common.ScenarioTest/Commands.Common.ScenarioTest.xproj b/src/CLU/Commands.Common.ScenarioTest/Commands.Common.ScenarioTest.xproj
new file mode 100644
index 000000000000..41dbb6db1989
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/Commands.Common.ScenarioTest.xproj
@@ -0,0 +1,21 @@
+
+
+
+ 14.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+
+
+
+ b1d3cb1f-c0ca-401f-8146-b2e9c1ef460f
+ Microsoft.Azure.Commands.Common.ScenarioTest
+ ..\artifacts\obj\$(MSBuildProjectName)
+ ..\artifacts\bin\$(MSBuildProjectName)\
+
+
+ 2.0
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/CLU/Commands.Common.ScenarioTest/EnvironmentConstants.cs b/src/CLU/Commands.Common.ScenarioTest/EnvironmentConstants.cs
new file mode 100644
index 000000000000..7c49f5092c00
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/EnvironmentConstants.cs
@@ -0,0 +1,32 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public static class EnvironmentConstants
+ {
+ public const string UsernameKey = "Username";
+ public const string PasswordKey = "Password";
+ public const string ServicePrincipalKey = "ServicePrincipal";
+ public const string TenantKey = "TenantId";
+ public const string SubscriptionKey = "SubscriptionId";
+ public const string TestRunDirectory = "TestRunDirectory";
+ public const string ExampleDirectory = "ExamplesDirectory";
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/EnvironmentContextFactory.cs b/src/CLU/Commands.Common.ScenarioTest/EnvironmentContextFactory.cs
new file mode 100644
index 000000000000..fc907f9ebb04
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/EnvironmentContextFactory.cs
@@ -0,0 +1,67 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System.Collections.Generic;
+using System.IO;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public class EnvironmentContextFactory
+ {
+ ICredentialsProvider _credentials;
+
+
+ public EnvironmentContextFactory(ICredentialsProvider credentials)
+ {
+ _credentials = credentials;
+ }
+
+ public TestContext GetTestContext(string scriptDirectoryName)
+ {
+ var context = new TestContext();
+ context.ExecutionDirectory = GetBaseDirectory();
+ context.TestScriptDirectory =GetExamplesDirectory(context.ExecutionDirectory, scriptDirectoryName);
+ context.TestExecutableName = "bash.exe";
+ context.TestScriptSuffix = ".sh";
+ var helpers = new List();
+ helpers.Add(_credentials.EnvironmentProvider);
+ context.EnvironmentHelpers = helpers;
+ return context;
+ }
+
+ private string GetExamplesDirectory(string executionDirectory, string scriptDirectoryName)
+ {
+ string examplesDirectory;
+ if (!Utilities.TryGetEnvironmentVariable(EnvironmentConstants.ExampleDirectory, out examplesDirectory))
+ {
+ examplesDirectory = Path.GetFullPath(Path.Combine(executionDirectory, "..",
+ "..", "..", "examples"));
+ }
+
+ return Path.Combine(examplesDirectory, scriptDirectoryName);
+ }
+ private string GetBaseDirectory()
+ {
+ string baseDirectory;
+ if (!Utilities.TryGetEnvironmentVariable(EnvironmentConstants.TestRunDirectory, out baseDirectory))
+ {
+ baseDirectory = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "..", "TestResults"));
+ }
+
+ Utilities.EnsureDirectoryExists(baseDirectory);
+ return baseDirectory;
+ }
+
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/EnvironmentCredentialsProvider.cs b/src/CLU/Commands.Common.ScenarioTest/EnvironmentCredentialsProvider.cs
new file mode 100644
index 000000000000..66b685bbe1db
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/EnvironmentCredentialsProvider.cs
@@ -0,0 +1,99 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Azure.Commands.Common.ScenarioTest;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public class EnvironmentCredentialsProvider : ICredentialsProvider
+ {
+ public const string userScript = "loginUser";
+ public const string serviceScript = "loginService";
+
+ public IScriptEnvironmentHelper EnvironmentProvider { get; protected set; }
+
+ public string LoginScriptName { get; protected set; }
+
+ public virtual void Initialize(string key)
+ {
+ IDictionary settings = GetSettings(key);
+ if (!TryInitializeServiceCredentials(settings) && !TryInitializeUserCredentials(settings))
+ {
+ throw new InvalidOperationException($"Unable to create credentials using key {key}. " +
+ "Please ensure your environment is correctly set up.");
+ }
+ }
+
+ protected virtual IDictionary GetSettings(string key)
+ {
+ var environmentValue = Environment.GetEnvironmentVariable(key);
+ if (string.IsNullOrWhiteSpace(environmentValue))
+ {
+ throw new InvalidOperationException($"Unable to create credentials. " +
+ "Please set environment ${key}");
+ }
+ IDictionary settings = new Dictionary();
+ foreach (
+ var setting in
+ environmentValue.Split(new string[] {$"{Path.PathSeparator}"},
+ StringSplitOptions.RemoveEmptyEntries)
+ )
+ {
+ string[] pair = setting.Split(new char[] { '='}, 2, StringSplitOptions.RemoveEmptyEntries);
+ var pairKey = pair[0].Trim();
+ var pairValue = pair[1].Trim();
+ settings[pairKey] = pairValue;
+ }
+
+ return settings;
+ }
+
+ protected virtual bool TryInitializeServiceCredentials(IDictionary settings )
+ {
+ if (settings.ContainsKey(EnvironmentConstants.ServicePrincipalKey) &&
+ settings.ContainsKey(EnvironmentConstants.PasswordKey) &&
+ settings.ContainsKey(EnvironmentConstants.TenantKey))
+ {
+ LoginScriptName = serviceScript;
+ EnvironmentProvider = new ServiceAuthenticationHelper(
+ settings[EnvironmentConstants.ServicePrincipalKey],
+ settings[EnvironmentConstants.PasswordKey],
+ settings[EnvironmentConstants.TenantKey],
+ settings.ContainsKey(EnvironmentConstants.SubscriptionKey) ? settings[EnvironmentConstants.SubscriptionKey] : null);
+ return true;
+ }
+ return false;
+ }
+
+ protected virtual bool TryInitializeUserCredentials(IDictionary settings )
+ {
+ if (settings.ContainsKey(EnvironmentConstants.UsernameKey) &&
+ settings.ContainsKey(EnvironmentConstants.PasswordKey))
+ {
+ LoginScriptName = userScript;
+ EnvironmentProvider = new UserAuthenticationHelper(
+ settings[EnvironmentConstants.UsernameKey],
+ settings[EnvironmentConstants.PasswordKey],
+ settings.ContainsKey(EnvironmentConstants.SubscriptionKey) ? settings[EnvironmentConstants.SubscriptionKey] : null);
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/ExampleScriptRunner.cs b/src/CLU/Commands.Common.ScenarioTest/ExampleScriptRunner.cs
new file mode 100644
index 000000000000..8d00e87e7d60
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/ExampleScriptRunner.cs
@@ -0,0 +1,183 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using Microsoft.Azure.Commands.Common.Authentication;
+using Microsoft.Azure.Commands.Common.Authentication.Factories;
+using Microsoft.Azure.Commands.Common.Authentication.Models;
+using Microsoft.Azure.Commands.Common.ScenarioTest;
+using Microsoft.Azure.Management.Resources;
+using Microsoft.Azure.Management.Resources.Models;
+using Microsoft.Rest;
+using Newtonsoft.Json.Linq;
+using Xunit;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public class ExampleScriptRunner
+ {
+ string _sessionId;
+ Random _generator;
+ string _resourceGroupName;
+ IClientFactory _clientFactory = new ClientFactory();
+ TestContext _context;
+ ResourceManagementClient _client;
+ const string DefaultLocation = "westus";
+ const string ResourceGroupNameKey = "groupName";
+ const string locationKey = "location";
+ const string SessionKey = "CmdletSessionID";
+
+ public ExampleScriptRunner(string sessionId) : this(new Random(), sessionId)
+ {
+ }
+
+ public ExampleScriptRunner(int seed, string sessionId) : this(new Random(seed), sessionId)
+ {
+ }
+
+
+ public ExampleScriptRunner(Random generator, string sessionId)
+ {
+ _generator = generator;
+ _sessionId = sessionId;
+ }
+
+ public IClientFactory ClientFactory
+ {
+ get { return _clientFactory; }
+ set { _clientFactory = value; }
+ }
+
+ public TestContext TestContext
+ {
+ get { return _context; }
+ set { _context = value; }
+ }
+
+ public string ScriptOutput { get; protected set; }
+
+ public string RunScript(string testName)
+ {
+ var testDirectory = Path.GetFullPath(_context.TestScriptDirectory);
+ var executionDirectory = Path.GetFullPath(_context.ExecutionDirectory);
+ string testFile = $"{testName}{_context.TestScriptSuffix}";
+ string logFile = $"{testName}.log";
+ string logFilePath = Path.Combine(executionDirectory, logFile);
+ string testPath = Path.Combine(testDirectory, testFile);
+ if (!File.Exists(testPath))
+ {
+ throw new InvalidOperationException($"Path to test script '{testPath}' does not exist.");
+ }
+
+ string deploymentTemplatePath = Path.Combine(testDirectory, $"{testName}.json");
+ TraceListener listener = null;
+ try
+ {
+ using (var stream = new FileStream(logFilePath, FileMode.Create))
+ using (listener = new TextWriterTraceListener(stream))
+ using (var process = new ProcessHelper(executionDirectory, _context.TestExecutableName, testPath))
+ {
+ Trace.Listeners.Add(listener);
+ _resourceGroupName = CreateRandomName();
+ if (File.Exists(deploymentTemplatePath))
+ {
+ DeployTemplate(deploymentTemplatePath, _resourceGroupName);
+ }
+
+ process.EnvironmentVariables[SessionKey] = _sessionId;
+ process.EnvironmentVariables[ResourceGroupNameKey] = _resourceGroupName;
+ process.EnvironmentVariables[locationKey] = DefaultLocation;
+ foreach (var helper in _context.EnvironmentHelpers)
+ {
+ helper.TrySetupScriptEnvironment(_context, _clientFactory, process.EnvironmentVariables);
+ }
+ int statusCode = process.StartAndWaitForExit();
+ Assert.Equal(0, statusCode);
+ return process.Output;
+ }
+ }
+ finally
+ {
+ if (listener != null)
+ {
+ Trace.Listeners.Remove(listener);
+ }
+ Cleanup();
+ }
+ }
+
+ public void DeployTemplate(string deploymentTemplatePath, string resourceGroupName)
+ {
+ EnsureClient();
+ var location = GetLocation();
+ CreateResourceGroup(resourceGroupName, location);
+ var template = JObject.Parse(File.ReadAllText(deploymentTemplatePath));
+ var deployment = _client.Deployments.CreateOrUpdateWithHttpMessagesAsync(resourceGroupName, "testDeployment",
+ new Deployment(new DeploymentProperties(template: template, mode: DeploymentMode.Complete))).GetAwaiter().GetResult();
+ if (!deployment.Response.IsSuccessStatusCode)
+ {
+ throw new InvalidOperationException($"Deployment failed with response: {deployment.Response.AsFormattedString()}");
+ }
+ }
+
+ public string CreateRandomName()
+ {
+ return "clutst" + _generator.Next(10000, 99999);
+ }
+
+ private void EnsureClient()
+ {
+ if (this._client == null)
+ {
+ var context = _context.Context;
+ var _client = _clientFactory.CreateArmClient(context,
+ AzureEnvironment.Endpoint.ResourceManager);
+ }
+ }
+
+
+ private string GetLocation()
+ {
+ return DefaultLocation;
+ }
+
+ private void CreateResourceGroup(string resourceGroupName, string location)
+ {
+ var response =
+ _client.ResourceGroups.CreateOrUpdateWithHttpMessagesAsync(resourceGroupName,
+ new ResourceGroup(location: location)).GetAwaiter().GetResult();
+ _resourceGroupName = resourceGroupName;
+ }
+
+ public void Cleanup()
+ {
+ if (_client != null && !string.IsNullOrWhiteSpace(_resourceGroupName))
+ {
+ try
+ {
+ _client.ResourceGroups.DeleteWithHttpMessagesAsync(_resourceGroupName).GetAwaiter().GetResult();
+ }
+ catch (Exception exception)
+ {
+ Logger.Instance.WriteError($"Could not remove resource group: {exception}");
+ }
+ }
+ _client = null;
+ _resourceGroupName = null;
+ }
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/ICredentialsProvider.cs b/src/CLU/Commands.Common.ScenarioTest/ICredentialsProvider.cs
new file mode 100644
index 000000000000..e0aa8a56740e
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/ICredentialsProvider.cs
@@ -0,0 +1,25 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Microsoft.Azure.Commands.Common.ScenarioTest;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public interface ICredentialsProvider
+ {
+ void Initialize(string key);
+ string LoginScriptName { get; }
+ IScriptEnvironmentHelper EnvironmentProvider { get; }
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/IScriptEnvironmentHelper.cs b/src/CLU/Commands.Common.ScenarioTest/IScriptEnvironmentHelper.cs
new file mode 100644
index 000000000000..3119dacfd4b7
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/IScriptEnvironmentHelper.cs
@@ -0,0 +1,24 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System.Collections.Generic;
+using Microsoft.Azure.Commands.Common.Authentication;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public interface IScriptEnvironmentHelper
+ {
+ bool TrySetupScriptEnvironment(TestContext testContext, IClientFactory clientFactory, IDictionary settings );
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/ITestLogger.cs b/src/CLU/Commands.Common.ScenarioTest/ITestLogger.cs
new file mode 100644
index 000000000000..8ce079c7063f
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/ITestLogger.cs
@@ -0,0 +1,24 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Xunit.Abstractions;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public interface ITestLogger
+ {
+ void WriteMessage(string message);
+ void WriteError(string message);
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/Logger.cs b/src/CLU/Commands.Common.ScenarioTest/Logger.cs
new file mode 100644
index 000000000000..5667793c8475
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/Logger.cs
@@ -0,0 +1,42 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System.Diagnostics;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public class Logger : ITestLogger
+ {
+ static Logger()
+ {
+ Logger.Instance = new Logger();
+ }
+ public static ITestLogger Instance { get; private set; }
+
+ private Logger()
+ {
+ }
+
+
+ public void WriteMessage(string message)
+ {
+ Trace.WriteLine(message);
+ }
+
+ public void WriteError(string message)
+ {
+ Trace.WriteLine($"Error: {message}");
+ }
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/ProcessHelper.cs b/src/CLU/Commands.Common.ScenarioTest/ProcessHelper.cs
new file mode 100644
index 000000000000..a45e88ab2b81
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/ProcessHelper.cs
@@ -0,0 +1,193 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Threading;
+using Microsoft.Azure.Commands.Common.ScenarioTest;
+using Xunit;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public class ProcessHelper : IDisposable
+ {
+ ///
+ /// The process running the service.
+ ///
+
+ string _executableName = "bash.exe";
+
+ StringBuilder _processOutput = new StringBuilder();
+
+ string _arguments;
+ string _directory;
+ Dictionary _environment = new Dictionary();
+ Process _process;
+
+ public IDictionary EnvironmentVariables
+ {
+ get { return _environment; }
+ }
+
+ public string ExecutableName
+ {
+ get { return _executableName; }
+ set { _executableName = value; }
+ }
+
+ public string Output { get { return _processOutput.ToString(); }}
+
+ public ProcessHelper(string directory, string executableName, params string[] arguments)
+ {
+ _executableName = executableName;
+ _directory = directory;
+ if (arguments != null && arguments.Length > 0)
+ {
+ _arguments = string.Join(" ", arguments);
+ }
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing && _process != null )
+ {
+ try
+ {
+ EndProcess();
+ }
+ catch
+ {
+ }
+
+ _process = null;
+ }
+ }
+
+
+ public static string GetPathToExecutable(string executableName)
+ {
+ var paths = Environment.GetEnvironmentVariable("PATH");
+ foreach (var path in paths.Split(new[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ var fullPath = Path.Combine(path, Path.GetFileName(executableName));
+ if (File.Exists(fullPath))
+ {
+ return fullPath;
+ }
+
+ var exec = Path.GetFileNameWithoutExtension(executableName);
+ var fullPathNoExe = Path.Combine(path, exec);
+ if (File.Exists(fullPath))
+ {
+ return fullPath;
+ }
+
+ if (File.Exists(fullPathNoExe))
+ {
+ return fullPathNoExe;
+ }
+ }
+
+ return null;
+ }
+
+ public int StartAndWaitForExit()
+ {
+ return StartAndWaitForExit(TimeSpan.FromMinutes(60));
+ }
+
+ public int StartAndWaitForExit(TimeSpan timeout)
+ {
+ var shellPath = GetPathToExecutable(_executableName);
+ if (shellPath == null)
+ {
+ throw new InvalidOperationException($"Could not find path to '{_executableName}'");
+ }
+
+ _process = StartProcess(shellPath, _arguments, _directory);
+ if (_process.WaitForExit((int) timeout.TotalMilliseconds))
+ {
+ return _process.ExitCode;
+ }
+
+ throw new TimeoutException($"Process using executable with path '{shellPath}' timed out");
+ }
+
+ ///
+ /// Run the given command with arguments. Return the result in standard output.
+ ///
+ /// The path to the command to execute.
+ /// The arguments to pass to the command.
+ /// The working directory for the process being launched.
+ /// The process
+ private Process StartProcess(
+ string path,
+ string arguments,
+ string workingDirectory)
+ {
+ var process = new Process();
+ var startInfo = process.StartInfo;
+ startInfo.CreateNoWindow = false;
+ startInfo.RedirectStandardOutput = true;
+ startInfo.RedirectStandardError = true;
+ startInfo.WorkingDirectory = workingDirectory;
+ startInfo.UseShellExecute = false;
+ startInfo.FileName = path;
+ startInfo.Arguments = arguments;
+ SetEnvironmentVariables(startInfo);
+ process.OutputDataReceived += ProcessOutput;
+ process.ErrorDataReceived += ProcessError;
+ process.Start();
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+ return process;
+ }
+
+ private void SetEnvironmentVariables(ProcessStartInfo startInfo)
+ {
+ foreach (var key in _environment.Keys)
+ {
+ startInfo.Environment[key] = _environment[key];
+ }
+ }
+
+ private void ProcessError(object sender, DataReceivedEventArgs e)
+ {
+ Logger.Instance.WriteError(e.Data);
+ }
+
+ private void ProcessOutput(object sender, DataReceivedEventArgs e)
+ {
+ Logger.Instance.WriteMessage(e.Data);
+ _processOutput.Append(e.Data);
+ }
+
+ private void EndProcess()
+ {
+ _process.CancelOutputRead();
+ _process.CancelErrorRead();
+ _process.WaitForExit(2000);
+ _process.Dispose();
+ }
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/SampleTest.cs b/src/CLU/Commands.Common.ScenarioTest/SampleTest.cs
new file mode 100644
index 000000000000..48e62f213bea
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/SampleTest.cs
@@ -0,0 +1,42 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Azure.Commands.Common.ScenarioTest;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ [Collection("SampleCollection")]
+ public class SampleTest
+ {
+ ScenarioTestFixture _collectionState;
+ public SampleTest(ScenarioTestFixture fixture)
+ {
+ _collectionState = fixture;
+ }
+ [Fact]
+ public void RunSampleTest()
+ {
+ var helper = _collectionState.GetRunner("resource-management");
+ helper.RunScript("01-ResourceGroups");
+ }
+
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/SampleTestCollection.cs b/src/CLU/Commands.Common.ScenarioTest/SampleTestCollection.cs
new file mode 100644
index 000000000000..f01b122ef604
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/SampleTestCollection.cs
@@ -0,0 +1,23 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using Xunit;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ [CollectionDefinition("SampleCollection")]
+ public class SampleTestCollection : ICollectionFixture
+ {
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/ScenarioTestFixture.cs b/src/CLU/Commands.Common.ScenarioTest/ScenarioTestFixture.cs
new file mode 100644
index 000000000000..ba487dd7a344
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/ScenarioTestFixture.cs
@@ -0,0 +1,55 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using Microsoft.Azure.Commands.Common.Authentication.Models;
+using Microsoft.Azure.Commands.Common.ScenarioTest;
+using Microsoft.Azure.Commands.Models;
+using Moq.Protected;
+using Newtonsoft.Json;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public class ScenarioTestFixture
+ {
+ protected EnvironmentContextFactory _contextFactory;
+ public ScenarioTestFixture()
+ {
+ Generator = new Random();
+ SessionId = $"{Generator.Next(10000, 99999)}";
+ var credentials = new EnvironmentCredentialsProvider();
+ credentials.Initialize("TestCredentials");
+ _contextFactory = new EnvironmentContextFactory(credentials);
+ var helper = GetRunner("lib");
+ var profileText = helper.RunScript(credentials.LoginScriptName);
+ var profile = JsonConvert.DeserializeObject(profileText);
+ AzureContext = (AzureContext) (profile.Context);
+ }
+
+ public string SessionId { get; protected set; }
+ public Random Generator { get; protected set; }
+
+ public ExampleScriptRunner GetRunner(string directoryName)
+ {
+ var context = _contextFactory.GetTestContext(directoryName);
+ context.Context = AzureContext;
+ return new ExampleScriptRunner(Generator, SessionId)
+ {
+ TestContext = context
+ };
+ }
+
+ public AzureContext AzureContext { get; protected set;}
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/ServiceAuthenticationHelper.cs b/src/CLU/Commands.Common.ScenarioTest/ServiceAuthenticationHelper.cs
new file mode 100644
index 000000000000..a145ae54225f
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/ServiceAuthenticationHelper.cs
@@ -0,0 +1,63 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System.Collections.Generic;
+using Microsoft.Azure.Commands.Common.Authentication;
+using Microsoft.Azure.Commands.Common.ScenarioTest;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ ///
+ /// Add the given SPN credentials to the environment for the login script
+ ///
+ public class ServiceAuthenticationHelper : IScriptEnvironmentHelper
+ {
+ string _spn;
+ string _secret;
+ string _tenant;
+ string _subscription;
+ const string SecretKey = "secret";
+ const string SPNKey = "spn";
+ const string TenantKey = "tenant";
+ const string SubscriptionKey = "subscription";
+ public ServiceAuthenticationHelper(string spn, string secret, string tenant)
+ : this(spn, secret, tenant, null)
+ {
+ }
+
+ public ServiceAuthenticationHelper(string spn, string secret, string tenant, string subscription)
+ {
+ _spn = spn;
+ _secret = secret;
+ _tenant = tenant;
+ _subscription = subscription;
+ }
+
+ public bool TrySetupScriptEnvironment(TestContext testContext, IClientFactory clientFactory, IDictionary settings)
+ {
+ Logger.Instance.WriteMessage($"Logging in using ServicePrincipal: {_spn}");
+ settings[SPNKey] = _spn;
+ settings[SecretKey] = _secret;
+ Logger.Instance.WriteMessage($"Logging in using Tenant: {_tenant}");
+ settings[TenantKey] = _tenant;
+ if (!string.IsNullOrWhiteSpace(_subscription))
+ {
+ Logger.Instance.WriteMessage($"Logging in using Subscription: {_subscription}");
+ settings[SubscriptionKey] = _subscription;
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/TestContext.cs b/src/CLU/Commands.Common.ScenarioTest/TestContext.cs
new file mode 100644
index 000000000000..3e66f7a414c8
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/TestContext.cs
@@ -0,0 +1,29 @@
+using System.Collections.Generic;
+using Microsoft.Azure.Commands.Common.Authentication.Models;
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public struct TestContext
+ {
+ public AzureContext Context { get; set; }
+ public string TestExecutableName { get; set; }
+ public string TestScriptSuffix { get; set; }
+ public string TestScriptDirectory { get; set; }
+ public string ExecutionDirectory { get; set; }
+ public IEnumerable EnvironmentHelpers { get; set; }
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/UserAuthenticationHelper.cs b/src/CLU/Commands.Common.ScenarioTest/UserAuthenticationHelper.cs
new file mode 100644
index 000000000000..a95736e802f6
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/UserAuthenticationHelper.cs
@@ -0,0 +1,69 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using Microsoft.Azure.Commands.Common.Authentication;
+using Microsoft.Azure.Commands.Common.ScenarioTest;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public class UserAuthenticationHelper : IScriptEnvironmentHelper
+ {
+ public const string UsernameVariable = "azureUser";
+ public const string PasswordVariable = "password";
+ public const string SubscriptionVariable = "subscription";
+ string _username;
+ string _password;
+ string _subscription;
+
+ public UserAuthenticationHelper(string username, string password)
+ : this(username, password, null)
+ {
+ }
+
+ public UserAuthenticationHelper(string username, string password, string subscription)
+ {
+ _username = username;
+ _password = password;
+ _subscription = subscription;
+ }
+
+ public bool TrySetupScriptEnvironment(TestContext testContext, IClientFactory clientFactory, IDictionary settings)
+ {
+ if (string.IsNullOrWhiteSpace(_username) || string.IsNullOrWhiteSpace(_password))
+ {
+ throw new ArgumentOutOfRangeException("textContext",
+ "Username and Password must be provided for user accounts");
+ }
+
+ if (settings == null)
+ {
+ throw new ArgumentNullException("settings");
+ }
+
+ settings[UsernameVariable] = _username;
+ Logger.Instance.WriteMessage($"Setting process environment {UsernameVariable} = {_username}");
+ settings[PasswordVariable] = _password;
+ Logger.Instance.WriteMessage($"Setting process environment {PasswordVariable} = ***********");
+ if (!string.IsNullOrWhiteSpace(_subscription))
+ {
+ Logger.Instance.WriteMessage($"Logging in using Subscription: {_subscription}");
+ settings[SubscriptionVariable] = _subscription;
+ }
+ return true;
+
+ }
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/Utilities.cs b/src/CLU/Commands.Common.ScenarioTest/Utilities.cs
new file mode 100644
index 000000000000..6f33e93f9980
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/Utilities.cs
@@ -0,0 +1,36 @@
+// ----------------------------------------------------------------------------------
+//
+// Copyright Microsoft Corporation
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ----------------------------------------------------------------------------------
+
+using System;
+using System.IO;
+
+namespace Microsoft.Azure.Commands.Common.ScenarioTest
+{
+ public static class Utilities
+ {
+ public static bool TryGetEnvironmentVariable(string variableName, out string variableValue)
+ {
+ variableValue = Environment.GetEnvironmentVariable(variableName);
+ return !string.IsNullOrWhiteSpace(variableValue);
+ }
+
+ public static void EnsureDirectoryExists(string directoryPath)
+ {
+ if (!Directory.Exists(directoryPath))
+ {
+ Directory.CreateDirectory(directoryPath);
+ }
+ }
+ }
+}
diff --git a/src/CLU/Commands.Common.ScenarioTest/project.json b/src/CLU/Commands.Common.ScenarioTest/project.json
new file mode 100644
index 000000000000..0b83615e7c8c
--- /dev/null
+++ b/src/CLU/Commands.Common.ScenarioTest/project.json
@@ -0,0 +1,64 @@
+{
+ "version": "1.0.0-*",
+ "description": "Tests for Authentication Management Cmdlets",
+ "authors": [ "markcowl" ],
+ "tags": [ "" ],
+ "projectUrl": "",
+ "licenseUrl": "",
+ "frameworks": {
+ "dnxcore50": {
+ "dependencies": {
+ "Microsoft.NETCore": "5.0.1-beta-23516",
+ "Microsoft.NETCore.Platforms": "1.0.1-beta-23516",
+ "Microsoft.CSharp": "4.0.1-beta-23516"
+ }
+ }
+ },
+ "dependencies": {
+ "System.Linq": "4.0.1-beta-23516",
+ "Microsoft.CLU": "1.0.0",
+ "Commands.Common": "",
+ "Commands.Common.Authentication": "",
+ "Commands.ResourceManager.Common": "",
+ "Commands.ScenarioTests.ResourceManager.Common": "",
+ "Microsoft.Azure.Commands.Profile": "",
+ "Microsoft.Azure.Management.Resources": "3.3.0-preview",
+ "Microsoft.IdentityModel.Clients.ActiveDirectory": "3.6.212041202-alpha",
+ "Microsoft.Rest.ClientRuntime": "1.8.0",
+ "Microsoft.Rest.ClientRuntime.Azure": "2.5.1",
+ "Microsoft.Rest.ClientRuntime.Azure.Authentication": "1.2.1-preview",
+ "Newtonsoft.Json": "7.0.1",
+ "System.Collections": "4.0.11-beta-23516",
+ "System.Collections.Concurrent": "4.0.11-beta-23516",
+ "System.Diagnostics.Tools": "4.0.1-beta-23516",
+ "System.Diagnostics.TraceSource": "4.0.0-beta-23516",
+ "System.Diagnostics.Tracing": "4.0.21-beta-23516",
+ "System.IO": "4.0.11-beta-23516",
+ "System.IO.FileSystem": "4.0.1-beta-23516",
+ "System.Net.Http": "4.0.1-beta-23516",
+ "System.Net.WebHeaderCollection": "4.0.1-beta-23516",
+ "System.Reflection": "4.1.0-beta-23516",
+ "System.Reflection.Extensions": "4.0.1-beta-23516",
+ "System.Reflection.Primitives": "4.0.1-beta-23516",
+ "System.Reflection.TypeExtensions": "4.1.0-beta-23516",
+ "System.Runtime": "4.0.21-beta-23516",
+ "System.Runtime.Extensions": "4.0.11-beta-23516",
+ "System.Runtime.Serialization.Json": "4.0.1-beta-23516",
+ "System.Runtime.Serialization.Primitives": "4.1.0-beta-23516",
+ "System.Runtime.Serialization.Xml": "4.1.0-beta-23516",
+ "System.Security.Cryptography.Algorithms": "4.0.0-beta-23516",
+ "System.Security.Cryptography.X509Certificates": "4.0.0-beta-23516",
+ "System.Text.Encoding": "4.0.11-beta-23516",
+ "System.Text.Encoding.Extensions": "4.0.11-beta-23516",
+ "System.Threading": "4.0.11-beta-23516",
+ "System.Threading.Tasks": "4.0.11-beta-23516",
+ "System.Threading.Thread": "4.0.0-beta-23516",
+ "System.Xml.ReaderWriter": "4.0.11-beta-23516",
+ "xunit": "2.1.0",
+ "xunit.assert": "2.1.0",
+ "xunit.runner.dnx": "2.1.0-rc1-build204"
+ },
+ "commands": {
+ "test": "xunit.runner.dnx"
+ }
+}
diff --git a/src/CLU/Commands.Common/Models/PSAzureProfile.cs b/src/CLU/Commands.Common/Models/PSAzureProfile.cs
index 285dd052dfda..11a4cdf4b47c 100644
--- a/src/CLU/Commands.Common/Models/PSAzureProfile.cs
+++ b/src/CLU/Commands.Common/Models/PSAzureProfile.cs
@@ -66,7 +66,7 @@ public IDictionary Environments
public string EnvironmentNames
{
- get { return _env == null? null : $"{string.Join(", ", _env.Keys.ToArray())}"; }
+ get { return _env == null || _env.Keys == null? null : string.Join(", ", _env.Keys.ToArray()); }
}
///
@@ -76,7 +76,7 @@ public string EnvironmentNames
public override string ToString()
{
- return Context!= null? Context.ToString() : null;
+ return Context?.ToString();
}
}
}
diff --git a/tools/CLU/azure.sh b/tools/CLU/azure.sh
index e5149fc2f0e9..b35980f2e5bb 100644
--- a/tools/CLU/azure.sh
+++ b/tools/CLU/azure.sh
@@ -4,4 +4,4 @@ then
export CmdletSessionID=$PPID
fi
SCRIPTPATH=$(dirname "$0")
-$SCRIPTPATH/clurun -s azure -r $SCRIPTPATH/azure.lx $*
+$SCRIPTPATH/clurun -s azure -r $SCRIPTPATH/azure.lx "$@"