diff --git a/Contentstack.Management.Core.Tests/Contentstack.cs b/Contentstack.Management.Core.Tests/Contentstack.cs index e69153c..7ff2492 100644 --- a/Contentstack.Management.Core.Tests/Contentstack.cs +++ b/Contentstack.Management.Core.Tests/Contentstack.cs @@ -16,17 +16,6 @@ namespace Contentstack.Management.Core.Tests { public class Contentstack { - private static readonly Lazy - client = - new Lazy(() => - { - ContentstackClientOptions options = Config.GetSection("Contentstack").Get(); - var handler = new LoggingHttpHandler(); - var httpClient = new HttpClient(handler); - return new ContentstackClient(httpClient, options); - }); - - private static readonly Lazy config = new Lazy(() => @@ -46,13 +35,28 @@ private static readonly Lazy return Config.GetSection("Contentstack:Organization").Get(); }); - public static ContentstackClient Client { get { return client.Value; } } public static IConfigurationRoot Config{ get { return config.Value; } } public static NetworkCredential Credential { get { return credential.Value; } } public static OrganizationModel Organization { get { return organization.Value; } } public static StackModel Stack { get; set; } + /// + /// Creates a new ContentstackClient, logs in via the Login API (never from config), + /// and returns the authenticated client. Callers are responsible for calling Logout() + /// when done. + /// + public static ContentstackClient CreateAuthenticatedClient() + { + ContentstackClientOptions options = Config.GetSection("Contentstack").Get(); + options.Authtoken = null; + var handler = new LoggingHttpHandler(); + var httpClient = new HttpClient(handler); + var client = new ContentstackClient(httpClient, options); + client.Login(Credential); + return client; + } + public static T serialize(JsonSerializer serializer, string filePath) { string response = GetResourceText(filePath); diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack001_LoginTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack001_LoginTest.cs index eef6538..766dd7b 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack001_LoginTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack001_LoginTest.cs @@ -5,9 +5,6 @@ using Contentstack.Management.Core.Models; using Contentstack.Management.Core.Tests.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Options; -using System.Threading; using Contentstack.Management.Core.Queryable; using Newtonsoft.Json.Linq; @@ -16,7 +13,6 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack001_LoginTest { - private readonly IConfigurationRoot _configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build(); private static ContentstackClient CreateClientWithLogging() { @@ -48,25 +44,24 @@ public void Test001_Should_Return_Failuer_On_Wrong_Login_Credentials() [TestMethod] [DoNotParallelize] - public void Test002_Should_Return_Failuer_On_Wrong_Async_Login_Credentials() + public async System.Threading.Tasks.Task Test002_Should_Return_Failuer_On_Wrong_Async_Login_Credentials() { TestOutputLogger.LogContext("TestScenario", "WrongCredentialsAsync"); ContentstackClient client = CreateClientWithLogging(); NetworkCredential credentials = new NetworkCredential("mock_user", "mock_pasword"); - var response = client.LoginAsync(credentials); - - response.ContinueWith((t) => - { - if (t.IsCompleted && t.Status == System.Threading.Tasks.TaskStatus.Faulted) - { - ContentstackErrorException errorException = t.Exception.InnerException as ContentstackErrorException; - AssertLogger.AreEqual(HttpStatusCode.UnprocessableEntity, errorException.StatusCode, "StatusCode"); - AssertLogger.AreEqual("Looks like your email or password is invalid. Please try again or reset your password.", errorException.Message, "Message"); - AssertLogger.AreEqual("Looks like your email or password is invalid. Please try again or reset your password.", errorException.ErrorMessage, "ErrorMessage"); - AssertLogger.AreEqual(104, errorException.ErrorCode, "ErrorCode"); - } - }); - Thread.Sleep(3000); + + try + { + await client.LoginAsync(credentials); + AssertLogger.Fail("Expected exception for wrong credentials"); + } + catch (ContentstackErrorException errorException) + { + AssertLogger.AreEqual(HttpStatusCode.UnprocessableEntity, errorException.StatusCode, "StatusCode"); + AssertLogger.AreEqual("Looks like your email or password is invalid. Please try again or reset your password.", errorException.Message, "Message"); + AssertLogger.AreEqual("Looks like your email or password is invalid. Please try again or reset your password.", errorException.ErrorMessage, "ErrorMessage"); + AssertLogger.AreEqual(104, errorException.ErrorCode, "ErrorCode"); + } } [TestMethod] @@ -304,5 +299,198 @@ public void Test011_Should_Prefer_Explicit_Token_Over_MfaSecret() AssertLogger.Fail($"Unexpected exception type: {e.GetType().Name} - {e.Message}"); } } + + [TestMethod] + [DoNotParallelize] + public void Test012_Should_Throw_InvalidOperation_When_Already_LoggedIn_Sync() + { + TestOutputLogger.LogContext("TestScenario", "AlreadyLoggedInSync"); + ContentstackClient client = CreateClientWithLogging(); + + try + { + client.Login(Contentstack.Credential); + AssertLogger.IsNotNull(client.contentstackOptions.Authtoken, "Authtoken"); + + AssertLogger.ThrowsException(() => + client.Login(Contentstack.Credential), "AlreadyLoggedIn"); + + client.Logout(); + } + catch (Exception e) + { + AssertLogger.Fail($"Unexpected exception: {e.GetType().Name} - {e.Message}"); + } + } + + [TestMethod] + [DoNotParallelize] + public async System.Threading.Tasks.Task Test013_Should_Throw_InvalidOperation_When_Already_LoggedIn_Async() + { + TestOutputLogger.LogContext("TestScenario", "AlreadyLoggedInAsync"); + ContentstackClient client = CreateClientWithLogging(); + + try + { + await client.LoginAsync(Contentstack.Credential); + AssertLogger.IsNotNull(client.contentstackOptions.Authtoken, "Authtoken"); + + await System.Threading.Tasks.Task.Run(() => + AssertLogger.ThrowsException(() => + client.LoginAsync(Contentstack.Credential).GetAwaiter().GetResult(), "AlreadyLoggedInAsync")); + + await client.LogoutAsync(); + } + catch (Exception e) + { + AssertLogger.Fail($"Unexpected exception: {e.GetType().Name} - {e.Message}"); + } + } + + [TestMethod] + [DoNotParallelize] + public void Test014_Should_Throw_ArgumentNullException_For_Null_Credentials_Sync() + { + TestOutputLogger.LogContext("TestScenario", "NullCredentialsSync"); + ContentstackClient client = CreateClientWithLogging(); + + AssertLogger.ThrowsException(() => + client.Login(null), "NullCredentials"); + } + + [TestMethod] + [DoNotParallelize] + public void Test015_Should_Throw_ArgumentNullException_For_Null_Credentials_Async() + { + TestOutputLogger.LogContext("TestScenario", "NullCredentialsAsync"); + ContentstackClient client = CreateClientWithLogging(); + + AssertLogger.ThrowsException(() => + client.LoginAsync(null).GetAwaiter().GetResult(), "NullCredentialsAsync"); + } + + [TestMethod] + [DoNotParallelize] + public async System.Threading.Tasks.Task Test016_Should_Throw_ArgumentException_For_Invalid_MfaSecret_Async() + { + TestOutputLogger.LogContext("TestScenario", "InvalidMfaSecretAsync"); + ContentstackClient client = CreateClientWithLogging(); + NetworkCredential credentials = new NetworkCredential("test_user", "test_password"); + string invalidMfaSecret = "INVALID_BASE32_SECRET!@#"; + + try + { + await client.LoginAsync(credentials, null, invalidMfaSecret); + AssertLogger.Fail("Expected ArgumentException for invalid MFA secret"); + } + catch (ArgumentException) + { + AssertLogger.IsTrue(true, "ArgumentException thrown as expected for async"); + } + catch (Exception e) + { + AssertLogger.Fail($"Unexpected exception type: {e.GetType().Name} - {e.Message}"); + } + } + + [TestMethod] + [DoNotParallelize] + public void Test017_Should_Handle_Valid_Credentials_With_TfaToken_Sync() + { + TestOutputLogger.LogContext("TestScenario", "WrongTfaTokenSync"); + ContentstackClient client = CreateClientWithLogging(); + + try + { + client.Login(Contentstack.Credential, "000000"); + // Account does not have 2FA enabled — tfa_token is ignored by the API and login succeeds. + // This is a valid outcome; assert token is set and clean up. + AssertLogger.IsNotNull(client.contentstackOptions.Authtoken, "Authtoken"); + client.Logout(); + } + catch (ContentstackErrorException errorException) + { + // Account has 2FA enabled — wrong token is correctly rejected with 422. + AssertLogger.AreEqual(HttpStatusCode.UnprocessableEntity, errorException.StatusCode, "StatusCode"); + AssertLogger.IsTrue(errorException.ErrorCode > 0, "TfaErrorCode"); + } + catch (Exception e) + { + AssertLogger.Fail($"Unexpected exception type: {e.GetType().Name} - {e.Message}"); + } + } + + [TestMethod] + [DoNotParallelize] + public async System.Threading.Tasks.Task Test018_Should_Handle_Valid_Credentials_With_TfaToken_Async() + { + TestOutputLogger.LogContext("TestScenario", "WrongTfaTokenAsync"); + ContentstackClient client = CreateClientWithLogging(); + + try + { + await client.LoginAsync(Contentstack.Credential, "000000"); + // Account does not have 2FA enabled — tfa_token is ignored by the API and login succeeds. + // This is a valid outcome; assert token is set and clean up. + AssertLogger.IsNotNull(client.contentstackOptions.Authtoken, "Authtoken"); + await client.LogoutAsync(); + } + catch (ContentstackErrorException errorException) + { + // Account has 2FA enabled — wrong token is correctly rejected with 422. + AssertLogger.AreEqual(HttpStatusCode.UnprocessableEntity, errorException.StatusCode, "StatusCode"); + AssertLogger.IsTrue(errorException.ErrorCode > 0, "TfaErrorCodeAsync"); + } + catch (Exception e) + { + AssertLogger.Fail($"Unexpected exception type: {e.GetType().Name} - {e.Message}"); + } + } + + [TestMethod] + [DoNotParallelize] + public void Test019_Should_Not_Include_TfaToken_When_MfaSecret_Is_Empty_Sync() + { + TestOutputLogger.LogContext("TestScenario", "EmptyMfaSecretSync"); + ContentstackClient client = CreateClientWithLogging(); + NetworkCredential credentials = new NetworkCredential("mock_user", "mock_password"); + + try + { + client.Login(credentials, null, ""); + } + catch (ContentstackErrorException errorException) + { + AssertLogger.AreEqual(HttpStatusCode.UnprocessableEntity, errorException.StatusCode, "StatusCode"); + AssertLogger.AreEqual(104, errorException.ErrorCode, "ErrorCode"); + } + catch (Exception e) + { + AssertLogger.Fail($"Unexpected exception type: {e.GetType().Name} - {e.Message}"); + } + } + + [TestMethod] + [DoNotParallelize] + public async System.Threading.Tasks.Task Test020_Should_Not_Include_TfaToken_When_MfaSecret_Is_Null_Async() + { + TestOutputLogger.LogContext("TestScenario", "NullMfaSecretAsync"); + ContentstackClient client = CreateClientWithLogging(); + NetworkCredential credentials = new NetworkCredential("mock_user", "mock_password"); + + try + { + await client.LoginAsync(credentials, null, null); + } + catch (ContentstackErrorException errorException) + { + AssertLogger.AreEqual(HttpStatusCode.UnprocessableEntity, errorException.StatusCode, "StatusCode"); + AssertLogger.AreEqual(104, errorException.ErrorCode, "ErrorCode"); + } + catch (Exception e) + { + AssertLogger.Fail($"Unexpected exception type: {e.GetType().Name} - {e.Message}"); + } + } } } diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack002_OrganisationTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack002_OrganisationTest.cs index 3d0d1d1..354278a 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack002_OrganisationTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack002_OrganisationTest.cs @@ -13,6 +13,7 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack002_OrganisationTest { + private static ContentstackClient _client; private double _count; static string RoleUID = ""; static string EmailSync = "testcs@contentstack.com"; @@ -21,6 +22,19 @@ public class Contentstack002_OrganisationTest static string InviteIDAsync = ""; private readonly IFixture _fixture = new Fixture(); + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + try { _client?.Logout(); } catch { } + _client = null; + } + [TestMethod] [DoNotParallelize] public void Test001_Should_Return_All_Organizations() @@ -28,7 +42,7 @@ public void Test001_Should_Return_All_Organizations() TestOutputLogger.LogContext("TestScenario", "GetAllOrganizations"); try { - Organization organization = Contentstack.Client.Organization(); + Organization organization = _client.Organization(); ContentstackResponse contentstackResponse = organization.GetOrganizations(); @@ -50,7 +64,7 @@ public async System.Threading.Tasks.Task Test002_Should_Return_All_Organizations TestOutputLogger.LogContext("TestScenario", "GetAllOrganizationsAsync"); try { - Organization organization = Contentstack.Client.Organization(); + Organization organization = _client.Organization(); ContentstackResponse contentstackResponse = await organization.GetOrganizationsAsync(); @@ -73,7 +87,7 @@ public void Test003_Should_Return_With_Skipping_Organizations() TestOutputLogger.LogContext("TestScenario", "SkipOrganizations"); try { - Organization organization = Contentstack.Client.Organization(); + Organization organization = _client.Organization(); ParameterCollection collection = new ParameterCollection(); collection.Add("skip", 4); ContentstackResponse contentstackResponse = organization.GetOrganizations(collection); @@ -98,7 +112,7 @@ public void Test004_Should_Return_Organization_With_UID() { var org = Contentstack.Organization; TestOutputLogger.LogContext("OrganizationUid", org.Uid); - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = organization.GetOrganizations(); @@ -124,7 +138,7 @@ public void Test005_Should_Return_Organization_With_UID_Include_Plan() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ParameterCollection collection = new ParameterCollection(); collection.Add("include_plan", true); @@ -150,7 +164,7 @@ public void Test006_Should_Return_Organization_Roles() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = organization.Roles(); @@ -175,7 +189,7 @@ public async System.Threading.Tasks.Task Test007_Should_Return_Organization_Role try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = await organization.RolesAsync(); @@ -198,7 +212,7 @@ public void Test008_Should_Add_User_To_Organization() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); UserInvitation invitation = new UserInvitation() { Email = EmailSync, @@ -230,7 +244,7 @@ public async System.Threading.Tasks.Task Test009_Should_Add_User_To_Organization try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); UserInvitation invitation = new UserInvitation() { Email = EmailAsync, @@ -261,7 +275,7 @@ public void Test010_Should_Resend_Invite() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = organization.ResendInvitation(InviteID); @@ -284,7 +298,7 @@ public async System.Threading.Tasks.Task Test011_Should_Resend_Invite() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = await organization.ResendInvitationAsync(InviteIDAsync); var response = contentstackResponse.OpenJObjectResponse(); @@ -306,7 +320,7 @@ public void Test012_Should_Remove_User_From_Organization() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = organization.RemoveUser(new System.Collections.Generic.List() { EmailSync } ); @@ -329,7 +343,7 @@ public async System.Threading.Tasks.Task Test013_Should_Remove_User_From_Organiz try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = await organization.RemoveUserAsync(new System.Collections.Generic.List() { EmailAsync }); var response = contentstackResponse.OpenJObjectResponse(); @@ -351,7 +365,7 @@ public void Test014_Should_Get_All_Invites() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = organization.GetInvitations(); @@ -376,7 +390,7 @@ public async System.Threading.Tasks.Task Test015_Should_Get_All_Invites_Async() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = await organization.GetInvitationsAsync(); var response = contentstackResponse.OpenJObjectResponse(); @@ -399,7 +413,7 @@ public void Test016_Should_Get_All_Stacks() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = organization.GetStacks(); @@ -424,7 +438,7 @@ public async System.Threading.Tasks.Task Test017_Should_Get_All_Stacks_Async() try { var org = Contentstack.Organization; - Organization organization = Contentstack.Client.Organization(org.Uid); + Organization organization = _client.Organization(org.Uid); ContentstackResponse contentstackResponse = await organization.GetStacksAsync(); var response = contentstackResponse.OpenJObjectResponse(); diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack003_StackTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack003_StackTest.cs index bcfe77b..eb4ba94 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack003_StackTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack003_StackTest.cs @@ -11,6 +11,7 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack003_StackTest { + private static ContentstackClient _client; private readonly string _locale = "en-us"; private string _stackName = "DotNet Management Stack"; private string _updatestackName = "DotNet Management SDK Stack"; @@ -18,6 +19,19 @@ public class Contentstack003_StackTest private OrganizationModel _org = Contentstack.Organization; + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + try { _client?.Logout(); } catch { } + _client = null; + } + [TestMethod] [DoNotParallelize] public void Test001_Should_Return_All_Stacks() @@ -25,7 +39,7 @@ public void Test001_Should_Return_All_Stacks() TestOutputLogger.LogContext("TestScenario", "ReturnAllStacks"); try { - Stack stack = Contentstack.Client.Stack(); + Stack stack = _client.Stack(); ContentstackResponse contentstackResponse = stack.GetAll(); @@ -45,7 +59,7 @@ public async System.Threading.Tasks.Task Test002_Should_Return_All_StacksAsync() TestOutputLogger.LogContext("TestScenario", "ReturnAllStacksAsync"); try { - Stack stack = Contentstack.Client.Stack(); + Stack stack = _client.Stack(); ContentstackResponse contentstackResponse = await stack.GetAllAsync(); @@ -66,7 +80,7 @@ public void Test003_Should_Create_Stack() TestOutputLogger.LogContext("TestScenario", "CreateStack"); try { - Stack stack = Contentstack.Client.Stack(); + Stack stack = _client.Stack(); ContentstackResponse contentstackResponse = stack.Create(_stackName, _locale, _org.Uid); var response = contentstackResponse.OpenJObjectResponse(); @@ -94,7 +108,7 @@ public void Test004_Should_Update_Stack() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); ContentstackResponse contentstackResponse = stack.Update(_updatestackName); var response = contentstackResponse.OpenJObjectResponse(); @@ -124,7 +138,7 @@ public async System.Threading.Tasks.Task Test005_Should_Update_Stack_Async() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); ContentstackResponse contentstackResponse = await stack.UpdateAsync(_updatestackName, _description); var response = contentstackResponse.OpenJObjectResponse(); @@ -152,7 +166,7 @@ public void Test006_Should_Fetch_Stack() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); ContentstackResponse contentstackResponse = stack.Fetch(); var response = contentstackResponse.OpenJObjectResponse(); @@ -179,7 +193,7 @@ public async System.Threading.Tasks.Task Test007_Should_Fetch_StackAsync() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); ContentstackResponse contentstackResponse = await stack.FetchAsync(); var response = contentstackResponse.OpenJObjectResponse(); @@ -206,7 +220,7 @@ public void Test008_Add_Stack_Settings() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); StackSettings settings = new StackSettings() { StackVariables = new Dictionary() @@ -240,7 +254,7 @@ public void Test009_Stack_Settings() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); ContentstackResponse contentstackResponse = stack.Settings(); @@ -266,7 +280,7 @@ public void Test010_Reset_Stack_Settings() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); ContentstackResponse contentstackResponse = stack.ResetSettings(); @@ -292,7 +306,7 @@ public async System.Threading.Tasks.Task Test011_Add_Stack_Settings_Async() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); StackSettings settings = new StackSettings() { Rte = new Dictionary() @@ -324,7 +338,7 @@ public async System.Threading.Tasks.Task Test012_Reset_Stack_Settings_Async() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); ContentstackResponse contentstackResponse = await stack.ResetSettingsAsync(); @@ -350,7 +364,7 @@ public async System.Threading.Tasks.Task Test013_Stack_Settings_Async() TestOutputLogger.LogContext("StackApiKey", Contentstack.Stack.APIKey); try { - Stack stack = Contentstack.Client.Stack(Contentstack.Stack.APIKey); + Stack stack = _client.Stack(Contentstack.Stack.APIKey); ContentstackResponse contentstackResponse = await stack.SettingsAsync(); diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack004_ReleaseTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack004_ReleaseTest.cs index 66f9014..cf5cb53 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack004_ReleaseTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack004_ReleaseTest.cs @@ -14,15 +14,29 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack004_ReleaseTest { + private static ContentstackClient _client; private Stack _stack; private string _testReleaseName = "DotNet SDK Integration Test Release"; private string _testReleaseDescription = "Release created for .NET SDK integration testing"; + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + try { _client?.Logout(); } catch { } + _client = null; + } + [TestInitialize] public async Task Initialize() { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - _stack = Contentstack.Client.Stack(response.Stack.APIKey); + StackResponse response = StackResponse.getStack(_client.serializer); + _stack = _client.Stack(response.Stack.APIKey); } diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack011_GlobalFieldTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack011_GlobalFieldTest.cs index 08f050b..d2d9f84 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack011_GlobalFieldTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack011_GlobalFieldTest.cs @@ -12,14 +12,29 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack004_GlobalFieldTest { + private static ContentstackClient _client; private Stack _stack; private ContentModelling _modelling; + + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + try { _client?.Logout(); } catch { } + _client = null; + } + [TestInitialize] public void Initialize () { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - _stack = Contentstack.Client.Stack(response.Stack.APIKey); - _modelling = Contentstack.serialize(Contentstack.Client.serializer, "globalfield.json"); + StackResponse response = StackResponse.getStack(_client.serializer); + _stack = _client.Stack(response.Stack.APIKey); + _modelling = Contentstack.serialize(_client.serializer, "globalfield.json"); } [TestMethod] diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack012_ContentTypeTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack012_ContentTypeTest.cs index a23d15c..f244d6a 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack012_ContentTypeTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack012_ContentTypeTest.cs @@ -10,17 +10,31 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack005_ContentTypeTest { + private static ContentstackClient _client; private Stack _stack; private ContentModelling _singlePage; private ContentModelling _multiPage; + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + try { _client?.Logout(); } catch { } + _client = null; + } + [TestInitialize] public void Initialize () { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - _stack = Contentstack.Client.Stack(response.Stack.APIKey); - _singlePage = Contentstack.serialize(Contentstack.Client.serializer, "singlepageCT.json"); - _multiPage = Contentstack.serialize(Contentstack.Client.serializer, "multiPageCT.json"); + StackResponse response = StackResponse.getStack(_client.serializer); + _stack = _client.Stack(response.Stack.APIKey); + _singlePage = Contentstack.serialize(_client.serializer, "singlepageCT.json"); + _multiPage = Contentstack.serialize(_client.serializer, "multiPageCT.json"); } [TestMethod] @@ -93,7 +107,7 @@ public void Test005_Should_Update_Content_Type() { TestOutputLogger.LogContext("TestScenario", "UpdateContentType"); TestOutputLogger.LogContext("ContentType", _multiPage.Uid); - _multiPage.Schema = Contentstack.serializeArray>(Contentstack.Client.serializer, "contentTypeSchema.json"); ; + _multiPage.Schema = Contentstack.serializeArray>(_client.serializer, "contentTypeSchema.json"); ; ContentstackResponse response = _stack.ContentType(_multiPage.Uid).Update(_multiPage); ContentTypeModel ContentType = response.OpenTResponse(); AssertLogger.IsNotNull(response, "response"); @@ -113,7 +127,7 @@ public async System.Threading.Tasks.Task Test006_Should_Update_Async_Content_Typ try { // Load the existing schema - _multiPage.Schema = Contentstack.serializeArray>(Contentstack.Client.serializer, "contentTypeSchema.json"); + _multiPage.Schema = Contentstack.serializeArray>(_client.serializer, "contentTypeSchema.json"); // Add a new text field to the schema var newTextField = new Models.Fields.TextboxField diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack012_NestedGlobalFieldTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack012_NestedGlobalFieldTest.cs index 545789a..c0e8f1d 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack012_NestedGlobalFieldTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack012_NestedGlobalFieldTest.cs @@ -15,13 +15,27 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack008_NestedGlobalFieldTest { + private static ContentstackClient _client; private Stack _stack; + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + try { _client?.Logout(); } catch { } + _client = null; + } + [TestInitialize] public void Initialize() { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - _stack = Contentstack.Client.Stack(response.Stack.APIKey); + StackResponse response = StackResponse.getStack(_client.serializer); + _stack = _client.Stack(response.Stack.APIKey); } private ContentModelling CreateReferencedGlobalFieldModel() diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack013_AssetTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack013_AssetTest.cs index 9d21420..2028a7f 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack013_AssetTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack013_AssetTest.cs @@ -18,13 +18,27 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack006_AssetTest { + private static ContentstackClient _client; private Stack _stack; + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + try { _client?.Logout(); } catch { } + _client = null; + } + [TestInitialize] public void Initialize() { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - _stack = Contentstack.Client.Stack(response.Stack.APIKey); + StackResponse response = StackResponse.getStack(_client.serializer); + _stack = _client.Stack(response.Stack.APIKey); } [TestMethod] diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack014_EntryTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack014_EntryTest.cs index 552ba07..93e6b5c 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack014_EntryTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack014_EntryTest.cs @@ -14,13 +14,27 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack007_EntryTest { + private static ContentstackClient _client; private Stack _stack; + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + try { _client?.Logout(); } catch { } + _client = null; + } + [TestInitialize] public void Initialize() { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - _stack = Contentstack.Client.Stack(response.Stack.APIKey); + StackResponse response = StackResponse.getStack(_client.serializer); + _stack = _client.Stack(response.Stack.APIKey); } [TestMethod] diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack015_BulkOperationTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack015_BulkOperationTest.cs index 6d9e573..9c61f86 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack015_BulkOperationTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack015_BulkOperationTest.cs @@ -60,18 +60,21 @@ private static void AssertWorkflowCreated() AssertLogger.IsFalse(string.IsNullOrEmpty(_bulkTestWorkflowStage2Uid), "Workflow Stage 2 (New stage 2) was not set. " + reason, "WorkflowStage2Uid"); } + private static ContentstackClient _client; + /// /// Returns a Stack instance for the test run (used by ClassInitialize/ClassCleanup). /// private static Stack GetStack() { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - return Contentstack.Client.Stack(response.Stack.APIKey); + StackResponse response = StackResponse.getStack(_client.serializer); + return _client.Stack(response.Stack.APIKey); } [ClassInitialize] public static void ClassInitialize(TestContext context) { + _client = Contentstack.CreateAuthenticatedClient(); try { Stack stack = GetStack(); @@ -87,13 +90,15 @@ public static void ClassInitialize(TestContext context) public static void ClassCleanup() { // Intentionally no cleanup: workflow, publish rules, and entries are left so you can verify them in the UI. + try { _client?.Logout(); } catch { } + _client = null; } [TestInitialize] public async Task Initialize() { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - _stack = Contentstack.Client.Stack(response.Stack.APIKey); + StackResponse response = StackResponse.getStack(_client.serializer); + _stack = _client.Stack(response.Stack.APIKey); // Create test environment and release for bulk operations (for new stack) try diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack016_DeliveryTokenTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack016_DeliveryTokenTest.cs index 9af15ba..fc30861 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack016_DeliveryTokenTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack016_DeliveryTokenTest.cs @@ -15,40 +15,32 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack016_DeliveryTokenTest { + private static ContentstackClient _client; private Stack _stack; private string _deliveryTokenUid; private string _testEnvironmentUid = "test_delivery_environment"; private DeliveryTokenModel _testTokenModel; + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + + [ClassCleanup] + public static void ClassCleanup() + { + try { _client?.Logout(); } catch { } + _client = null; + } + [TestInitialize] public async Task Initialize() { try { - // First, ensure the client is logged in - try - { - ContentstackResponse loginResponse = Contentstack.Client.Login(Contentstack.Credential); - if (!loginResponse.IsSuccessStatusCode) - { - AssertLogger.Fail($"Login failed: {loginResponse.OpenResponse()}"); - } - } - catch (Exception loginEx) - { - // If already logged in, that's fine - continue with the test - if (loginEx.Message.Contains("already logged in")) - { - Console.WriteLine("Client already logged in, continuing with test"); - } - else - { - throw; // Re-throw if it's a different error - } - } - - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - _stack = Contentstack.Client.Stack(response.Stack.APIKey); + StackResponse response = StackResponse.getStack(_client.serializer); + _stack = _client.Stack(response.Stack.APIKey); await CreateTestEnvironment(); diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack017_TaxonomyTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack017_TaxonomyTest.cs index ba8cf83..ba34b4c 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack017_TaxonomyTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack017_TaxonomyTest.cs @@ -17,6 +17,7 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack017_TaxonomyTest { + private static ContentstackClient _client; private static string _taxonomyUid; private static string _asyncCreatedTaxonomyUid; private static string _importedTaxonomyUid; @@ -30,11 +31,17 @@ public class Contentstack017_TaxonomyTest private Stack _stack; private TaxonomyModel _createModel; + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + _client = Contentstack.CreateAuthenticatedClient(); + } + [TestInitialize] public void Initialize() { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - _stack = Contentstack.Client.Stack(response.Stack.APIKey); + StackResponse response = StackResponse.getStack(_client.serializer); + _stack = _client.Stack(response.Stack.APIKey); if (_taxonomyUid == null) _taxonomyUid = "taxonomy_integration_test_" + Guid.NewGuid().ToString("N").Substring(0, 8); _createdTermUids = _createdTermUids ?? new List(); @@ -796,8 +803,8 @@ public void Test042_Should_Throw_When_Delete_NonExistent_Term() private static Stack GetStack() { - StackResponse response = StackResponse.getStack(Contentstack.Client.serializer); - return Contentstack.Client.Stack(response.Stack.APIKey); + StackResponse response = StackResponse.getStack(_client.serializer); + return _client.Stack(response.Stack.APIKey); } [ClassCleanup] @@ -900,6 +907,9 @@ public static void Cleanup() { Console.WriteLine($"[Cleanup] Cleanup failed: {ex.Message}"); } + + try { _client?.Logout(); } catch { } + _client = null; } } } diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack999_LogoutTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack999_LogoutTest.cs index cf8a4ca..538387b 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack999_LogoutTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack999_LogoutTest.cs @@ -1,4 +1,5 @@ using System; +using System.Net.Http; using Contentstack.Management.Core.Tests.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -7,24 +8,76 @@ namespace Contentstack.Management.Core.Tests.IntegrationTest [TestClass] public class Contentstack999_LogoutTest { + private static ContentstackClient CreateClientWithLogging() + { + var handler = new LoggingHttpHandler(); + var httpClient = new HttpClient(handler); + return new ContentstackClient(httpClient, new ContentstackClientOptions()); + } + [TestMethod] [DoNotParallelize] - public void Test001_Should_Return_Success_On_Logout() + public void Test001_Should_Return_Success_On_Sync_Logout() { - TestOutputLogger.LogContext("TestScenario", "Logout"); + TestOutputLogger.LogContext("TestScenario", "SyncLogout"); try { - ContentstackClient client = Contentstack.Client; + ContentstackClient client = Contentstack.CreateAuthenticatedClient(); + AssertLogger.IsNotNull(client.contentstackOptions.Authtoken, "AuthtokenBeforeLogout"); + ContentstackResponse contentstackResponse = client.Logout(); string loginResponse = contentstackResponse.OpenResponse(); - AssertLogger.IsNull(client.contentstackOptions.Authtoken, "Authtoken"); - AssertLogger.IsNotNull(loginResponse, "loginResponse"); + AssertLogger.IsNull(client.contentstackOptions.Authtoken, "AuthtokenAfterLogout"); + AssertLogger.IsNotNull(loginResponse, "LogoutResponse"); } catch (Exception e) { AssertLogger.Fail(e.Message); } } + + [TestMethod] + [DoNotParallelize] + public async System.Threading.Tasks.Task Test002_Should_Return_Success_On_Async_Logout() + { + TestOutputLogger.LogContext("TestScenario", "AsyncLogout"); + try + { + ContentstackClient client = Contentstack.CreateAuthenticatedClient(); + AssertLogger.IsNotNull(client.contentstackOptions.Authtoken, "AuthtokenBeforeLogout"); + + ContentstackResponse contentstackResponse = await client.LogoutAsync(); + string logoutResponse = contentstackResponse.OpenResponse(); + + AssertLogger.IsNull(client.contentstackOptions.Authtoken, "AuthtokenAfterLogout"); + AssertLogger.IsNotNull(logoutResponse, "LogoutResponse"); + } + catch (Exception e) + { + AssertLogger.Fail(e.Message); + } + } + + [TestMethod] + [DoNotParallelize] + public void Test003_Should_Handle_Logout_When_Not_LoggedIn() + { + TestOutputLogger.LogContext("TestScenario", "LogoutWhenNotLoggedIn"); + ContentstackClient client = CreateClientWithLogging(); + + AssertLogger.IsNull(client.contentstackOptions.Authtoken, "AuthtokenNotSet"); + + try + { + client.Logout(); + } + catch (Exception e) + { + AssertLogger.IsTrue( + e.Message.Contains("token") || e.Message.Contains("Authentication") || e.Message.Contains("not logged in"), + "LogoutNotLoggedInError"); + } + } } } diff --git a/Contentstack.Management.Core/contentstack.management.core.csproj b/Contentstack.Management.Core/contentstack.management.core.csproj index dbe8960..f422b69 100644 --- a/Contentstack.Management.Core/contentstack.management.core.csproj +++ b/Contentstack.Management.Core/contentstack.management.core.csproj @@ -3,11 +3,11 @@ netstandard2.0;net471;net472 - - - netstandard2.0 - - + + + netstandard2.0 + + 8.0 enable Contentstack Management