diff --git a/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/GoogleCloudExtension.GCloud.UnitTests.csproj b/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/GoogleCloudExtension.GCloud.UnitTests.csproj
new file mode 100644
index 000000000..4546095a4
--- /dev/null
+++ b/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/GoogleCloudExtension.GCloud.UnitTests.csproj
@@ -0,0 +1,76 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {608977EE-0606-45F6-B68C-4861842B6FE3}
+ Library
+ Properties
+ GoogleCloudExtension.GCloud.UnitTests
+ GoogleCloudExtension.GCloud.UnitTests
+ v4.6.1
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 15.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
+ False
+ UnitTest
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\MSTest.TestFramework.1.2.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
+
+
+ ..\packages\MSTest.TestFramework.1.2.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
+
+
+ ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {95EFAC7E-4F6E-46F0-BCC8-90EE1487E1E1}
+ GoogleCloudExtension.GCloud
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/Properties/AssemblyInfo.cs b/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..ba9cbaf6a
--- /dev/null
+++ b/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/Properties/AssemblyInfo.cs
@@ -0,0 +1,32 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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.Reflection;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("GoogleCloudExtension.GCloud.UnitTests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Google Inc.")]
+[assembly: AssemblyProduct("Cloud Tools for Visual Studio")]
+[assembly: AssemblyCopyright("Copyright © Google Inc. 2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("608977ee-0606-45f6-b68c-4861842b6fe3")]
+
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/WindowsInstanceCredentialsTests.cs b/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/WindowsInstanceCredentialsTests.cs
new file mode 100644
index 000000000..654c1166e
--- /dev/null
+++ b/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/WindowsInstanceCredentialsTests.cs
@@ -0,0 +1,92 @@
+// Copyright 2018 Google Inc. All Rights Reserved.
+//
+// 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.VisualStudio.TestTools.UnitTesting;
+using Newtonsoft.Json;
+using System.Diagnostics.CodeAnalysis;
+
+namespace GoogleCloudExtension.GCloud.UnitTests
+{
+ [TestClass]
+ public class WindowsInstanceCredentialsTests
+ {
+ // ReSharper disable once UnusedAutoPropertyAccessor.Local
+ private static object[][] NotEqualObjects { get; } =
+ {
+ new object[] {null},
+ new object[] {"UserNameAndPassword"},
+ new object[] {new WindowsInstanceCredentials("DifferentUser", "Password")},
+ new object[] {new WindowsInstanceCredentials("User", "DifferentPassword")}
+ };
+
+ [TestMethod]
+ public void TestJsonSerialization()
+ {
+ var objectUnderTest = new WindowsInstanceCredentials("UserString", "PasswordString");
+
+ string json = JsonConvert.SerializeObject(objectUnderTest);
+
+ Assert.AreEqual(@"{""username"":""UserString"",""password"":""PasswordString""}", json);
+ }
+
+ [TestMethod]
+ public void TestJsonDeserialization()
+ {
+ var json = @"{""username"":""UserString"",""password"":""PasswordString""}";
+
+ var result = JsonConvert.DeserializeObject(json);
+
+ Assert.AreEqual("UserString", result.User);
+ Assert.AreEqual("PasswordString", result.Password);
+ }
+
+ [TestMethod]
+ [DynamicData(nameof(NotEqualObjects))]
+ public void TestEqualsFalse(object notEqualObject)
+ {
+ var sourceObject = new WindowsInstanceCredentials("User", "Password");
+ Assert.IsFalse(sourceObject.Equals(notEqualObject));
+ }
+
+ [TestMethod]
+ [DynamicData(nameof(NotEqualObjects))]
+ public void TestHashCodeNotEqual(object notEqualObject)
+ {
+ var sourceObject = new WindowsInstanceCredentials("User", "Password");
+ Assert.AreNotEqual(sourceObject.GetHashCode(), notEqualObject?.GetHashCode());
+ }
+
+ [TestMethod]
+ [SuppressMessage("ReSharper", "EqualExpressionComparison")]
+ public void TestEqualsTrue()
+ {
+ const string user = "User";
+ const string password = "Password";
+ var source = new WindowsInstanceCredentials(user, password);
+ var target = new WindowsInstanceCredentials(user, password);
+ Assert.IsTrue(source.Equals(source));
+ Assert.IsTrue(source.Equals(target));
+ }
+
+ [TestMethod]
+ public void TestGetHashCodeEqual()
+ {
+ const string user = "User";
+ const string password = "Password";
+ Assert.AreEqual(
+ new WindowsInstanceCredentials(user, password).GetHashCode(),
+ new WindowsInstanceCredentials(user, password).GetHashCode());
+ }
+ }
+}
diff --git a/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/packages.config b/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/packages.config
new file mode 100644
index 000000000..68e27a267
--- /dev/null
+++ b/GoogleCloudExtension/GoogleCloudExtension.GCloud.UnitTests/packages.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GoogleCloudExtension/GoogleCloudExtension.GCloud/WindowsInstanceCredentials.cs b/GoogleCloudExtension/GoogleCloudExtension.GCloud/WindowsInstanceCredentials.cs
index 34e90887f..40d1b0185 100644
--- a/GoogleCloudExtension/GoogleCloudExtension.GCloud/WindowsInstanceCredentials.cs
+++ b/GoogleCloudExtension/GoogleCloudExtension.GCloud/WindowsInstanceCredentials.cs
@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+using GoogleCloudExtension.Utils;
using Newtonsoft.Json;
namespace GoogleCloudExtension.GCloud
@@ -22,9 +23,47 @@ namespace GoogleCloudExtension.GCloud
public sealed class WindowsInstanceCredentials
{
[JsonProperty("username")]
- public string User { get; set; }
+ public string User { get; }
[JsonProperty("password")]
- public string Password { get; set; }
+ public string Password { get; }
+
+ [JsonConstructor]
+ public WindowsInstanceCredentials(string user, string password)
+ {
+ user.ThrowIfNull(nameof(user));
+ User = user;
+ Password = password;
+ }
+
+ /// Returns a string that represents the current object.
+ /// A string that represents the current object.
+ public override string ToString() => JsonConvert.SerializeObject(this);
+
+ public override bool Equals(object obj)
+ {
+ if (obj == this)
+ {
+ return true;
+ }
+ else if (!(obj is WindowsInstanceCredentials))
+ {
+ return false;
+ }
+ else
+ {
+ var credentials = (WindowsInstanceCredentials)obj;
+ return User == credentials.User &&
+ Password == credentials.Password;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ int hashCode = -1879510246;
+ hashCode = hashCode * -1521134295 + User.GetHashCode();
+ hashCode = hashCode * -1521134295 + Password.GetHashCode();
+ return hashCode;
+ }
}
}
diff --git a/GoogleCloudExtension/GoogleCloudExtension.sln b/GoogleCloudExtension/GoogleCloudExtension.sln
index 79d335246..9fbdb61f9 100644
--- a/GoogleCloudExtension/GoogleCloudExtension.sln
+++ b/GoogleCloudExtension/GoogleCloudExtension.sln
@@ -69,6 +69,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoogleCloudExtension.Deploy
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestingHelpers", "TestingHelpers\TestingHelpers.csproj", "{4EB5A3A0-3D68-4880-8855-405A46CDCE0B}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoogleCloudExtension.GCloud.UnitTests", "GoogleCloudExtension.GCloud.UnitTests\GoogleCloudExtension.GCloud.UnitTests.csproj", "{608977EE-0606-45F6-B68C-4861842B6FE3}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -171,6 +173,10 @@ Global
{4EB5A3A0-3D68-4880-8855-405A46CDCE0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EB5A3A0-3D68-4880-8855-405A46CDCE0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EB5A3A0-3D68-4880-8855-405A46CDCE0B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {608977EE-0606-45F6-B68C-4861842B6FE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {608977EE-0606-45F6-B68C-4861842B6FE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {608977EE-0606-45F6-B68C-4861842B6FE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {608977EE-0606-45F6-B68C-4861842B6FE3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/GoogleCloudExtension/GoogleCloudExtension/Accounts/IWindowsCredentialsStore.cs b/GoogleCloudExtension/GoogleCloudExtension/Accounts/IWindowsCredentialsStore.cs
index 3630abcee..817b6266d 100644
--- a/GoogleCloudExtension/GoogleCloudExtension/Accounts/IWindowsCredentialsStore.cs
+++ b/GoogleCloudExtension/GoogleCloudExtension/Accounts/IWindowsCredentialsStore.cs
@@ -43,7 +43,7 @@ internal interface IWindowsCredentialsStore
/// The GCE VM
/// The list of associated with The GCE VM. It might be
/// empty if no credentials are found.
- IEnumerable GetCredentialsForInstance(Instance instance);
+ IList GetCredentialsForInstance(Instance instance);
///
/// Returns the path where to store credential related information for a GCE VM.
diff --git a/GoogleCloudExtension/GoogleCloudExtension/Accounts/WindowsCredentialsStore.cs b/GoogleCloudExtension/GoogleCloudExtension/Accounts/WindowsCredentialsStore.cs
index c17b5ee8a..d66a42cb2 100644
--- a/GoogleCloudExtension/GoogleCloudExtension/Accounts/WindowsCredentialsStore.cs
+++ b/GoogleCloudExtension/GoogleCloudExtension/Accounts/WindowsCredentialsStore.cs
@@ -15,9 +15,9 @@
using Google.Apis.Compute.v1.Data;
using GoogleCloudExtension.DataSources;
using GoogleCloudExtension.GCloud;
+using GoogleCloudExtension.Utils;
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
@@ -40,48 +40,47 @@ internal class WindowsCredentialsStore : IWindowsCredentialsStore
private const string WindowsInstanceCredentialsPath = @"googlecloudvsextension\windows_credentials";
private const string PasswordFileExtension = ".data";
- private static readonly Lazy s_defaultStore = new Lazy();
- private static readonly string s_credentialsStoreRoot = GetCredentialsStoreRoot();
+ private static readonly Lazy s_defaultStore =
+ new Lazy(() => new WindowsCredentialsStore());
+ internal static readonly string s_credentialsStoreRoot = GetCredentialsStoreRoot();
private static readonly Regex s_invalidNameCharPattern = new Regex("[;:\\?\\\\]");
- ///
- /// In memory cache of the credentials for the current credentials (account and project pair).
- ///
- private readonly Dictionary> _credentialsForInstance = new Dictionary>();
-
public static WindowsCredentialsStore Default => s_defaultStore.Value;
+ /// Mockable static methods for testing.
+ internal Func DirectoryExists { private get; set; } = Directory.Exists;
+ internal Func FileExists { private get; set; } = File.Exists;
+ internal Func> EnumerateFiles { private get; set; } = Directory.EnumerateFiles;
+ internal Func ReadAllBytes { private get; set; } = File.ReadAllBytes;
+ internal Action WriteAllBytes { private get; set; } = File.WriteAllBytes;
+ internal Func CreateDirectory { private get; set; } = Directory.CreateDirectory;
+ internal Action DeleteFile { private get; set; } = File.Delete;
+
///
/// Loads the list of Windows credentials associated with .
///
/// The GCE VM
/// The list of associated with The GCE VM. It might be
/// empty if no credentials are found.
- public IEnumerable GetCredentialsForInstance(Instance instance)
+ public IList GetCredentialsForInstance(Instance instance)
{
- var instancePath = GetInstancePath(instance);
IEnumerable result;
- if (_credentialsForInstance.TryGetValue(instancePath, out result))
- {
- return result;
- }
- var instanceStoragePath = GetStoragePathForInstance(instance);
- if (!Directory.Exists(instanceStoragePath))
+ string instanceStoragePath = GetStoragePathForInstance(instance);
+ if (!DirectoryExists(instanceStoragePath))
{
result = Enumerable.Empty();
}
else
{
- result = Directory.EnumerateFiles(instanceStoragePath)
+ result = EnumerateFiles(instanceStoragePath)
.Where(x => Path.GetExtension(x) == PasswordFileExtension)
- .Select(x => LoadEncryptedCredentials(x))
+ .Select(LoadEncryptedCredentials)
.Where(x => x != null)
.OrderBy(x => x.User);
}
- _credentialsForInstance[instancePath] = result;
- return result;
+ return result.ToList();
}
///
@@ -91,11 +90,9 @@ public IEnumerable GetCredentialsForInstance(Instanc
/// The credentials to store.
public void AddCredentialsToInstance(Instance instance, WindowsInstanceCredentials credentials)
{
- var instancePath = GetInstancePath(instance);
- var instanceStoragePath = GetStoragePathForInstance(instance);
+ string instanceStoragePath = GetStoragePathForInstance(instance);
SaveEncryptedCredentials(instanceStoragePath, credentials);
- _credentialsForInstance.Remove(instancePath);
}
///
@@ -105,14 +102,12 @@ public void AddCredentialsToInstance(Instance instance, WindowsInstanceCredentia
/// The credentials.
public void DeleteCredentialsForInstance(Instance instance, WindowsInstanceCredentials credentials)
{
- var instancePath = GetInstancePath(instance);
- var instanceStoragePath = GetStoragePathForInstance(instance);
- var credentialsPath = Path.Combine(instanceStoragePath, GetFileName(credentials));
+ string instanceStoragePath = GetStoragePathForInstance(instance);
+ string credentialsPath = Path.Combine(instanceStoragePath, GetFileName(credentials));
- if (File.Exists(credentialsPath))
+ if (FileExists(credentialsPath))
{
- File.Delete(credentialsPath);
- _credentialsForInstance.Remove(instancePath);
+ DeleteFile(credentialsPath);
}
}
@@ -123,7 +118,7 @@ public void DeleteCredentialsForInstance(Instance instance, WindowsInstanceCrede
/// The full path where to store information for the instance.
public string GetStoragePathForInstance(Instance instance)
{
- var instancePath = GetInstancePath(instance);
+ string instancePath = GetInstancePath(instance);
return Path.Combine(s_credentialsStoreRoot, instancePath);
}
@@ -140,54 +135,64 @@ private WindowsInstanceCredentials LoadEncryptedCredentials(string path)
{
try
{
- var userName = GetUserName(path);
- var encryptedPassword = File.ReadAllBytes(path);
- var passwordBytes = ProtectedData.Unprotect(encryptedPassword, null, DataProtectionScope.CurrentUser);
+ string userName = GetUserName(path);
+ byte[] encryptedPassword = ReadAllBytes(path);
+ byte[] passwordBytes = ProtectedData.Unprotect(
+ encryptedPassword, null, DataProtectionScope.CurrentUser);
- return new WindowsInstanceCredentials { User = userName, Password = Encoding.UTF8.GetString(passwordBytes) };
+ return new WindowsInstanceCredentials(userName, Encoding.UTF8.GetString(passwordBytes));
}
- catch (CryptographicException)
+ catch (CryptographicException cryptographicException)
{
- Debug.WriteLine($"Failed to decrypt credentials from: {path}");
- try
- {
- File.Delete(path);
- }
- catch (IOException)
+ bool delete = UserPromptUtils.ErrorActionPrompt(
+ string.Format(Resources.WindowsCredentialsStoreDecryptErrorMessage, path),
+ Resources.WindowsCredentialsStoreDecryptionErrorTitle, cryptographicException.ToString());
+ if (delete)
{
- Debug.WriteLine($"Failed cleaning corrupted credentials {path}");
+ try
+ {
+ DeleteFile(path);
+ }
+ catch (IOException ioException)
+ {
+ UserPromptUtils.ErrorPrompt(
+ string.Format(Resources.WindowsCredentialsStoreDeletingCorruptedErrorMessage, path),
+ Resources.WindowsCredentialsStoreDeletingCorruptedErrorTitle, ioException.ToString());
+ }
}
return null;
}
- catch (IOException)
+ catch (IOException e)
{
- Debug.WriteLine($"Failed to load credentials from: {path}");
+ UserPromptUtils.ErrorPrompt(
+ string.Format(Resources.WindowsCredentialsStoreCredentialFileLoadErrorMessage, path),
+ Resources.WindowsCredentialsStoreCredentialFileLoadErrorTitle, e.ToString());
return null;
}
}
private void SaveEncryptedCredentials(string path, WindowsInstanceCredentials credentials)
{
- if (!Directory.Exists(path))
+ if (!DirectoryExists(path))
{
- Directory.CreateDirectory(path);
+ CreateDirectory(path);
}
- var filePath = Path.Combine(path, GetFileName(credentials));
- var passwordBytes = Encoding.UTF8.GetBytes(credentials.Password);
- var encrypted = ProtectedData.Protect(passwordBytes, null, DataProtectionScope.CurrentUser);
- File.WriteAllBytes(filePath, encrypted);
+ string filePath = Path.Combine(path, GetFileName(credentials));
+ byte[] passwordBytes = Encoding.UTF8.GetBytes(credentials.Password);
+ byte[] encrypted = ProtectedData.Protect(passwordBytes, null, DataProtectionScope.CurrentUser);
+ WriteAllBytes(filePath, encrypted);
}
private static string GetCredentialsStoreRoot()
{
- var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
return Path.Combine(localAppData, WindowsInstanceCredentialsPath);
}
- private static string GetInstancePath(Instance instance)
+ private string GetInstancePath(Instance instance)
{
- var credentials = CredentialsStore.Default;
+ CredentialsStore credentials = CredentialsStore.Default;
return $@"{ToValidPathName(credentials.CurrentProjectId)}\{ToValidPathName(instance.GetZoneName())}\{ToValidPathName(instance.Name)}";
}
diff --git a/GoogleCloudExtension/GoogleCloudExtension/GoogleCloudExtension.csproj.user b/GoogleCloudExtension/GoogleCloudExtension/GoogleCloudExtension.csproj.user
deleted file mode 100644
index 14a9884fa..000000000
--- a/GoogleCloudExtension/GoogleCloudExtension/GoogleCloudExtension.csproj.user
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- Program
- C:\Program Files %28x86%29\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe
- /rootsuffix Exp
-
-
- Program
- C:\Program Files %28x86%29\Microsoft Visual Studio 14.0\Common7\IDE\devenv.exe
- /rootsuffix Exp
-
-
- Program
- C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\devenv.exe
- /rootsuffix Exp
-
-
- Program
- C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\devenv.exe
- /rootsuffix Exp
-
-
- ProjectFiles
-
-
\ No newline at end of file
diff --git a/GoogleCloudExtension/GoogleCloudExtension/ManageWindowsCredentials/ManageWindowsCredentialsViewModel.cs b/GoogleCloudExtension/GoogleCloudExtension/ManageWindowsCredentials/ManageWindowsCredentialsViewModel.cs
index a708e8470..0de9d4435 100644
--- a/GoogleCloudExtension/GoogleCloudExtension/ManageWindowsCredentials/ManageWindowsCredentialsViewModel.cs
+++ b/GoogleCloudExtension/GoogleCloudExtension/ManageWindowsCredentials/ManageWindowsCredentialsViewModel.cs
@@ -158,11 +158,7 @@ private async void OnAddCredentialsCommand()
}
else
{
- credentials = new WindowsInstanceCredentials
- {
- User = request.User,
- Password = request.Password
- };
+ credentials = new WindowsInstanceCredentials(request.User, request.Password);
}
if (credentials != null)
diff --git a/GoogleCloudExtension/GoogleCloudExtension/Resources.Designer.cs b/GoogleCloudExtension/GoogleCloudExtension/Resources.Designer.cs
index c0c2e08a3..bae5662d3 100644
--- a/GoogleCloudExtension/GoogleCloudExtension/Resources.Designer.cs
+++ b/GoogleCloudExtension/GoogleCloudExtension/Resources.Designer.cs
@@ -6442,6 +6442,61 @@ public static string WindowsCredentialsChooserNoCredentialsFoundMessage {
}
}
+ ///
+ /// Looks up a localized string similar to Failed to load credentials from: {0}.
+ ///
+ public static string WindowsCredentialsStoreCredentialFileLoadErrorMessage {
+ get {
+ return ResourceManager.GetString("WindowsCredentialsStoreCredentialFileLoadErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Load failed.
+ ///
+ public static string WindowsCredentialsStoreCredentialFileLoadErrorTitle {
+ get {
+ return ResourceManager.GetString("WindowsCredentialsStoreCredentialFileLoadErrorTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Failed to decrypt credentials from: {0}
+ ///Delete corrupted file?.
+ ///
+ public static string WindowsCredentialsStoreDecryptErrorMessage {
+ get {
+ return ResourceManager.GetString("WindowsCredentialsStoreDecryptErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Delete Corrupted File.
+ ///
+ public static string WindowsCredentialsStoreDecryptionErrorTitle {
+ get {
+ return ResourceManager.GetString("WindowsCredentialsStoreDecryptionErrorTitle", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Failed to delete corrupted credentials file: {0}.
+ ///
+ public static string WindowsCredentialsStoreDeletingCorruptedErrorMessage {
+ get {
+ return ResourceManager.GetString("WindowsCredentialsStoreDeletingCorruptedErrorMessage", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Delete failed.
+ ///
+ public static string WindowsCredentialsStoreDeletingCorruptedErrorTitle {
+ get {
+ return ResourceManager.GetString("WindowsCredentialsStoreDeletingCorruptedErrorTitle", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to _MVC.
///
diff --git a/GoogleCloudExtension/GoogleCloudExtension/Resources.resx b/GoogleCloudExtension/GoogleCloudExtension/Resources.resx
index e6d9f05ab..4c3e4b55e 100644
--- a/GoogleCloudExtension/GoogleCloudExtension/Resources.resx
+++ b/GoogleCloudExtension/GoogleCloudExtension/Resources.resx
@@ -1,4 +1,4 @@
-
+
+
+
+
+
+ Debug
+ AnyCPU
+ {0CD177FD-16EE-4DE7-B013-5C26348A4AB9}
+ Library
+ Properties
+ GoogleCloudExtensionUnitTests
+ GoogleCloudExtensionUnitTests
+ v4.5.2
+ 512
+ {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 10.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
+ False
+ UnitTest
+
+
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ true
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ true
+
+
+ true
+
+
+ key.snk
+
+
+
+ ..\packages\Castle.Core.4.1.1\lib\net45\Castle.Core.dll
+ True
+
+
+ False
+ ..\packages\VSSDK.DTE.7.0.4\lib\net20\envdte.dll
+ True
+
+
+ ..\packages\Google.Apis.1.29.1\lib\net45\Google.Apis.dll
+ True
+
+
+ ..\packages\Google.Apis.Appengine.v1.1.29.1.987\lib\net45\Google.Apis.Appengine.v1.dll
+ True
+
+
+ ..\packages\Google.Apis.Auth.1.29.1\lib\net45\Google.Apis.Auth.dll
+ True
+
+
+ ..\packages\Google.Apis.Auth.1.29.1\lib\net45\Google.Apis.Auth.PlatformServices.dll
+ True
+
+
+ ..\packages\Google.Apis.Clouderrorreporting.v1beta1.1.29.1.987\lib\net45\Google.Apis.Clouderrorreporting.v1beta1.dll
+
+
+ ..\packages\Google.Apis.CloudResourceManager.v1.1.29.1.993\lib\net45\Google.Apis.CloudResourceManager.v1.dll
+ True
+
+
+ ..\packages\Google.Apis.CloudSourceRepositories.v1.1.29.1.981\lib\net45\Google.Apis.CloudSourceRepositories.v1.dll
+ True
+
+
+ ..\packages\Google.Apis.Compute.v1.1.29.1.981\lib\net45\Google.Apis.Compute.v1.dll
+ True
+
+
+ ..\packages\Google.Apis.Container.v1.1.29.1.981\lib\net45\Google.Apis.Container.v1.dll
+ True
+
+
+ ..\packages\Google.Apis.Core.1.29.1\lib\net45\Google.Apis.Core.dll
+ True
+
+
+ False
+ ..\packages\Google.Apis.Logging.v2.1.29.1.991\lib\net45\Google.Apis.Logging.v2.dll
+
+
+ ..\packages\Google.Apis.1.29.1\lib\net45\Google.Apis.PlatformServices.dll
+ True
+
+
+ ..\packages\Google.Apis.Pubsub.v1.1.29.1.971\lib\net45\Google.Apis.Pubsub.v1.dll
+ True
+
+
+ ..\packages\log4net.2.0.8\lib\net45-full\log4net.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Imaging.14.3.25407\lib\net45\Microsoft.VisualStudio.Imaging.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.OLE.Interop.7.10.6070\lib\Microsoft.VisualStudio.OLE.Interop.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Shell.14.0.14.3.25407\lib\Microsoft.VisualStudio.Shell.14.0.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Shell.Immutable.10.0.10.0.30319\lib\net40\Microsoft.VisualStudio.Shell.Immutable.10.0.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Shell.Immutable.11.0.11.0.50727\lib\net45\Microsoft.VisualStudio.Shell.Immutable.11.0.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Shell.Immutable.12.0.12.0.21003\lib\net45\Microsoft.VisualStudio.Shell.Immutable.12.0.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Shell.Immutable.14.0.14.3.25407\lib\net45\Microsoft.VisualStudio.Shell.Immutable.14.0.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Shell.Interop.7.10.6071\lib\Microsoft.VisualStudio.Shell.Interop.dll
+ True
+
+
+ True
+ ..\packages\Microsoft.VisualStudio.Shell.Interop.10.0.10.0.30319\lib\Microsoft.VisualStudio.Shell.Interop.10.0.dll
+ True
+
+
+ True
+ ..\packages\Microsoft.VisualStudio.Shell.Interop.11.0.11.0.61030\lib\Microsoft.VisualStudio.Shell.Interop.11.0.dll
+ True
+
+
+ True
+ ..\packages\Microsoft.VisualStudio.Shell.Interop.12.0.12.0.30110\lib\Microsoft.VisualStudio.Shell.Interop.12.0.dll
+ True
+
+
+ True
+ ..\packages\Microsoft.VisualStudio.Shell.Interop.12.1.DesignTime.12.1.30328\lib\Microsoft.VisualStudio.Shell.Interop.12.1.DesignTime.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Shell.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.Shell.Interop.8.0.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Shell.Interop.9.0.9.0.30729\lib\Microsoft.VisualStudio.Shell.Interop.9.0.dll
+ True
+
+
+ ..\packages\VSSDK.TemplateWizardInterface.12.0.4\lib\net20\Microsoft.VisualStudio.TemplateWizardInterface.dll
+ True
+ False
+
+
+ ..\packages\MSTest.TestFramework.1.2.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
+
+
+ ..\packages\MSTest.TestFramework.1.2.1\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
+
+
+ ..\packages\Microsoft.VisualStudio.TextManager.Interop.7.10.6070\lib\Microsoft.VisualStudio.TextManager.Interop.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.TextManager.Interop.8.0.8.0.50727\lib\Microsoft.VisualStudio.TextManager.Interop.8.0.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Threading.14.1.131\lib\net45\Microsoft.VisualStudio.Threading.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Utilities.14.3.25407\lib\net45\Microsoft.VisualStudio.Utilities.dll
+ True
+
+
+ ..\packages\Microsoft.VisualStudio.Validation.14.1.111\lib\net45\Microsoft.VisualStudio.Validation.dll
+ True
+
+
+ ..\packages\Moq.4.7.127\lib\net45\Moq.dll
+ True
+
+
+ ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll
+ True
+
+
+ False
+ ..\packages\VSSDK.DTE.7.0.4\lib\net20\stdole.dll
+ True
+
+
+
+ ..\packages\Zlib.Portable.Signed.1.11.0\lib\portable-net4+sl5+wp8+win8+wpa81+MonoTouch+MonoAndroid\Zlib.Portable.dll
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+ True
+ UnitTestResources.resx
+
+
+
+
+
+
+
+
+
+
+
+
+ {A2D9AC4E-9621-4385-A175-316832F7BFDC}
+ GoogleAnalyticsUtils
+
+
+ {3988aac1-3b20-4ba1-9627-ed7d3c80145f}
+ GoogleCloudExtension.DataSources
+
+
+ {85d0caad-a3e0-4a3b-b107-500caa2a5994}
+ GoogleCloudExtension.Deployment.UnitTests
+
+
+ {92c6e0d0-41d8-4ecc-87e1-ae72fca891fc}
+ GoogleCloudExtension.Deployment
+
+
+ {95EFAC7E-4F6E-46F0-BCC8-90EE1487E1E1}
+ GoogleCloudExtension.GCloud
+
+
+ {0C891356-CCD7-4A10-BA27-C4A4359EA825}
+ GoogleCloudExtension.GcsUtils
+
+
+ {856b9f2e-441f-405a-9d5c-af5dc5653902}
+ GoogleCloudExtension.Interop
+
+
+ {21501704-9D0C-442F-AD39-292B3DA4BC57}
+ GoogleCloudExtension.Utils
+
+
+ {bfd6afbf-f0db-4ce1-9681-dae4e93f6dc5}
+ GoogleCloudExtension
+
+
+ {4EB5A3A0-3D68-4880-8855-405A46CDCE0B}
+ TestingHelpers
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+ Designer
+
+
+
+
+ ResXFileCodeGenerator
+ UnitTestResources.Designer.cs
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/GoogleCloudExtension/GoogleCloudExtensionUnitTests/PublishDialogSteps/GceStep/GceStepViewModelTests.cs b/GoogleCloudExtension/GoogleCloudExtensionUnitTests/PublishDialogSteps/GceStep/GceStepViewModelTests.cs
index d3048c2f9..438046e0a 100644
--- a/GoogleCloudExtension/GoogleCloudExtensionUnitTests/PublishDialogSteps/GceStep/GceStepViewModelTests.cs
+++ b/GoogleCloudExtension/GoogleCloudExtensionUnitTests/PublishDialogSteps/GceStep/GceStepViewModelTests.cs
@@ -97,13 +97,13 @@ public class GceStepViewModelTests : ExtensionTestBase
s_windows2012Instance
};
- private static readonly WindowsInstanceCredentials s_credentials = new WindowsInstanceCredentials { User = "User1", Password = "Password1" };
+ private static readonly WindowsInstanceCredentials s_credentials = new WindowsInstanceCredentials("User1", "Password1");
private static readonly List s_credentialsList =
new List
{
s_credentials,
- new WindowsInstanceCredentials {User = "User2", Password = "Password2"}
+ new WindowsInstanceCredentials ("User2", "Password2")
};
private GceStepViewModel _objectUnderTest;
@@ -219,7 +219,7 @@ public void TestSetSelectedInstance_ToEnablesManagedCredentialsCommand()
[TestMethod]
public void TestSetSelectedCredentials()
{
- var credentials2 = new WindowsInstanceCredentials { User = "User2", Password = "Password2" };
+ var credentials2 = new WindowsInstanceCredentials("User2", "Password2");
_objectUnderTest.SelectedCredentials = credentials2;
Assert.AreEqual(credentials2, _objectUnderTest.SelectedCredentials);
@@ -234,7 +234,7 @@ public void TestSetSelectedCredentials_ToNullDisablesCanPublish()
.Returns(s_credentialsList);
_objectUnderTest.OnVisible(_mockedPublishDialog);
_objectUnderTest.SelectedCredentials =
- new WindowsInstanceCredentials { User = "User2", Password = "Password2" };
+ new WindowsInstanceCredentials("User2", "Password2");
_canPublishChangedCount = 0;
_objectUnderTest.SelectedCredentials = null;
@@ -253,7 +253,7 @@ public void TestSetSelectedCredentials_EnablesCanPublish()
_objectUnderTest.SelectedCredentials = null;
_canPublishChangedCount = 0;
- _objectUnderTest.SelectedCredentials = new WindowsInstanceCredentials { User = "User2", Password = "Password2" };
+ _objectUnderTest.SelectedCredentials = new WindowsInstanceCredentials("User2", "Password2");
Assert.IsTrue(_objectUnderTest.CanPublish);
Assert.AreEqual(1, _canPublishChangedCount);
diff --git a/GoogleCloudExtension/GoogleCloudExtensionUnitTests/StackdriverErrorReporting/ErrorReportingDetailViewModelTests.cs b/GoogleCloudExtension/GoogleCloudExtensionUnitTests/StackdriverErrorReporting/ErrorReportingDetailViewModelTests.cs
index 964b82313..a84406c95 100644
--- a/GoogleCloudExtension/GoogleCloudExtensionUnitTests/StackdriverErrorReporting/ErrorReportingDetailViewModelTests.cs
+++ b/GoogleCloudExtension/GoogleCloudExtensionUnitTests/StackdriverErrorReporting/ErrorReportingDetailViewModelTests.cs
@@ -46,7 +46,6 @@ public class ErrorReportingDetailViewModelTests : ExtensionTestBase
private Mock _dataSourceMock;
private TaskCompletionSource _getPageOfEventsSource;
private TaskCompletionSource _getPageOfGroupStatusSource;
- private Mock> _promptUserMock;
private IGoogleCloudExtensionPackage _oldPackage;
private Mock _packageMock;
@@ -87,9 +86,7 @@ protected override void BeforeEach()
new ErrorGroupStats { Group = new ErrorGroup { GroupId = "" }, TimedCounts = new List() },
_defaultTimeRangeItem);
- _promptUserMock = new Mock>();
- _promptUserMock.Setup(f => f(It.IsAny())).Returns(true);
- UserPromptWindow.PromptUserFunction = _promptUserMock.Object;
+ PromptUserMock.Setup(f => f(It.IsAny())).Returns(true);
}
[TestCleanup]
diff --git a/TestScript.ps1 b/TestScript.ps1
index f8ad2b951..21c02c2bb 100644
--- a/TestScript.ps1
+++ b/TestScript.ps1
@@ -8,7 +8,8 @@ $testDllNames = "GoogleAnalyticsUtilsTests.dll",
"GoogleCloudExtensionUnitTests.dll",
"GoogleCloudExtension.Utils.UnitTests.dll",
"GoogleCloudExtension.DataSources.UnitTests.dll",
- "GoogleCloudExtension.Deployment.UnitTests.dll"
+ "GoogleCloudExtension.Deployment.UnitTests.dll",
+ "GoogleCloudExtension.GCloud.UnitTests.dll"
if ($env:APPVEYOR_SCHEDULED_BUILD -or $FunctionalTests) {
# Don't run functional tests on triggered (PR) builds.