From eabda46c076aa76665209d13c0d96d3fab73178c Mon Sep 17 00:00:00 2001 From: Alan Quillin Date: Thu, 7 Feb 2013 16:11:52 -0600 Subject: [PATCH] Added new Extended Identity Tests: ChangePassword --- lib/SimpleRestServices.dll | Bin 15872 -> 32256 bytes lib/SimpleRestServices.pdb | Bin 36352 -> 69120 bytes src/corelib/Core/Domain/ServerState.cs | 42 ++++ .../Response/MethodNotImplementedException.cs | 14 ++ .../Exceptions/Response/ResponseException.cs | 1 + .../Response/UserNotAuthorizedException.cs | 3 + src/corelib/Core/IComputeProvider.cs | 7 + src/corelib/Core/IIdentityProvider.cs | 1 + .../Providers/Rackspace/ComputeProvider.cs | 67 ++++++ .../Rackspace/GeographicalIdentityProvider.cs | 53 +++-- .../Rackspace/IExtendedIdentityProvider.cs | 4 + .../Providers/Rackspace/IdentityProvider.cs | 30 +++ .../Providers/Rackspace/ProviderBase.cs | 4 +- src/corelib/corelib.csproj | 2 + src/testing/integration/Bootstrapper.cs | 39 ++-- .../Rackspace/ComputeFull.orderedtest | 10 +- .../Providers/Rackspace/ComputeTests.cs | 84 ++++---- .../ExtendedIdentityFull.orderedtest | 16 ++ .../Rackspace/ExtendedIdentityTests.cs | 191 ++++++++++++++++++ .../Providers/Rackspace/Full.orderedtest | 3 +- .../Providers/Rackspace/IdentityTests.cs | 15 +- src/testing/integration/integration.csproj | 4 + 22 files changed, 496 insertions(+), 94 deletions(-) create mode 100644 src/corelib/Core/Domain/ServerState.cs create mode 100644 src/corelib/Core/Exceptions/Response/MethodNotImplementedException.cs create mode 100644 src/testing/integration/Providers/Rackspace/ExtendedIdentityFull.orderedtest create mode 100644 src/testing/integration/Providers/Rackspace/ExtendedIdentityTests.cs diff --git a/lib/SimpleRestServices.dll b/lib/SimpleRestServices.dll index b700a8b378c3b46a362c68112be3cdfda91392d1..b3543a6d20113017b85eb28ff5ba41b291eb0f3d 100644 GIT binary patch literal 32256 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 E0nNdPR{#J2 literal 15872 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 XiEF$3Jq!)5`IGSW|DF6Fj=+Bb3X0mr diff --git a/lib/SimpleRestServices.pdb b/lib/SimpleRestServices.pdb index ccdf6e528658cb50e26db69cb21ae77d536c3ca4..8dfbd29664ec6066e2dd4aab384797a2c3e095ff 100644 GIT binary patch literal 69120 zcmeI54Pe$)y~m#i$9T~xLl98V@%}!xvB4&&+t?5ils6R>gRwopbZm1Q0%iIqQPJ=v zFO{YiDW-L`tkkURhNWFJExLKju3FSJueWPyUcBke?0&xI<^TNm?Ah4ZxRr9?x9{^m zufOv<=lss=|NIx$RyQ>?H>_#NnKNz9LzuzLmuLGvh}-l^-uw1sLE6m=ycVUoyZW z0{$E}?`a7%H`K4Vh(AqJ7DZHHoI4iMBb>bZMe# zg*b3*H#RlEMstHnpg#pR2#P}urAM0L`wf5lnP0J(s&+P%34Ibz@}V%jp(PA)jsi8r z=?jg5`aos)lb=6<$Aj+~^VaIcr+vTAPqJ@X8ryx=UA;c{c;y+l{^!g8l6})@_W8&= zu0B6|%}=twJt-D@tMB}8uljs_>5pnYy5Qm0%b(rSbkD6)8!~sk{qQ>r|M!YJ?|J!$ zuU_z#Cx^^KP#Fj_K-yDqzX|Cs2P>c>AQgfNU^a9LbSiWjR0@?rL!n`iggpdOVJIyX z&Ok_oqCy@Fod6AoMnES*CqX&TNJs@Z8X5zQg~mbSp$X7Lh-}3sL*j8NlnYIR@}PXE z0GbXJLPgLFXeLwwNpGGE&4P}F{vJ&_{jZ)-<>U3go|U&${CmvrVV+w{;83;yeI&CV znnFc-m4>>9-)jG_LKWzSLUcnZBptC2yP??aL?PSCilAKJ)?T3}^wg5IPe&3t9v%hL%9fAkE*;hR%V`g(Uy;ps4Ao@?Ut@ z^H*GW|0!4fcTVuz-TPPlcQlQ|zyEe6aHz^(ZBG5P>hxjrw<`hZzWs5=Fh|(&jPK(! zDY$LeOJ}4b`Rl4tJbfUN3det))zydV5kflzhHf_26XX9?V{iNJ!;5og-udfs86WM|9f6=?~x4lRQWdyzh~mh_doIOiU0nc?Eb(0;i{#q(XlkB1;1GL zRu8p0>6R$9J{d+k=j0XVhHH{b&6?yARs>zbc1<#k^&Gn zOXGe?LQ;@45|Io^O5X3zmWR%jU*%qYN8lqi3Que)T)*m&f;%>8bKRY566;`g+N*`328U-n!(IBmdHp zSkGGgnC!EcZf@px?wp3Yxt$%!QmBK7! zB~9!2T5Ht0w)PP;2h~$XuL)*Pfi=NQ#ZeHOWa58a6#%2PH*XljW`3}@tsAk*O^NCa zEv9N57ds+*0RA6^A;?@P z(0&qoR)O}vWxJXoy`Ty?z&;2y-^e;TS{-R^IzkJ{Lh21TG zmBIgK`K!J~>wwDp{a|{k{0H^j`q0W(uDJW1;~)INqF$@U^+frrO#T|}UuCcMulhG1 zite|}qo)wn?M>UT6=KmI%V0OP+D_cr6dr2D~+|L!#sxxniE_FT@76WZG*0bu7f@XZHKOhZh&rt zZh}4z-3pxdF|&{XIS=rhn~p`FkyXf~wz&Z*F8(C45# zp}U}6&_^M=e){*i{@1-V%d?y6%9CehySK>O`rIuu(GJX!Ct633ZM~|O(<+-^(|i{T z-|MBWYf4MBUGK5$D+gGkAy(<2>X>^swUNWQ_NN=H^0_m<} zK*a+E(naX1AO}QWF}EIL=E+&i#Is^K(0KE_A9saSE@kw45A*`GAI4TuxfR#Lki7Uc z8g!>rA*SuRROi-c(yv2pk}}5RS}=dfPv#H#WmrsEhq?v+DhMP0-j8^s;NYw+kMF+r z?rVzY6*b!KRo%#Pd$l+3D|Jt_J-&ev?*I7mzfO&=drTfK|CSYhcl&?I*FCyd z_L&j#U^XV3?=0+W&cgm}Jz~douz*U*#cPzdHc`mqGIH z{rIs#x_≱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 PumlcE;IIS^u>}4PkLaxD delta 7582 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 H8}i=)BL2*P diff --git a/src/corelib/Core/Domain/ServerState.cs b/src/corelib/Core/Domain/ServerState.cs new file mode 100644 index 000000000..85f23f62f --- /dev/null +++ b/src/corelib/Core/Domain/ServerState.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace net.openstack.Core.Domain +{ + public class ServerState + { + public static string ACTIVE { get { return "ACTIVE"; } } + + public static string BUILD { get { return "BUILD"; } } + + public static string DELETED { get { return "DELETED"; } } + + public static string ERROR { get { return "ERROR"; } } + + public static string HARD_REBOOT { get { return "HARD_REBOOT"; } } + + public static string MIGRATING { get { return "MIGRATING"; } } + + public static string PASSWORD { get { return "PASSWORD"; } } + + public static string REBOOT { get { return "REBOOT"; } } + + public static string REBUILD { get { return "REBUILD"; } } + + public static string RESCUE { get { return "RESCUE"; } } + + public static string RESIZE { get { return "RESIZE"; } } + + public static string REVERT_RESIZE { get { return "REVERT_RESIZE"; } } + + public static string SUSPENDED { get { return "SUSPENDED"; } } + + public static string UNKNOWN { get { return "UNKNOWN"; } } + + public static string VERIFY_RESIZE { get { return "VERIFY_RESIZE"; } } + } + + public class ImageState : ServerState{} +} diff --git a/src/corelib/Core/Exceptions/Response/MethodNotImplementedException.cs b/src/corelib/Core/Exceptions/Response/MethodNotImplementedException.cs new file mode 100644 index 000000000..4f621a0c0 --- /dev/null +++ b/src/corelib/Core/Exceptions/Response/MethodNotImplementedException.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace net.openstack.Core.Exceptions.Response +{ + class MethodNotImplementedException : ResponseException + { + public MethodNotImplementedException(SimpleRestServices.Client.Response response) : base("The requested method is not implemented at the service.", response) { } + + public MethodNotImplementedException(string message, SimpleRestServices.Client.Response response) : base(message, response) {} + } +} diff --git a/src/corelib/Core/Exceptions/Response/ResponseException.cs b/src/corelib/Core/Exceptions/Response/ResponseException.cs index cac0ce3c5..4ee81781b 100644 --- a/src/corelib/Core/Exceptions/Response/ResponseException.cs +++ b/src/corelib/Core/Exceptions/Response/ResponseException.cs @@ -2,6 +2,7 @@ namespace net.openstack.Core.Exceptions.Response { + [Serializable] public class ResponseException : Exception { public SimpleRestServices.Client.Response Response { get; private set; } diff --git a/src/corelib/Core/Exceptions/Response/UserNotAuthorizedException.cs b/src/corelib/Core/Exceptions/Response/UserNotAuthorizedException.cs index 9da797c54..9baa36e64 100644 --- a/src/corelib/Core/Exceptions/Response/UserNotAuthorizedException.cs +++ b/src/corelib/Core/Exceptions/Response/UserNotAuthorizedException.cs @@ -1,5 +1,8 @@ +using System; + namespace net.openstack.Core.Exceptions.Response { + [Serializable] public class UserNotAuthorizedException : ResponseException { public UserNotAuthorizedException(SimpleRestServices.Client.Response response) : base("Unable to authenticate user and retrieve authorized service endpoints", response){} diff --git a/src/corelib/Core/IComputeProvider.cs b/src/corelib/Core/IComputeProvider.cs index 7d382d209..98cf1bc94 100644 --- a/src/corelib/Core/IComputeProvider.cs +++ b/src/corelib/Core/IComputeProvider.cs @@ -57,6 +57,13 @@ public interface IComputeProvider string GetImageMetadataItem(CloudIdentity identity, string cloudServerId, string key, string region = null); bool SetImageMetadataItem(CloudIdentity identity, string cloudServerId, string key, string value, string region = null); bool DeleteImageMetadataItem(CloudIdentity identity, string cloudServerId, string key, string region = null); + + ServerDetails WaitForServerState(CloudIdentity identity, string cloudServerId, string expectedState, string[] errorStates, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400); + ServerDetails WaitForServerActive(CloudIdentity identity, string cloudServerId, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400); + ServerDetails WaitForServerDeleted(CloudIdentity identity, string cloudServerId, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400); + ServerImageDetails WaitForImageState(CloudIdentity identity, string imageId, string expectedState, string[] errorStates, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400); + ServerImageDetails WaitForImageActive(CloudIdentity identity, string imageId, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400); + ServerImageDetails WaitForImageDeleted(CloudIdentity identity, string imageId, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400); } } \ No newline at end of file diff --git a/src/corelib/Core/IIdentityProvider.cs b/src/corelib/Core/IIdentityProvider.cs index a08e33288..897c0a565 100644 --- a/src/corelib/Core/IIdentityProvider.cs +++ b/src/corelib/Core/IIdentityProvider.cs @@ -20,5 +20,6 @@ public interface IIdentityProvider UserCredential[] ListUserCredentials(CloudIdentity identity, string userId); Tenant[] ListTenants(CloudIdentity identity); + UserAccess GetUserAccess(CloudIdentity identity, bool forceCacheRefresh = false); } } diff --git a/src/corelib/Providers/Rackspace/ComputeProvider.cs b/src/corelib/Providers/Rackspace/ComputeProvider.cs index ac074cd23..7beef46e2 100644 --- a/src/corelib/Providers/Rackspace/ComputeProvider.cs +++ b/src/corelib/Providers/Rackspace/ComputeProvider.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using SimpleRestServices.Client; using SimpleRestServices.Client.Json; using net.openstack.Core; @@ -116,6 +117,34 @@ public bool DeleteServer(CloudIdentity identity, string cloudServerId, string re return true; } + public ServerDetails WaitForServerState(CloudIdentity identity, string cloudServerId, string expectedState, string[] errorStates, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400) + { + var serverDetails = GetDetails(identity, cloudServerId, region); + + int count = 0; + while (!serverDetails.Status.Equals(expectedState) && !errorStates.Contains(serverDetails.Status) && count < refreshCount) + { + Thread.Sleep(refreshDelayInMS); + serverDetails = GetDetails(identity, cloudServerId, region); + count++; + } + + if (errorStates.Contains(serverDetails.Status)) + throw new ServerEnteredErrorStateException(serverDetails.Status); + + return serverDetails; + } + + public ServerDetails WaitForServerActive(CloudIdentity identity, string cloudServerId, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400) + { + return WaitForServerState(identity, cloudServerId, ServerState.ACTIVE, new [] {ServerState.ERROR, ServerState.UNKNOWN, ServerState.SUSPENDED}, region, refreshCount, refreshDelayInMS); + } + + public ServerDetails WaitForServerDeleted(CloudIdentity identity, string cloudServerId, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400) + { + return WaitForServerState(identity, cloudServerId, ServerState.DELETED, new[] { ServerState.ERROR, ServerState.UNKNOWN, ServerState.SUSPENDED }, region, refreshCount, refreshDelayInMS); + } + #endregion #region Server Addresses @@ -394,6 +423,34 @@ public bool DeleteImage(CloudIdentity identity, string imageId, string region = return true; } + public ServerImageDetails WaitForImageState(CloudIdentity identity, string imageId, string expectedState, string[] errorStates, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400) + { + var details = GetImage(identity, imageId, region); + + int count = 0; + while (!details.Status.Equals(expectedState) && !errorStates.Contains(details.Status) && count < refreshCount) + { + Thread.Sleep(refreshDelayInMS); + details = GetImage(identity, imageId, region); + count++; + } + + if (errorStates.Contains(details.Status)) + throw new ServerEnteredErrorStateException(details.Status); + + return details; + } + + public ServerImageDetails WaitForImageActive(CloudIdentity identity, string imageId, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400) + { + return WaitForImageState(identity, imageId, ImageState.ACTIVE, new[] { ImageState.ERROR, ImageState.UNKNOWN, ImageState.SUSPENDED }, region, refreshCount, refreshDelayInMS); + } + + public ServerImageDetails WaitForImageDeleted(CloudIdentity identity, string imageId, string region = null, int refreshCount = 600, int refreshDelayInMS = 2400) + { + return WaitForImageState(identity, imageId, ImageState.DELETED, new[] { ImageState.ERROR, ImageState.UNKNOWN, ImageState.SUSPENDED }, region, refreshCount, refreshDelayInMS); + } + #endregion #region Server Metadata @@ -557,4 +614,14 @@ protected string GetServiceEndpoint(CloudIdentity identity, string region = null #endregion } + + public class ServerEnteredErrorStateException : Exception + { + public string Status { get; private set; } + + public ServerEnteredErrorStateException(string status) : base(string.Format("The server entered an error state: '{0}'", status)) + { + Status = status; + } + } } diff --git a/src/corelib/Providers/Rackspace/GeographicalIdentityProvider.cs b/src/corelib/Providers/Rackspace/GeographicalIdentityProvider.cs index 63a37cd64..c10bc68e0 100644 --- a/src/corelib/Providers/Rackspace/GeographicalIdentityProvider.cs +++ b/src/corelib/Providers/Rackspace/GeographicalIdentityProvider.cs @@ -99,12 +99,22 @@ public bool SetUserPassword(CloudIdentity identity, string userId, string passwo { var user = GetUser(identity, userId); + return SetUserPassword(identity, user, password); + } + + public bool SetUserPassword(CloudIdentity identity, User user, string password) + { + return SetUserPassword(identity, user.Id, user.Username, password); + } + + public bool SetUserPassword(CloudIdentity identity, string userId, string username, string password) + { var urlPath = string.Format("v2.0/users/{0}/OS-KSADM/credentials", userId); var request = new SetPasswordRequest - { - PasswordCredencial = - new PasswordCredencial {Username = user.Username, Password = password} - }; + { + PasswordCredencial = + new PasswordCredencial { Username = username, Password = password } + }; var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, request); if (response == null || response.StatusCode != 201 || response.Data == null) @@ -128,8 +138,18 @@ public UserCredential UpdateUserCredentials(CloudIdentity identity, string userI { var user = GetUser(identity, userId); + return UpdateUserCredentials(identity, user, apiKey); + } + + public UserCredential UpdateUserCredentials(CloudIdentity identity, User user, string apiKey) + { + return UpdateUserCredentials(identity, user.Id, user.Username, apiKey); + } + + public UserCredential UpdateUserCredentials(CloudIdentity identity, string userId, string username, string apiKey) + { var urlPath = string.Format("v2.0/users/{0}/OS-KSADM/credentials/RAX-KSKEY:apiKeyCredentials", userId); - var request = new UpdateUserCredencialRequest { UserCredential = new UserCredential { Username = user.Username, APIKey = apiKey } }; + var request = new UpdateUserCredencialRequest { UserCredential = new UserCredential { Username = username, APIKey = apiKey } }; var response = ExecuteRESTRequest(identity, urlPath, HttpMethod.POST, request); if (response == null || response.Data == null) @@ -280,24 +300,27 @@ public IdentityToken GetTokenInfo(CloudIdentity identity, bool forceCacheRefresh public UserAccess Authenticate(CloudIdentity identity) { - var auth = AuthRequest.FromCloudIdentity(identity); - var response = ExecuteRESTRequest(identity, "/v2.0/tokens", HttpMethod.POST, auth, isTokenRequest: true); - - - if (response == null || response.Data == null || response.Data.UserAccess == null || response.Data.UserAccess.Token == null) - return null; - - return response.Data.UserAccess; + return GetUserAccess(identity, true); } - private UserAccess GetUserAccess(CloudIdentity identity, bool forceCacheRefresh = false) + public UserAccess GetUserAccess(CloudIdentity identity, bool forceCacheRefresh = false) { var rackspaceCloudIdentity = identity as RackspaceCloudIdentity; if (rackspaceCloudIdentity == null) throw new InvalidCloudIdentityException(string.Format("Invalid Identity object. Rackspace Identity service requires an instance of type: {0}", typeof(RackspaceCloudIdentity))); - var userAccess = _userAccessCache.Get(string.Format("{0}/{1}", rackspaceCloudIdentity.CloudInstance, rackspaceCloudIdentity.Username), () => Authenticate(rackspaceCloudIdentity), forceCacheRefresh); + var userAccess = _userAccessCache.Get(string.Format("{0}/{1}", rackspaceCloudIdentity.CloudInstance, rackspaceCloudIdentity.Username), () => + { + var auth = AuthRequest.FromCloudIdentity(identity); + var response = ExecuteRESTRequest(identity, "/v2.0/tokens", HttpMethod.POST, auth, isTokenRequest: true); + + + if (response == null || response.Data == null || response.Data.UserAccess == null || response.Data.UserAccess.Token == null) + return null; + + return response.Data.UserAccess; + }, forceCacheRefresh); return userAccess; } diff --git a/src/corelib/Providers/Rackspace/IExtendedIdentityProvider.cs b/src/corelib/Providers/Rackspace/IExtendedIdentityProvider.cs index ff82a15ab..ad0b54a99 100644 --- a/src/corelib/Providers/Rackspace/IExtendedIdentityProvider.cs +++ b/src/corelib/Providers/Rackspace/IExtendedIdentityProvider.cs @@ -14,5 +14,9 @@ public interface IExtendedIdentityProvider : IIdentityProvider UserCredential UpdateUserCredentials(CloudIdentity identity, string userId, string apiKey); bool DeleteUserCredentials(CloudIdentity identity, string userId); bool SetUserPassword(CloudIdentity identity, string userId, string password); + bool SetUserPassword(CloudIdentity identity, User user, string password); + bool SetUserPassword(CloudIdentity identity, string userId, string username, string password); + UserCredential UpdateUserCredentials(CloudIdentity identity, User user, string apiKey); + UserCredential UpdateUserCredentials(CloudIdentity identity, string userId, string username, string apiKey); } } diff --git a/src/corelib/Providers/Rackspace/IdentityProvider.cs b/src/corelib/Providers/Rackspace/IdentityProvider.cs index 32a0e43fd..1ecb11afa 100644 --- a/src/corelib/Providers/Rackspace/IdentityProvider.cs +++ b/src/corelib/Providers/Rackspace/IdentityProvider.cs @@ -91,6 +91,30 @@ public bool SetUserPassword(CloudIdentity identity, string userId, string passwo return provider.SetUserPassword(identity, userId, password); } + public bool SetUserPassword(CloudIdentity identity, User user, string password) + { + var provider = GetProvider(identity); + return provider.SetUserPassword(identity, user, password); + } + + public bool SetUserPassword(CloudIdentity identity, string userId, string username, string password) + { + var provider = GetProvider(identity); + return provider.SetUserPassword(identity, userId, username, password); + } + + public UserCredential UpdateUserCredentials(CloudIdentity identity, User user, string apiKey) + { + var provider = GetProvider(identity); + return provider.UpdateUserCredentials(identity, user, apiKey); + } + + public UserCredential UpdateUserCredentials(CloudIdentity identity, string userId, string username, string apiKey) + { + var provider = GetProvider(identity); + return provider.UpdateUserCredentials(identity, userId, username, apiKey); + } + public UserCredential[] ListUserCredentials(CloudIdentity identity, string userId) { var provider = GetProvider(identity); @@ -115,6 +139,12 @@ public Tenant[] ListTenants(CloudIdentity identity) return provider.ListTenants(identity); } + public UserAccess GetUserAccess(CloudIdentity identity, bool forceCacheRefresh = false) + { + var provider = GetProvider(identity); + return provider.GetUserAccess(identity, forceCacheRefresh); + } + public string GetToken(CloudIdentity identity, bool forceCacheRefresh = false) { var provider = GetProvider(identity); diff --git a/src/corelib/Providers/Rackspace/ProviderBase.cs b/src/corelib/Providers/Rackspace/ProviderBase.cs index e01712644..479d02ba1 100644 --- a/src/corelib/Providers/Rackspace/ProviderBase.cs +++ b/src/corelib/Providers/Rackspace/ProviderBase.cs @@ -104,7 +104,7 @@ internal JsonRequestSettings BuildDefaultRequestSettings(IEnumerable non200 protected virtual string GetServiceEndpoint(CloudIdentity identity, string serviceName, string region = null) { - var userAccess = _identityProvider.Authenticate(identity); + var userAccess = _identityProvider.GetUserAccess(identity); if (userAccess == null || userAccess.ServiceCatalog == null) throw new UserAuthenticationException("Unable to authenticate user and retrieve authorized service endpoints"); @@ -144,6 +144,8 @@ internal static void CheckResponse(Response response) throw new ServiceLimitReachedException(response); case 500: throw new ServiceFaultException(response); + case 501: + throw new MethodNotImplementedException(response); case 503: throw new ServiceUnavailableException(response); } diff --git a/src/corelib/corelib.csproj b/src/corelib/corelib.csproj index f9c1ac245..7d62c1994 100644 --- a/src/corelib/corelib.csproj +++ b/src/corelib/corelib.csproj @@ -61,10 +61,12 @@ + + diff --git a/src/testing/integration/Bootstrapper.cs b/src/testing/integration/Bootstrapper.cs index fe77328f1..894d09964 100644 --- a/src/testing/integration/Bootstrapper.cs +++ b/src/testing/integration/Bootstrapper.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using net.openstack.Core.Domain; @@ -9,25 +7,15 @@ namespace Net.OpenStack.Testing.Integration { public class Bootstrapper { - private static CloudIdentity _testIdentity; - public static CloudIdentity TestIdentity + private static OpenstackNetSetings _settings; + public static OpenstackNetSetings Settings { get { - if(_testIdentity == null) + if(_settings == null) Initialize(); - return _testIdentity; - } - } - private static CloudIdentity _testAdminIdentity; - public static CloudIdentity TestAdminIdentity - { - get - { - if (_testAdminIdentity == null) - Initialize(); - return _testAdminIdentity; + return _settings; } } @@ -37,27 +25,34 @@ public static void Initialize() var path = Path.Combine(homeDir, ".openstack_net"); - string contents; + var contents = new StringBuilder(); using(var stream = File.Open(path, FileMode.Open, FileAccess.Read)) { using(var reader = new StreamReader(stream)) { - contents = reader.ReadToEnd(); + while (!reader.EndOfStream) + { + var line = reader.ReadLine(); + if(!line.Trim().StartsWith("//")) + contents.Append(line); + } } } - var appCredentials = Newtonsoft.Json.JsonConvert.DeserializeObject(contents); + var appCredentials = Newtonsoft.Json.JsonConvert.DeserializeObject(contents.ToString()); - _testIdentity = appCredentials.TestIdentity; - _testAdminIdentity = appCredentials.TestAdminIdentity; + _settings = appCredentials; } } - public class OpenstackNetCredencials + public class OpenstackNetSetings { public CloudIdentity TestIdentity { get; set; } public CloudIdentity TestAdminIdentity { get; set; } + + public string RackspaceExtendedIdentityUSUrl { get; set; } + public string RackspaceExtendedIdentityUKUrl { get; set; } } } diff --git a/src/testing/integration/Providers/Rackspace/ComputeFull.orderedtest b/src/testing/integration/Providers/Rackspace/ComputeFull.orderedtest index dc7513a5b..884d95805 100644 --- a/src/testing/integration/Providers/Rackspace/ComputeFull.orderedtest +++ b/src/testing/integration/Providers/Rackspace/ComputeFull.orderedtest @@ -1,5 +1,5 @@  - + @@ -9,20 +9,28 @@ + + + + + + + + diff --git a/src/testing/integration/Providers/Rackspace/ComputeTests.cs b/src/testing/integration/Providers/Rackspace/ComputeTests.cs index dc4f256fa..07d201faf 100644 --- a/src/testing/integration/Providers/Rackspace/ComputeTests.cs +++ b/src/testing/integration/Providers/Rackspace/ComputeTests.cs @@ -15,11 +15,6 @@ namespace Net.OpenStack.Testing.Integration.Providers.Rackspace [TestClass] public class ComputeTests { - public ComputeTests() - { - _testIdentity = new RackspaceCloudIdentity(Bootstrapper.TestIdentity); - } - private TestContext testContextInstance; private static CloudIdentity _testIdentity; private static NewServer _testServer; @@ -42,6 +37,12 @@ public TestContext TestContext } } + [ClassInitialize] + public static void Init(TestContext context) + { + _testIdentity = new RackspaceCloudIdentity(Bootstrapper.Settings.TestIdentity); + } + [TestMethod] public void Test001_Should_Create_A_New_Server_In_DFW() { @@ -61,23 +62,15 @@ public void Test002_Should_Get_Details_For_Newly_Created_Server_In_DFW() Assert.IsNotNull(serverDetails); Assert.AreEqual("net-sdk-test-server", serverDetails.Name); Assert.AreEqual("d531a2dd-7ae9-4407-bb5a-e5ea03303d98", serverDetails.Image.Id); - Assert.AreEqual("2", serverDetails.Flavor.Id); + Assert.AreEqual("2", serverDetails.Flavor.Id); } [TestMethod] public void Test003_Should_Wait_Until_Server_Becomes_Active_Or_A_Maximum_Of_10_Minutes() { var provider = new net.openstack.Providers.Rackspace.ComputeProvider(); - var serverDetails = provider.GetDetails(_testIdentity, _testServer.Id); - Assert.IsNotNull(serverDetails); - int count = 0; - while (!serverDetails.Status.Equals("ACTIVE") && !serverDetails.Status.Equals("ERROR") && !serverDetails.Status.Equals("UNKNOWN") && !serverDetails.Status.Equals("SUSPENDED") && count < 600) - { - Thread.Sleep(2400); - serverDetails = provider.GetDetails(_testIdentity, _testServer.Id); - count++; - } + var serverDetails = provider.WaitForServerActive(_testIdentity, _testServer.Id); Assert.IsNotNull(serverDetails); Assert.AreEqual("ACTIVE", serverDetails.Status); @@ -134,9 +127,9 @@ public void Test008_Should_Get_The_Initial_Test_Server_Metadata() Assert.IsNotNull(metadata); Assert.IsTrue(metadata.Count == 2); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_1")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_1").Value == "My_Value_1"); + Assert.AreEqual("My_Value_1", metadata.First(md => md.Key == "Metadata_Key_1").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_2")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_2").Value == "My_Value_2"); + Assert.AreEqual("My_Value_2", metadata.First(md => md.Key == "Metadata_Key_2").Value); } [TestMethod] @@ -158,9 +151,9 @@ public void Test010_Should_Get_The_Update_Reset_Test_Server_Metadata() Assert.IsNotNull(metadata); Assert.IsTrue(metadata.Count == 2); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_3")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_3").Value == "My_Value_3"); + Assert.AreEqual("My_Value_3", metadata.First(md => md.Key == "Metadata_Key_3").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_4")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_4").Value == "My_Value_4"); + Assert.AreEqual("My_Value_4", metadata.First(md => md.Key == "Metadata_Key_4").Value); } [TestMethod] @@ -170,6 +163,7 @@ public void Test011_Should_Set_Update_All_Server_Metadata_Items() var metadata = new Metadata() { { "Metadata_Key_3", "My_Value_3_Updated" }, { "Metadata_Key_4", "My_Value_4_Updated" } }; var response = provider.UpdateServerMetadata(_testIdentity, _testServer.Id, metadata); + Thread.Sleep(10000); // Sleep a few seconds because there is an edge case that the system does not reflect the new metadata changes quick enough Assert.IsTrue(response); } @@ -182,9 +176,9 @@ public void Test012_Should_Get_The_Updated_Test_Server_Metadata() Assert.IsNotNull(metadata); Assert.IsTrue(metadata.Count == 2); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_3")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_3").Value == "My_Value_3_Updated"); + Assert.AreEqual("My_Value_3_Updated", metadata.First(md => md.Key == "Metadata_Key_3").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_4")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_4").Value == "My_Value_4_Updated"); + Assert.AreEqual("My_Value_4_Updated", metadata.First(md => md.Key == "Metadata_Key_4").Value); } [TestMethod] @@ -205,11 +199,11 @@ public void Test014_Should_Get_The_Test_Server_Metadata_Including_The_New_Item() Assert.IsNotNull(metadata); Assert.IsTrue(metadata.Count == 3); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_3")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_3").Value == "My_Value_3_Updated"); + Assert.AreEqual("My_Value_3_Updated", metadata.First(md => md.Key == "Metadata_Key_3").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_4")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_4").Value == "My_Value_4_Updated"); + Assert.AreEqual("My_Value_4_Updated", metadata.First(md => md.Key == "Metadata_Key_4").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_5")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_5").Value == "My_Value_5"); + Assert.AreEqual("My_Value_5", metadata.First(md => md.Key == "Metadata_Key_5").Value); } [TestMethod] @@ -231,11 +225,11 @@ public void Test016_Should_Get_The_Updated_Test_Server_Metadata_Including_The_Up Assert.IsNotNull(metadata); Assert.IsTrue(metadata.Count == 3); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_3")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_3").Value == "My_Value_3_Updated_Again"); + Assert.AreEqual("My_Value_3_Updated_Again", metadata.First(md => md.Key == "Metadata_Key_3").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_4")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_4").Value == "My_Value_4_Updated"); + Assert.AreEqual("My_Value_4_Updated", metadata.First(md => md.Key == "Metadata_Key_4").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_5")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_5").Value == "My_Value_5_Updated"); + Assert.AreEqual("My_Value_5_Updated", metadata.First(md => md.Key == "Metadata_Key_5").Value); } [TestMethod] @@ -256,11 +250,11 @@ public void Test018_Should_Get_The_Updated_Test_Server_Metadata_Including_The_Up Assert.IsNotNull(metadata); Assert.IsTrue(metadata.Count == 3); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_3")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_3").Value == "My_Value_3_Updated_Again"); + Assert.AreEqual("My_Value_3_Updated_Again", metadata.First(md => md.Key == "Metadata_Key_3").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_4")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_4").Value == "My_Value_4_Updated_Again"); + Assert.AreEqual("My_Value_4_Updated_Again", metadata.First(md => md.Key == "Metadata_Key_4").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_5")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_5").Value == "My_Value_5_Updated"); + Assert.AreEqual("My_Value_5_Updated", metadata.First(md => md.Key == "Metadata_Key_5").Value); } [TestMethod] @@ -281,9 +275,9 @@ public void Test020_Should_Get_The_Updated_Test_Server_Metadata_Excluding_The_De Assert.IsNotNull(metadata); Assert.IsTrue(metadata.Count == 2); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_3")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_3").Value == "My_Value_3_Updated_Again"); + Assert.AreEqual("My_Value_3_Updated_Again", metadata.First(md => md.Key == "Metadata_Key_3").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_5")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_5").Value == "My_Value_5_Updated"); + Assert.AreEqual("My_Value_5_Updated", metadata.First(md => md.Key == "Metadata_Key_5").Value); } [TestMethod] @@ -305,11 +299,11 @@ public void Test022_Should_Get_The_Updated_Test_Server_Metadata() Assert.IsNotNull(metadata); Assert.IsTrue(metadata.Count == 3); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_3")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_3").Value == "My_Value_3_Updated_Again"); + Assert.AreEqual("My_Value_3_Updated_Again", metadata.First(md => md.Key == "Metadata_Key_3").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_4")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_4").Value == "My_Value_4"); + Assert.AreEqual("My_Value_4", metadata.First(md => md.Key == "Metadata_Key_4").Value); Assert.IsTrue(metadata.Any(md => md.Key == "Metadata_Key_5")); - Assert.IsTrue(metadata.First(md => md.Key == "Metadata_Key_5").Value == "My_Value_5_Updated_Again"); + Assert.AreEqual("My_Value_5_Updated_Again", metadata.First(md => md.Key == "Metadata_Key_5").Value); } [TestMethod] @@ -393,7 +387,7 @@ public void Test029_Should_Get_List_All_Images_With_Details() [TestMethod] public void Test030_Should_Return_One_Image_When_Searching_By_Valid_Id() { - var validImage = _allImages.First(); + var validImage = _allImages.First(i => i.Server != null); var provider = new net.openstack.Providers.Rackspace.ComputeProvider(); var images = provider.ListImages(_testIdentity, serverId: validImage.Server.Id); @@ -433,7 +427,7 @@ public void Test033_Should_Return_At_Least_One_Image_When_Searching_By_Valid_Cha [TestMethod] public void Test034_Should_Return_One_Image_With_Details_When_Searching_By_Valid_Id() { - var validImage = _allImages.First(); + var validImage = _allImages.First(i => i.Server != null); var provider = new net.openstack.Providers.Rackspace.ComputeProvider(); var images = provider.ListImagesWithDetails(_testIdentity, serverId: validImage.Server.Id); @@ -510,7 +504,11 @@ public void Test041_Should_Return_All_Images_With_Details_When_Using_A_Limit_Gre Assert.IsTrue(images.Count() == _allImages.Count()); } - + [TestMethod] + public void Test042_Should_Wait_For_Image_To_Be_ACTIVE() + { + + } @@ -542,14 +540,8 @@ public void Test100_Should_Mark_The_Server_For_Deletion() public void Test101_Should_Wait_A_Max_Of_10_Minutes_For_The_Server_Is_Deleted_Indicated_By_A_Null_Return_Value_For_Details() { var provider = new net.openstack.Providers.Rackspace.ComputeProvider(); - var details = provider.GetDetails(_testIdentity, _testServer.Id); - Assert.IsNotNull(details); - - while (details != null && (!details.Status.Equals("DELETED") && !details.Status.Equals("ERROR") && !details.Status.Equals("UNKNOWN") && !details.Status.Equals("SUSPENDED"))) - { - Thread.Sleep(1000); - details = provider.GetDetails(_testIdentity, _testServer.Id); - } + + var details = provider.WaitForServerDeleted(_testIdentity, _testServer.Id); if(details != null) Assert.AreEqual("DELETED", details.Status); diff --git a/src/testing/integration/Providers/Rackspace/ExtendedIdentityFull.orderedtest b/src/testing/integration/Providers/Rackspace/ExtendedIdentityFull.orderedtest new file mode 100644 index 000000000..55ff0ef88 --- /dev/null +++ b/src/testing/integration/Providers/Rackspace/ExtendedIdentityFull.orderedtest @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/testing/integration/Providers/Rackspace/ExtendedIdentityTests.cs b/src/testing/integration/Providers/Rackspace/ExtendedIdentityTests.cs new file mode 100644 index 000000000..081e44e61 --- /dev/null +++ b/src/testing/integration/Providers/Rackspace/ExtendedIdentityTests.cs @@ -0,0 +1,191 @@ +using System; +using System.Text; +using System.Collections.Generic; +using System.Linq; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using SimpleRestServices.Client; +using net.openstack; +using net.openstack.Core.Domain; +using net.openstack.Core.Exceptions.Response; +using net.openstack.Providers.Rackspace; + +namespace Net.OpenStack.Testing.Integration.Providers.Rackspace +{ + [TestClass] + public class ExtendedIdentityTests + { + private TestContext testContextInstance; + private static RackspaceCloudIdentity _testIdentity; + private static RackspaceCloudIdentity _testAdminIdentity; + private static User _userDetails; + private static User _adminUserDetails; + private const string NewPassword = "My_n3w_p@$$w0rd"; + private const string AdminNewPassword = "My_n3w_@dmin_p@$$w0rd"; + private static string _newAPIKey; + private static string _adminNewAPIKey; + + /// + ///Gets or sets the test context which provides + ///information about and functionality for the current test run. + /// + public TestContext TestContext + { + get + { + return testContextInstance; + } + set + { + testContextInstance = value; + } + } + + [ClassInitialize] + public static void Init(TestContext context) + { + _testIdentity = new RackspaceCloudIdentity(Bootstrapper.Settings.TestIdentity); + _testAdminIdentity = new RackspaceCloudIdentity(Bootstrapper.Settings.TestAdminIdentity); + + _newAPIKey = Guid.NewGuid().ToString(); + _adminNewAPIKey = Guid.NewGuid().ToString(); + + var provider = BuildProvider(); + + _userDetails = provider.GetUserByName(_testIdentity, _testIdentity.Username); + _adminUserDetails = provider.GetUserByName(_testAdminIdentity, _testAdminIdentity.Username); + } + + private static IExtendedIdentityProvider BuildProvider(IRestService restService = null, ICache cache = null) + { + return new IdentityProvider(restService, cache, Bootstrapper.Settings.RackspaceExtendedIdentityUSUrl, Bootstrapper.Settings.RackspaceExtendedIdentityUKUrl); + } + + [TestMethod] + public void Test001_Should_Throw_Exception_When_Trying_To_Change_Password_For_Self_When_Changeing_Password_As_Non_Admin_Identity() + { + var provider = BuildProvider(); + + try + { + var result = provider.SetUserPassword(_testIdentity, _userDetails, NewPassword); + + throw new Exception("This code path is invalid, exception was expected."); + } + catch(ResponseException ex) + { + Assert.IsTrue(true); + } + } + + [TestMethod] + public void Test002_Should_Throw_Exception_When_Trying_To_Change_Password_For_Other_User_When_Changeing_Password_As_Non_Admin_Identity() + { + var provider = BuildProvider(); + + try + { + var result = provider.SetUserPassword(_testIdentity, _adminUserDetails, AdminNewPassword); + + throw new Exception("This code path is invalid, exception was expected."); + } + catch (ResponseException ex) + { + Assert.IsTrue(true); + } + } + + [TestMethod] + public void Test003_Should_Change_Password_For_Self_When_Changeing_Password_As_Admin_Identity() + { + var provider = BuildProvider(); + + var result = provider.SetUserPassword(_testAdminIdentity, _adminUserDetails, AdminNewPassword); + + Assert.IsTrue(result); + } + + [TestMethod] + public void Test004_Should_Successfully_Authenticate_With_New_Password_For_Admin_User() + { + var provider = BuildProvider(); + + var userAcess = + provider.Authenticate(new RackspaceCloudIdentity + { + Username = _testAdminIdentity.Username, + Password = AdminNewPassword, + CloudInstance = _testAdminIdentity.CloudInstance + }); + + Assert.IsNotNull(userAcess); + } + + [TestMethod] + public void Test005_Should_Change_Password_Back_For_Self_When_Changeing_Password_As_Admin_Identity() + { + var provider = BuildProvider(); + + var result = provider.SetUserPassword(_testAdminIdentity, _adminUserDetails, _testAdminIdentity.Password); + + Assert.IsTrue(result); + } + + [TestMethod] + public void Test006_Should_Successfully_Authenticate_With_Old_Password_For_Admin_User() + { + var provider = BuildProvider(); + + var userAcess = + provider.Authenticate(_testAdminIdentity); + + Assert.IsNotNull(userAcess); + } + + [TestMethod] + public void Test007_Should_Change_Password_For_Other_User_When_Changeing_Password_As_Admin_Identity() + { + var provider = BuildProvider(); + + var result = provider.SetUserPassword(_testAdminIdentity, _adminUserDetails, AdminNewPassword); + + Assert.IsTrue(result); + } + + [TestMethod] + public void Test008_Should_Successfully_Authenticate_With_New_Password_For_Non_Admin_User() + { + var provider = BuildProvider(); + + var userAcess = + provider.Authenticate(new RackspaceCloudIdentity + { + Username = _testAdminIdentity.Username, + Password = AdminNewPassword, + CloudInstance = _testAdminIdentity.CloudInstance + }); + + Assert.IsNotNull(userAcess); + } + + [TestMethod] + public void Test009_Should_Change_Password_Back_For_Other_User_When_Changeing_Password_As_Admin_Identity() + { + var provider = BuildProvider(); + + var result = provider.SetUserPassword(_testAdminIdentity, _adminUserDetails, _testAdminIdentity.Password); + + Assert.IsTrue(result); + } + + [TestMethod] + public void Test010_Should_Successfully_Authenticate_With_Old_Password_For_Non_Admin_User() + { + var provider = BuildProvider(); + + var userAcess = + provider.Authenticate(_testAdminIdentity); + + Assert.IsNotNull(userAcess); + } + } +} diff --git a/src/testing/integration/Providers/Rackspace/Full.orderedtest b/src/testing/integration/Providers/Rackspace/Full.orderedtest index f5fa6b5ca..a3e4334ea 100644 --- a/src/testing/integration/Providers/Rackspace/Full.orderedtest +++ b/src/testing/integration/Providers/Rackspace/Full.orderedtest @@ -1,7 +1,8 @@  - + + \ No newline at end of file diff --git a/src/testing/integration/Providers/Rackspace/IdentityTests.cs b/src/testing/integration/Providers/Rackspace/IdentityTests.cs index fa945851d..22142e8d7 100644 --- a/src/testing/integration/Providers/Rackspace/IdentityTests.cs +++ b/src/testing/integration/Providers/Rackspace/IdentityTests.cs @@ -1,6 +1,4 @@ using System; -using System.Text; -using System.Collections.Generic; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using net.openstack.Core; @@ -12,12 +10,6 @@ namespace Net.OpenStack.Testing.Integration.Providers.Rackspace [TestClass] public class IdentityTests { - public IdentityTests() - { - _testIdentity = new RackspaceCloudIdentity(Bootstrapper.TestIdentity); - _testAdminIdentity = new RackspaceCloudIdentity(Bootstrapper.TestAdminIdentity); - } - private TestContext testContextInstance; private static RackspaceCloudIdentity _testIdentity; private static RackspaceCloudIdentity _testAdminIdentity; @@ -41,6 +33,13 @@ public TestContext TestContext } } + [ClassInitialize] + public static void Init(TestContext context) + { + _testIdentity = new RackspaceCloudIdentity(Bootstrapper.Settings.TestIdentity); + _testAdminIdentity = new RackspaceCloudIdentity(Bootstrapper.Settings.TestAdminIdentity); + } + [TestMethod] public void Should_Authenticate_Test_Identity() { diff --git a/src/testing/integration/integration.csproj b/src/testing/integration/integration.csproj index ed9483dd2..6d42526fa 100644 --- a/src/testing/integration/integration.csproj +++ b/src/testing/integration/integration.csproj @@ -62,6 +62,7 @@ + @@ -82,6 +83,9 @@ Always + + Always +