Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 16 additions & 12 deletions Contentstack.Management.Core.Tests/Contentstack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,6 @@ namespace Contentstack.Management.Core.Tests
{
public class Contentstack
{
private static readonly Lazy<ContentstackClient>
client =
new Lazy<ContentstackClient>(() =>
{
ContentstackClientOptions options = Config.GetSection("Contentstack").Get<ContentstackClientOptions>();
var handler = new LoggingHttpHandler();
var httpClient = new HttpClient(handler);
return new ContentstackClient(httpClient, options);
});


private static readonly Lazy<IConfigurationRoot>
config =
new Lazy<IConfigurationRoot>(() =>
Expand All @@ -46,13 +35,28 @@ private static readonly Lazy<IConfigurationRoot>
return Config.GetSection("Contentstack:Organization").Get<OrganizationModel>();
});

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; }

/// <summary>
/// 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.
/// </summary>
public static ContentstackClient CreateAuthenticatedClient()
{
ContentstackClientOptions options = Config.GetSection("Contentstack").Get<ContentstackClientOptions>();
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<T>(JsonSerializer serializer, string filePath)
{
string response = GetResourceText(filePath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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()
{
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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<InvalidOperationException>(() =>
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<InvalidOperationException>(() =>
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<ArgumentNullException>(() =>
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<ArgumentNullException>(() =>
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}");
}
}
}
}
Loading
Loading