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.