From cf2289617cd5d489573dcdb55e5d207789843e6f Mon Sep 17 00:00:00 2001 From: Dovchik Date: Fri, 16 Feb 2024 09:28:53 +0100 Subject: [PATCH 1/8] refactor: move ProjectId param to first place in SinchClient.cs --- src/Sinch/SinchClient.cs | 29 +++++++++++++++++---------- tests/Sinch.Tests/SinchClientTests.cs | 12 +++++------ tests/Sinch.Tests/e2e/TestBase.cs | 4 ++-- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/Sinch/SinchClient.cs b/src/Sinch/SinchClient.cs index b6e2413a..278a843b 100644 --- a/src/Sinch/SinchClient.cs +++ b/src/Sinch/SinchClient.cs @@ -129,6 +129,9 @@ public class SinchClient : ISinchClient private readonly HttpClient _httpClient; private readonly ApiUrlOverrides _apiUrlOverrides; + private string _keyId; + private string _keySecret; + private string _projectId; /// /// Initialize a new @@ -138,22 +141,26 @@ public class SinchClient : ISinchClient /// Your project id. /// Optional. See: /// - public SinchClient(string keyId, string keySecret, string projectId, + public SinchClient(string projectId, string keyId, string keySecret, Action options = default) { - if (keyId is null) + _projectId = projectId; + _keyId = keyId; + if (_keyId is null) { - throw new ArgumentNullException(nameof(keyId), "Should have a value"); + throw new ArgumentNullException(nameof(_keyId), "Should have a value"); } - if (keySecret is null) + _keySecret = keySecret; + if (_keySecret is null) { - throw new ArgumentNullException(nameof(keySecret), "Should have a value"); + throw new ArgumentNullException(nameof(_keySecret), "Should have a value"); } - if (projectId is null) + _projectId = projectId; + if (_projectId is null) { - throw new ArgumentNullException(nameof(projectId), "Should have a value"); + throw new ArgumentNullException(nameof(_projectId), "Should have a value"); } var optionsObj = new SinchOptions(); @@ -169,7 +176,7 @@ public SinchClient(string keyId, string keySecret, string projectId, _apiUrlOverrides = optionsObj?.ApiUrlOverrides; ISinchAuth auth = - new OAuth(keyId, keySecret, _httpClient, _loggerFactory?.Create(), + new OAuth(_keyId, _keySecret, _httpClient, _loggerFactory?.Create(), new Uri(_apiUrlOverrides?.AuthUrl ?? AuthApiUrl)); Auth = auth; var httpCamelCase = new Http(auth, _httpClient, _loggerFactory?.Create(), @@ -177,12 +184,12 @@ public SinchClient(string keyId, string keySecret, string projectId, var httpSnakeCase = new Http(auth, _httpClient, _loggerFactory?.Create(), SnakeCaseNamingPolicy.Instance); - Numbers = new Numbers.Numbers(projectId, new Uri(_apiUrlOverrides?.NumbersUrl ?? NumbersApiUrl), + Numbers = new Numbers.Numbers(_projectId, new Uri(_apiUrlOverrides?.NumbersUrl ?? NumbersApiUrl), _loggerFactory, httpCamelCase); - Sms = new Sms(projectId, GetSmsBaseAddress(optionsObj.SmsHostingRegion, _apiUrlOverrides?.SmsUrl), + Sms = new Sms(_projectId, GetSmsBaseAddress(optionsObj.SmsHostingRegion, _apiUrlOverrides?.SmsUrl), _loggerFactory, httpSnakeCase); - Conversation = new Conversation.SinchConversationClient(projectId, + Conversation = new Conversation.SinchConversationClient(_projectId, new Uri(_apiUrlOverrides?.ConversationUrl ?? string.Format(ConversationApiUrlTemplate, optionsObj.ConversationRegion.Value)), _loggerFactory, httpSnakeCase); diff --git a/tests/Sinch.Tests/SinchClientTests.cs b/tests/Sinch.Tests/SinchClientTests.cs index 5cd4ef59..a0bb50d7 100644 --- a/tests/Sinch.Tests/SinchClientTests.cs +++ b/tests/Sinch.Tests/SinchClientTests.cs @@ -10,7 +10,7 @@ public class SinchClientTests [Fact] public void Should_instantiate_sinch_client_with_provided_required_params() { - var sinch = new SinchClient("TEST_KEY", "TEST_KEY_SECRET", "TEST_PROJECT_ID"); + var sinch = new SinchClient("TEST_PROJECT_ID", "TEST_KEY", "TEST_KEY_SECRET"); sinch.Should().NotBeNull(); sinch.Numbers.Should().NotBeNull(); } @@ -19,7 +19,7 @@ public void Should_instantiate_sinch_client_with_provided_required_params() public void InitSinchClientWithCustomHttpClient() { var httpClient = new HttpClient(); - var sinch = new SinchClient("TEST_KEY", "TEST_KEY_SECRET", "TEST_PROJECT_ID", + var sinch = new SinchClient("TEST_PROJECT_ID", "TEST_KEY", "TEST_KEY_SECRET", options => { options.HttpClient = httpClient; }); sinch.Should().NotBeNull(); Helpers.GetPrivateField(sinch, "_httpClient").Should().Be(httpClient); @@ -28,28 +28,28 @@ public void InitSinchClientWithCustomHttpClient() [Fact] public void ThrowNullKeyId() { - Func initAction = () => new SinchClient(null, "secret", "project"); + Func initAction = () => new SinchClient("project", null, "secret"); initAction.Should().Throw("Should have a value"); } [Fact] public void ThrowNullKeySecret() { - Func initAction = () => new SinchClient("secret", null, "project"); + Func initAction = () => new SinchClient("project", "secret", null); initAction.Should().Throw("Should have a value"); } [Fact] public void ThrowNullProjectId() { - Func initAction = () => new SinchClient("id", "secret", null); + Func initAction = () => new SinchClient(null, "id", "secret"); initAction.Should().Throw("Should have a value"); } [Fact] public void InitializeOwnHttpIfNotPassed() { - var sinch = new SinchClient("id", "secret", "proj"); + var sinch = new SinchClient("proj", "id", "secret"); Helpers.GetPrivateField(sinch, "_httpClient").Should().NotBeNull(); } } diff --git a/tests/Sinch.Tests/e2e/TestBase.cs b/tests/Sinch.Tests/e2e/TestBase.cs index 3e9dfd6f..4761a43a 100644 --- a/tests/Sinch.Tests/e2e/TestBase.cs +++ b/tests/Sinch.Tests/e2e/TestBase.cs @@ -18,7 +18,7 @@ public class TestBase protected TestBase() { Env.Load(); - SinchClientMockStudio = new SinchClient("key_id", "key_secret", ProjectId, + SinchClientMockStudio = new SinchClient(ProjectId, "key_id", "key_secret", options => { options.ApiUrlOverrides = new ApiUrlOverrides() @@ -29,7 +29,7 @@ protected TestBase() }; }); - SinchClientMockServer = new SinchClient("key_id", "key_secret", ProjectId, options => + SinchClientMockServer = new SinchClient(ProjectId, "key_id", "key_secret", options => { options.ApiUrlOverrides = new ApiUrlOverrides() { From 5ee3d3b43c24e28b6ea36e5eb956ad36742c775f Mon Sep 17 00:00:00 2001 From: Dovchik Date: Fri, 16 Feb 2024 09:30:20 +0100 Subject: [PATCH 2/8] fix: remove setter from Conversation prop in SinchClient.cs --- src/Sinch/SinchClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Sinch/SinchClient.cs b/src/Sinch/SinchClient.cs index 278a843b..bb4de252 100644 --- a/src/Sinch/SinchClient.cs +++ b/src/Sinch/SinchClient.cs @@ -218,7 +218,7 @@ private static Uri GetSmsBaseAddress(SmsHostingRegion smsHostingRegion, string s public ISinchSms Sms { get; } /// - public ISinchConversation Conversation { get; set; } + public ISinchConversation Conversation { get; } /// From b82d275c66992529f0f54178efeae7c2f7ecbb99 Mon Sep 17 00:00:00 2001 From: Dovchik Date: Fri, 16 Feb 2024 09:48:10 +0100 Subject: [PATCH 3/8] refactor: throw null credentials when accessing service --- src/Sinch/SinchClient.cs | 95 +++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 26 deletions(-) diff --git a/src/Sinch/SinchClient.cs b/src/Sinch/SinchClient.cs index bb4de252..4e8cf260 100644 --- a/src/Sinch/SinchClient.cs +++ b/src/Sinch/SinchClient.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Net.Http; using System.Text.Json; using Sinch.Auth; @@ -129,9 +130,36 @@ public class SinchClient : ISinchClient private readonly HttpClient _httpClient; private readonly ApiUrlOverrides _apiUrlOverrides; - private string _keyId; - private string _keySecret; - private string _projectId; + + private readonly string _keyId; + private readonly string _keySecret; + private readonly string _projectId; + + private readonly ISinchNumbers _numbers; + private readonly ISinchSms _sms; + private readonly ISinchConversation _conversation; + private readonly ISinchAuth _auth; + + private void ValidateCommonCredentials() + { + var exceptions = new List(); + if (_keyId is null) + { + exceptions.Add(new InvalidOperationException("keyId should have a value")); + } + + if (_projectId is null) + { + exceptions.Add(new InvalidOperationException("projectId should have a value")); + } + + if (_keySecret is null) + { + exceptions.Add(new InvalidOperationException("keySecret should have a value")); + } + + throw new AggregateException("Credentials are missing", exceptions); + } /// /// Initialize a new @@ -146,22 +174,8 @@ public SinchClient(string projectId, string keyId, string keySecret, { _projectId = projectId; _keyId = keyId; - if (_keyId is null) - { - throw new ArgumentNullException(nameof(_keyId), "Should have a value"); - } - _keySecret = keySecret; - if (_keySecret is null) - { - throw new ArgumentNullException(nameof(_keySecret), "Should have a value"); - } - _projectId = projectId; - if (_projectId is null) - { - throw new ArgumentNullException(nameof(_projectId), "Should have a value"); - } var optionsObj = new SinchOptions(); options?.Invoke(optionsObj); @@ -178,18 +192,18 @@ public SinchClient(string projectId, string keyId, string keySecret, ISinchAuth auth = new OAuth(_keyId, _keySecret, _httpClient, _loggerFactory?.Create(), new Uri(_apiUrlOverrides?.AuthUrl ?? AuthApiUrl)); - Auth = auth; + _auth = auth; var httpCamelCase = new Http(auth, _httpClient, _loggerFactory?.Create(), JsonNamingPolicy.CamelCase); var httpSnakeCase = new Http(auth, _httpClient, _loggerFactory?.Create(), SnakeCaseNamingPolicy.Instance); - Numbers = new Numbers.Numbers(_projectId, new Uri(_apiUrlOverrides?.NumbersUrl ?? NumbersApiUrl), + _numbers = new Numbers.Numbers(_projectId, new Uri(_apiUrlOverrides?.NumbersUrl ?? NumbersApiUrl), _loggerFactory, httpCamelCase); - Sms = new Sms(_projectId, GetSmsBaseAddress(optionsObj.SmsHostingRegion, _apiUrlOverrides?.SmsUrl), + _sms = new Sms(_projectId, GetSmsBaseAddress(optionsObj.SmsHostingRegion, _apiUrlOverrides?.SmsUrl), _loggerFactory, httpSnakeCase); - Conversation = new Conversation.SinchConversationClient(_projectId, + _conversation = new SinchConversationClient(_projectId, new Uri(_apiUrlOverrides?.ConversationUrl ?? string.Format(ConversationApiUrlTemplate, optionsObj.ConversationRegion.Value)), _loggerFactory, httpSnakeCase); @@ -199,7 +213,7 @@ public SinchClient(string projectId, string keyId, string keySecret, private static Uri GetSmsBaseAddress(SmsHostingRegion smsHostingRegion, string smsUrlOverride) { - if (smsUrlOverride != null) + if (!string.IsNullOrEmpty(smsUrlOverride)) { return new Uri(smsUrlOverride); } @@ -212,17 +226,46 @@ private static Uri GetSmsBaseAddress(SmsHostingRegion smsHostingRegion, string s } /// - public ISinchNumbers Numbers { get; } + public ISinchNumbers Numbers + { + get + { + ValidateCommonCredentials(); + return _numbers; + } + } /// - public ISinchSms Sms { get; } + public ISinchSms Sms + { + get + { + // TODO: when support service plan id make sure validation is proper here. + ValidateCommonCredentials(); + return _sms; + } + } /// - public ISinchConversation Conversation { get; } + public ISinchConversation Conversation + { + get + { + ValidateCommonCredentials(); + return _conversation; + } + } /// - public ISinchAuth Auth { get; } + public ISinchAuth Auth + { + get + { + ValidateCommonCredentials(); + return _auth; + } + } /// public ISinchVerificationClient Verification(string appKey, string appSecret, From feeb0ebd9cfe1dfde02c2742851c2be9775d38b1 Mon Sep 17 00:00:00 2001 From: Dovchik Date: Fri, 16 Feb 2024 10:38:54 +0100 Subject: [PATCH 4/8] chore: add example of use only verification or voice product --- examples/Console/UseOnlyVoiceOrVerification.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 examples/Console/UseOnlyVoiceOrVerification.cs diff --git a/examples/Console/UseOnlyVoiceOrVerification.cs b/examples/Console/UseOnlyVoiceOrVerification.cs new file mode 100644 index 00000000..ae080771 --- /dev/null +++ b/examples/Console/UseOnlyVoiceOrVerification.cs @@ -0,0 +1,17 @@ +using Sinch; + +namespace Examples +{ + public class UseOnlyVoiceOrVerification + { + /// + /// If you want to use only voice and/or verification api, you can init sinch client without providing + /// necessary credentials. But be aware that when you try to use other services which depends on the common credentials you will get an exception. + /// + public void Example() + { + var sinchVoiceClient = new SinchClient(null, null, null).Voice("appKey", "appSecret"); + var sinchVerificationClient = new SinchClient(null, null, null).Verification("appKey", "appSecret"); + } + } +} From 53a3e80b5d28b1db7a5e94feecd185cb3391e9da Mon Sep 17 00:00:00 2001 From: Dovchik Date: Fri, 16 Feb 2024 10:39:11 +0100 Subject: [PATCH 5/8] feat: add test initialization without credentials --- tests/Sinch.Tests/SinchClientTests.cs | 65 ++++++++++++++++++++------- 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/tests/Sinch.Tests/SinchClientTests.cs b/tests/Sinch.Tests/SinchClientTests.cs index a0bb50d7..1c609acc 100644 --- a/tests/Sinch.Tests/SinchClientTests.cs +++ b/tests/Sinch.Tests/SinchClientTests.cs @@ -8,44 +8,75 @@ namespace Sinch.Tests public class SinchClientTests { [Fact] - public void Should_instantiate_sinch_client_with_provided_required_params() + public void InitSinchClientWithoutAllCredentials() { - var sinch = new SinchClient("TEST_PROJECT_ID", "TEST_KEY", "TEST_KEY_SECRET"); + var sinch = new SinchClient(null, null, null); sinch.Should().NotBeNull(); - sinch.Numbers.Should().NotBeNull(); } [Fact] - public void InitSinchClientWithCustomHttpClient() + public void InitSinchClientWithoutProjectId() { - var httpClient = new HttpClient(); - var sinch = new SinchClient("TEST_PROJECT_ID", "TEST_KEY", "TEST_KEY_SECRET", - options => { options.HttpClient = httpClient; }); + var sinch = new SinchClient(null, "key", "secret"); sinch.Should().NotBeNull(); - Helpers.GetPrivateField(sinch, "_httpClient").Should().Be(httpClient); } [Fact] - public void ThrowNullKeyId() + public void InitSinchClientWithoutKeyId() { - Func initAction = () => new SinchClient("project", null, "secret"); - initAction.Should().Throw("Should have a value"); + var sinch = new SinchClient("key", null, "secret"); + sinch.Should().NotBeNull(); } [Fact] - public void ThrowNullKeySecret() + public void InitSinchClientWithoutKeySecret() { - Func initAction = () => new SinchClient("project", "secret", null); - initAction.Should().Throw("Should have a value"); + var sinch = new SinchClient("key", "secret", null); + sinch.Should().NotBeNull(); } [Fact] - public void ThrowNullProjectId() + public void InitSinchClientWithCustomHttpClient() { - Func initAction = () => new SinchClient(null, "id", "secret"); - initAction.Should().Throw("Should have a value"); + var httpClient = new HttpClient(); + var sinch = new SinchClient("TEST_PROJECT_ID", "TEST_KEY", "TEST_KEY_SECRET", + options => { options.HttpClient = httpClient; }); + sinch.Should().NotBeNull(); + Helpers.GetPrivateField(sinch, "_httpClient").Should().Be(httpClient); } + [Theory] + [InlineData(null, null, null, + "Credentials are missing (keyId should have a value) (projectId should have a value) (keySecret should have a value)")] + [InlineData("projectId", null, null, + "Credentials are missing (keyId should have a value) (keySecret should have a value)")] + [InlineData(null, "keyId", null, + "Credentials are missing (projectId should have a value) (keySecret should have a value)")] + [InlineData(null, null, "keySecret", + "Credentials are missing (keyId should have a value) (projectId should have a value)")] + [InlineData("projectId", "keySecret", null, "Credentials are missing (keySecret should have a value)")] + [InlineData("projectId", null, "keySecret", "Credentials are missing (keyId should have a value)")] + [InlineData(null, "keySecret", "keySecret", "Credentials are missing (projectId should have a value)")] + public void ThrowAggregateExceptionWhenAccessingCommonCredentialsProducts(string projectId, string keyId, + string keySecret, string message) + { + var sinch = new SinchClient(projectId, keyId, keySecret); + var smsOp = () => sinch.Sms; + var aggregateExceptionSms = smsOp.Should().Throw().Which; + aggregateExceptionSms.Message.Should().BeEquivalentTo(message); + + var conversationOp = () => sinch.Conversation; + var aggregateExceptionConversation = conversationOp.Should().Throw().Which; + aggregateExceptionConversation.Message.Should().BeEquivalentTo(message); + + var numbersOp = () => sinch.Numbers; + var aggregateExceptionNumbers = numbersOp.Should().Throw().Which; + aggregateExceptionNumbers.Message.Should().BeEquivalentTo(message); + + var authOp = () => sinch.Auth; + var aggregateExceptionAuth = authOp.Should().Throw().Which; + aggregateExceptionAuth.Message.Should().BeEquivalentTo(message); + } [Fact] public void InitializeOwnHttpIfNotPassed() { From b9f5f2a18124454cbf68ad7019756eaeaf3ca53b Mon Sep 17 00:00:00 2001 From: Dovchik Date: Fri, 16 Feb 2024 10:43:37 +0100 Subject: [PATCH 6/8] refactor: use theory --- tests/Sinch.Tests/SinchClientTests.cs | 55 ++++++++++----------------- 1 file changed, 21 insertions(+), 34 deletions(-) diff --git a/tests/Sinch.Tests/SinchClientTests.cs b/tests/Sinch.Tests/SinchClientTests.cs index 1c609acc..7cb9b2df 100644 --- a/tests/Sinch.Tests/SinchClientTests.cs +++ b/tests/Sinch.Tests/SinchClientTests.cs @@ -7,42 +7,18 @@ namespace Sinch.Tests { public class SinchClientTests { - [Fact] - public void InitSinchClientWithoutAllCredentials() - { - var sinch = new SinchClient(null, null, null); - sinch.Should().NotBeNull(); - } - - [Fact] - public void InitSinchClientWithoutProjectId() - { - var sinch = new SinchClient(null, "key", "secret"); - sinch.Should().NotBeNull(); - } - - [Fact] - public void InitSinchClientWithoutKeyId() - { - var sinch = new SinchClient("key", null, "secret"); - sinch.Should().NotBeNull(); - } - - [Fact] - public void InitSinchClientWithoutKeySecret() - { - var sinch = new SinchClient("key", "secret", null); - sinch.Should().NotBeNull(); - } - - [Fact] - public void InitSinchClientWithCustomHttpClient() + [Theory] + [InlineData(null, null, null)] + [InlineData("projectId", null, null)] + [InlineData(null, "keyId", null)] + [InlineData(null, null, "keySecret")] + [InlineData("projectId", "keySecret", null)] + [InlineData("projectId", null, "keySecret")] + [InlineData(null, "keySecret", "keySecret")] + public void InitSinchClientWithoutCredentials(string projectId, string keyId, string keySecret) { - var httpClient = new HttpClient(); - var sinch = new SinchClient("TEST_PROJECT_ID", "TEST_KEY", "TEST_KEY_SECRET", - options => { options.HttpClient = httpClient; }); + var sinch = new SinchClient(projectId, keyId, keySecret); sinch.Should().NotBeNull(); - Helpers.GetPrivateField(sinch, "_httpClient").Should().Be(httpClient); } [Theory] @@ -77,11 +53,22 @@ public void ThrowAggregateExceptionWhenAccessingCommonCredentialsProducts(string var aggregateExceptionAuth = authOp.Should().Throw().Which; aggregateExceptionAuth.Message.Should().BeEquivalentTo(message); } + [Fact] public void InitializeOwnHttpIfNotPassed() { var sinch = new SinchClient("proj", "id", "secret"); Helpers.GetPrivateField(sinch, "_httpClient").Should().NotBeNull(); } + + [Fact] + public void InitSinchClientWithCustomHttpClient() + { + var httpClient = new HttpClient(); + var sinch = new SinchClient("TEST_PROJECT_ID", "TEST_KEY", "TEST_KEY_SECRET", + options => { options.HttpClient = httpClient; }); + sinch.Should().NotBeNull(); + Helpers.GetPrivateField(sinch, "_httpClient").Should().Be(httpClient); + } } } From 768547a1f5f3046155f4e4eb3bcfbe68aebdb0a9 Mon Sep 17 00:00:00 2001 From: Dovchik Date: Fri, 16 Feb 2024 11:06:53 +0100 Subject: [PATCH 7/8] feat: add warning if credentials not set --- src/Sinch/SinchClient.cs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Sinch/SinchClient.cs b/src/Sinch/SinchClient.cs index 4e8cf260..17357f9c 100644 --- a/src/Sinch/SinchClient.cs +++ b/src/Sinch/SinchClient.cs @@ -181,12 +181,27 @@ public SinchClient(string projectId, string keyId, string keySecret, options?.Invoke(optionsObj); if (optionsObj.LoggerFactory is not null) _loggerFactory = new LoggerFactory(optionsObj.LoggerFactory); - - _httpClient = optionsObj.HttpClient ?? new HttpClient(); - var logger = _loggerFactory?.Create(); logger?.LogInformation("Initializing SinchClient..."); + + if (string.IsNullOrEmpty(projectId)) + { + logger?.LogWarning($"{nameof(projectId)} is not set!"); + } + + if (string.IsNullOrEmpty(keyId)) + { + logger?.LogWarning($"{nameof(keyId)} is not set!"); + } + + if (string.IsNullOrEmpty(keySecret)) + { + logger?.LogWarning($"{nameof(keySecret)} is not set!"); + } + + _httpClient = optionsObj.HttpClient ?? new HttpClient(); + _apiUrlOverrides = optionsObj?.ApiUrlOverrides; ISinchAuth auth = From 47c6894ff0a35d636f745c6cd340b8c2871fbf1a Mon Sep 17 00:00:00 2001 From: Dovchik Date: Fri, 16 Feb 2024 11:24:41 +0100 Subject: [PATCH 8/8] fix: throw credentials error only if any missing --- src/Sinch/SinchClient.cs | 12 ++++++++---- tests/Sinch.Tests/SinchClientTests.cs | 18 ++++++++++++++---- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/Sinch/SinchClient.cs b/src/Sinch/SinchClient.cs index 17357f9c..00ed266d 100644 --- a/src/Sinch/SinchClient.cs +++ b/src/Sinch/SinchClient.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Text.Json; using Sinch.Auth; @@ -143,22 +144,25 @@ public class SinchClient : ISinchClient private void ValidateCommonCredentials() { var exceptions = new List(); - if (_keyId is null) + if (string.IsNullOrEmpty(_keyId)) { exceptions.Add(new InvalidOperationException("keyId should have a value")); } - if (_projectId is null) + if (string.IsNullOrEmpty(_projectId)) { exceptions.Add(new InvalidOperationException("projectId should have a value")); } - if (_keySecret is null) + if (string.IsNullOrEmpty(_keySecret)) { exceptions.Add(new InvalidOperationException("keySecret should have a value")); } - throw new AggregateException("Credentials are missing", exceptions); + if (exceptions.Any()) + { + throw new AggregateException("Credentials are missing", exceptions); + } } /// diff --git a/tests/Sinch.Tests/SinchClientTests.cs b/tests/Sinch.Tests/SinchClientTests.cs index 7cb9b2df..7fadbe68 100644 --- a/tests/Sinch.Tests/SinchClientTests.cs +++ b/tests/Sinch.Tests/SinchClientTests.cs @@ -44,23 +44,33 @@ public void ThrowAggregateExceptionWhenAccessingCommonCredentialsProducts(string var conversationOp = () => sinch.Conversation; var aggregateExceptionConversation = conversationOp.Should().Throw().Which; aggregateExceptionConversation.Message.Should().BeEquivalentTo(message); - + var numbersOp = () => sinch.Numbers; var aggregateExceptionNumbers = numbersOp.Should().Throw().Which; aggregateExceptionNumbers.Message.Should().BeEquivalentTo(message); - + var authOp = () => sinch.Auth; var aggregateExceptionAuth = authOp.Should().Throw().Which; aggregateExceptionAuth.Message.Should().BeEquivalentTo(message); } - + + [Fact] + public void GetServiceWithoutExceptionsIfCredentialsAreSet() + { + var sinch = new SinchClient("projectId", "keyId", "keySecret"); + sinch.Conversation.Should().NotBeNull(); + sinch.Sms.Should().NotBeNull(); + sinch.Auth.Should().NotBeNull(); + sinch.Numbers.Should().NotBeNull(); + } + [Fact] public void InitializeOwnHttpIfNotPassed() { var sinch = new SinchClient("proj", "id", "secret"); Helpers.GetPrivateField(sinch, "_httpClient").Should().NotBeNull(); } - + [Fact] public void InitSinchClientWithCustomHttpClient() {