From 7bd347875defd21e3d0223089d3f0b5a06925740 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 19:48:20 +0000 Subject: [PATCH 1/2] feat: Remove /bulk endpoints from api-spec (C-19507) (#171) * Remove /bulk endpoints from api-spec (C-19507) Removes the `/bulk` resource and all of its endpoints: - POST /bulk (create job) - POST /bulk/{job_id} (add users) - GET /bulk/{job_id} (get job) - POST /bulk/{job_id}/run (run job) - GET /bulk/{job_id}/users (get users) Deletes the corresponding paths and now-orphaned Bulk component schemas from specs/openapi.yml and the `bulk` resource from specs/stainless.yml. The unrelated /users/{user_id}/preferences bulk update/replace endpoints are untouched. Co-Authored-By: Claude Opus 4.8 * Remove bulk e2e test The /bulk endpoints were removed, so the generated SDK no longer exposes courier.bulk. Delete the corresponding e2e test. Co-Authored-By: Claude Opus 4.8 * Remove bulk SDK examples The /bulk endpoints were removed, so the generated SDKs no longer expose the bulk resource. Delete the per-language bulk example files (csharp, go, java, kotlin, php, python, ruby) that reference client.bulk() and were breaking the example compile/test checks. Co-Authored-By: Claude Opus 4.8 --------- Co-authored-by: Claude Opus 4.8 --- .stats.yml | 8 +- .../Models/Bulk/BulkAddUsersParamsTest.cs | 408 ---- .../Models/Bulk/BulkCreateJobParamsTest.cs | 145 -- .../Models/Bulk/BulkCreateJobResponseTest.cs | 67 - .../Models/Bulk/BulkListUsersParamsTest.cs | 67 - .../Models/Bulk/BulkListUsersResponseTest.cs | 2114 ----------------- .../Models/Bulk/BulkRetrieveJobParamsTest.cs | 37 - .../Bulk/BulkRetrieveJobResponseTest.cs | 639 ----- .../Models/Bulk/BulkRunJobParamsTest.cs | 37 - .../Models/Bulk/InboundBulkMessageTest.cs | 444 ---- .../Models/Bulk/InboundBulkMessageUserTest.cs | 1071 --------- .../Services/BulkServiceTest.cs | 182 -- src/TryCourier/Core/ModelBase.cs | 9 +- src/TryCourier/CourierClient.cs | 14 - src/TryCourier/ICourierClient.cs | 4 - .../Models/Bulk/BulkAddUsersParams.cs | 170 -- .../Models/Bulk/BulkCreateJobParams.cs | 156 -- .../Models/Bulk/BulkCreateJobResponse.cs | 72 - .../Models/Bulk/BulkListUsersParams.cs | 135 -- .../Models/Bulk/BulkListUsersResponse.cs | 383 --- .../Models/Bulk/BulkRetrieveJobParams.cs | 121 - .../Models/Bulk/BulkRetrieveJobResponse.cs | 227 -- .../Models/Bulk/BulkRunJobParams.cs | 121 - .../Models/Bulk/InboundBulkMessage.cs | 448 ---- .../Models/Bulk/InboundBulkMessageUser.cs | 139 -- src/TryCourier/Services/BulkService.cs | 330 --- src/TryCourier/Services/IBulkService.cs | 187 -- 27 files changed, 7 insertions(+), 7728 deletions(-) delete mode 100644 src/TryCourier.Tests/Models/Bulk/BulkAddUsersParamsTest.cs delete mode 100644 src/TryCourier.Tests/Models/Bulk/BulkCreateJobParamsTest.cs delete mode 100644 src/TryCourier.Tests/Models/Bulk/BulkCreateJobResponseTest.cs delete mode 100644 src/TryCourier.Tests/Models/Bulk/BulkListUsersParamsTest.cs delete mode 100644 src/TryCourier.Tests/Models/Bulk/BulkListUsersResponseTest.cs delete mode 100644 src/TryCourier.Tests/Models/Bulk/BulkRetrieveJobParamsTest.cs delete mode 100644 src/TryCourier.Tests/Models/Bulk/BulkRetrieveJobResponseTest.cs delete mode 100644 src/TryCourier.Tests/Models/Bulk/BulkRunJobParamsTest.cs delete mode 100644 src/TryCourier.Tests/Models/Bulk/InboundBulkMessageTest.cs delete mode 100644 src/TryCourier.Tests/Models/Bulk/InboundBulkMessageUserTest.cs delete mode 100644 src/TryCourier.Tests/Services/BulkServiceTest.cs delete mode 100644 src/TryCourier/Models/Bulk/BulkAddUsersParams.cs delete mode 100644 src/TryCourier/Models/Bulk/BulkCreateJobParams.cs delete mode 100644 src/TryCourier/Models/Bulk/BulkCreateJobResponse.cs delete mode 100644 src/TryCourier/Models/Bulk/BulkListUsersParams.cs delete mode 100644 src/TryCourier/Models/Bulk/BulkListUsersResponse.cs delete mode 100644 src/TryCourier/Models/Bulk/BulkRetrieveJobParams.cs delete mode 100644 src/TryCourier/Models/Bulk/BulkRetrieveJobResponse.cs delete mode 100644 src/TryCourier/Models/Bulk/BulkRunJobParams.cs delete mode 100644 src/TryCourier/Models/Bulk/InboundBulkMessage.cs delete mode 100644 src/TryCourier/Models/Bulk/InboundBulkMessageUser.cs delete mode 100644 src/TryCourier/Services/BulkService.cs delete mode 100644 src/TryCourier/Services/IBulkService.cs diff --git a/.stats.yml b/.stats.yml index 44174988..e2794c72 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 139 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-b03f5346718dcd7b22f15893445ea593ab87535c90c540fc5a796c6ecd54d779.yml -openapi_spec_hash: 15677d3be4ecd33eab154080b4bc437f -config_hash: dcd58abf1e56b114bdce22336ca3d570 +configured_endpoints: 134 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/courier/courier-b053468fefe6d757f86f3233ebbc52d80329ed2a6e7a6740fee01e4028a4c3b9.yml +openapi_spec_hash: 416835e693de0fe19945be90a787d3f3 +config_hash: 8d28dbeabe9d4dcc7d5b8c021a4cbbd7 diff --git a/src/TryCourier.Tests/Models/Bulk/BulkAddUsersParamsTest.cs b/src/TryCourier.Tests/Models/Bulk/BulkAddUsersParamsTest.cs deleted file mode 100644 index a927e6b0..00000000 --- a/src/TryCourier.Tests/Models/Bulk/BulkAddUsersParamsTest.cs +++ /dev/null @@ -1,408 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; -using TryCourier.Models; -using TryCourier.Models.Bulk; - -namespace TryCourier.Tests.Models.Bulk; - -public class BulkAddUsersParamsTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var parameters = new BulkAddUsersParams - { - JobID = "job_id", - Users = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }, - ], - }; - - string expectedJobID = "job_id"; - List expectedUsers = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }, - ]; - - Assert.Equal(expectedJobID, parameters.JobID); - Assert.Equal(expectedUsers.Count, parameters.Users.Count); - for (int i = 0; i < expectedUsers.Count; i++) - { - Assert.Equal(expectedUsers[i], parameters.Users[i]); - } - } - - [Fact] - public void Url_Works() - { - BulkAddUsersParams parameters = new() - { - JobID = "job_id", - Users = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }, - ], - }; - - var url = parameters.Url(new() { ApiKey = "My API Key" }); - - Assert.True(TestBase.UrisEqual(new Uri("https://api.courier.com/bulk/job_id"), url)); - } - - [Fact] - public void CopyConstructor_Works() - { - var parameters = new BulkAddUsersParams - { - JobID = "job_id", - Users = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }, - ], - }; - - BulkAddUsersParams copied = new(parameters); - - Assert.Equal(parameters, copied); - } -} diff --git a/src/TryCourier.Tests/Models/Bulk/BulkCreateJobParamsTest.cs b/src/TryCourier.Tests/Models/Bulk/BulkCreateJobParamsTest.cs deleted file mode 100644 index 4e63b2e7..00000000 --- a/src/TryCourier.Tests/Models/Bulk/BulkCreateJobParamsTest.cs +++ /dev/null @@ -1,145 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; -using TryCourier.Models; -using TryCourier.Models.Bulk; - -namespace TryCourier.Tests.Models.Bulk; - -public class BulkCreateJobParamsTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var parameters = new BulkCreateJobParams - { - Message = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - }; - - InboundBulkMessage expectedMessage = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }; - - Assert.Equal(expectedMessage, parameters.Message); - } - - [Fact] - public void Url_Works() - { - BulkCreateJobParams parameters = new() - { - Message = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - }; - - var url = parameters.Url(new() { ApiKey = "My API Key" }); - - Assert.True(TestBase.UrisEqual(new Uri("https://api.courier.com/bulk"), url)); - } - - [Fact] - public void CopyConstructor_Works() - { - var parameters = new BulkCreateJobParams - { - Message = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - }; - - BulkCreateJobParams copied = new(parameters); - - Assert.Equal(parameters, copied); - } -} diff --git a/src/TryCourier.Tests/Models/Bulk/BulkCreateJobResponseTest.cs b/src/TryCourier.Tests/Models/Bulk/BulkCreateJobResponseTest.cs deleted file mode 100644 index 40b1a84a..00000000 --- a/src/TryCourier.Tests/Models/Bulk/BulkCreateJobResponseTest.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Text.Json; -using TryCourier.Core; -using TryCourier.Models.Bulk; - -namespace TryCourier.Tests.Models.Bulk; - -public class BulkCreateJobResponseTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var model = new BulkCreateJobResponse { JobID = "jobId" }; - - string expectedJobID = "jobId"; - - Assert.Equal(expectedJobID, model.JobID); - } - - [Fact] - public void SerializationRoundtrip_Works() - { - var model = new BulkCreateJobResponse { JobID = "jobId" }; - - string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(model, deserialized); - } - - [Fact] - public void FieldRoundtripThroughSerialization_Works() - { - var model = new BulkCreateJobResponse { JobID = "jobId" }; - - string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - Assert.NotNull(deserialized); - - string expectedJobID = "jobId"; - - Assert.Equal(expectedJobID, deserialized.JobID); - } - - [Fact] - public void Validation_Works() - { - var model = new BulkCreateJobResponse { JobID = "jobId" }; - - model.Validate(); - } - - [Fact] - public void CopyConstructor_Works() - { - var model = new BulkCreateJobResponse { JobID = "jobId" }; - - BulkCreateJobResponse copied = new(model); - - Assert.Equal(model, copied); - } -} diff --git a/src/TryCourier.Tests/Models/Bulk/BulkListUsersParamsTest.cs b/src/TryCourier.Tests/Models/Bulk/BulkListUsersParamsTest.cs deleted file mode 100644 index 1a440dc8..00000000 --- a/src/TryCourier.Tests/Models/Bulk/BulkListUsersParamsTest.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using TryCourier.Models.Bulk; - -namespace TryCourier.Tests.Models.Bulk; - -public class BulkListUsersParamsTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var parameters = new BulkListUsersParams { JobID = "job_id", Cursor = "cursor" }; - - string expectedJobID = "job_id"; - string expectedCursor = "cursor"; - - Assert.Equal(expectedJobID, parameters.JobID); - Assert.Equal(expectedCursor, parameters.Cursor); - } - - [Fact] - public void OptionalNullableParamsUnsetAreNotSet_Works() - { - var parameters = new BulkListUsersParams { JobID = "job_id" }; - - Assert.Null(parameters.Cursor); - Assert.False(parameters.RawQueryData.ContainsKey("cursor")); - } - - [Fact] - public void OptionalNullableParamsSetToNullAreSetToNull_Works() - { - var parameters = new BulkListUsersParams - { - JobID = "job_id", - - Cursor = null, - }; - - Assert.Null(parameters.Cursor); - Assert.True(parameters.RawQueryData.ContainsKey("cursor")); - } - - [Fact] - public void Url_Works() - { - BulkListUsersParams parameters = new() { JobID = "job_id", Cursor = "cursor" }; - - var url = parameters.Url(new() { ApiKey = "My API Key" }); - - Assert.True( - TestBase.UrisEqual( - new Uri("https://api.courier.com/bulk/job_id/users?cursor=cursor"), - url - ) - ); - } - - [Fact] - public void CopyConstructor_Works() - { - var parameters = new BulkListUsersParams { JobID = "job_id", Cursor = "cursor" }; - - BulkListUsersParams copied = new(parameters); - - Assert.Equal(parameters, copied); - } -} diff --git a/src/TryCourier.Tests/Models/Bulk/BulkListUsersResponseTest.cs b/src/TryCourier.Tests/Models/Bulk/BulkListUsersResponseTest.cs deleted file mode 100644 index f30d7303..00000000 --- a/src/TryCourier.Tests/Models/Bulk/BulkListUsersResponseTest.cs +++ /dev/null @@ -1,2114 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json; -using TryCourier.Core; -using TryCourier.Exceptions; -using TryCourier.Models.Bulk; -using Models = TryCourier.Models; - -namespace TryCourier.Tests.Models.Bulk; - -public class BulkListUsersResponseTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var model = new BulkListUsersResponse - { - Items = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary< - string, - Models::NotificationPreferenceDetails - >() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }, - ], - Paging = new() { More = true, Cursor = "cursor" }, - }; - - List expectedItems = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }, - ]; - Models::Paging expectedPaging = new() { More = true, Cursor = "cursor" }; - - Assert.Equal(expectedItems.Count, model.Items.Count); - for (int i = 0; i < expectedItems.Count; i++) - { - Assert.Equal(expectedItems[i], model.Items[i]); - } - Assert.Equal(expectedPaging, model.Paging); - } - - [Fact] - public void SerializationRoundtrip_Works() - { - var model = new BulkListUsersResponse - { - Items = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary< - string, - Models::NotificationPreferenceDetails - >() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }, - ], - Paging = new() { More = true, Cursor = "cursor" }, - }; - - string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(model, deserialized); - } - - [Fact] - public void FieldRoundtripThroughSerialization_Works() - { - var model = new BulkListUsersResponse - { - Items = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary< - string, - Models::NotificationPreferenceDetails - >() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }, - ], - Paging = new() { More = true, Cursor = "cursor" }, - }; - - string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - Assert.NotNull(deserialized); - - List expectedItems = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }, - ]; - Models::Paging expectedPaging = new() { More = true, Cursor = "cursor" }; - - Assert.Equal(expectedItems.Count, deserialized.Items.Count); - for (int i = 0; i < expectedItems.Count; i++) - { - Assert.Equal(expectedItems[i], deserialized.Items[i]); - } - Assert.Equal(expectedPaging, deserialized.Paging); - } - - [Fact] - public void Validation_Works() - { - var model = new BulkListUsersResponse - { - Items = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary< - string, - Models::NotificationPreferenceDetails - >() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }, - ], - Paging = new() { More = true, Cursor = "cursor" }, - }; - - model.Validate(); - } - - [Fact] - public void CopyConstructor_Works() - { - var model = new BulkListUsersResponse - { - Items = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary< - string, - Models::NotificationPreferenceDetails - >() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }, - ], - Paging = new() { More = true, Cursor = "cursor" }, - }; - - BulkListUsersResponse copied = new(model); - - Assert.Equal(model, copied); - } -} - -public class ItemTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var model = new Item - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }; - - JsonElement expectedData = JsonSerializer.Deserialize("{}"); - Models::RecipientPreferences expectedPreferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }; - Dictionary expectedProfile = new() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }; - string expectedRecipient = "recipient"; - Models::UserRecipient expectedTo = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }; - ApiEnum expectedStatus = Status.Pending; - string expectedMessageID = "messageId"; - - Assert.NotNull(model.Data); - Assert.True(JsonElement.DeepEquals(expectedData, model.Data.Value)); - Assert.Equal(expectedPreferences, model.Preferences); - Assert.NotNull(model.Profile); - Assert.Equal(expectedProfile.Count, model.Profile.Count); - foreach (var item in expectedProfile) - { - Assert.True(model.Profile.TryGetValue(item.Key, out var value)); - - Assert.True(JsonElement.DeepEquals(value, model.Profile[item.Key])); - } - Assert.Equal(expectedRecipient, model.Recipient); - Assert.Equal(expectedTo, model.To); - Assert.Equal(expectedStatus, model.Status); - Assert.Equal(expectedMessageID, model.MessageID); - } - - [Fact] - public void SerializationRoundtrip_Works() - { - var model = new Item - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }; - - string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize(json, ModelBase.SerializerOptions); - - Assert.Equal(model, deserialized); - } - - [Fact] - public void FieldRoundtripThroughSerialization_Works() - { - var model = new Item - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }; - - string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize(element, ModelBase.SerializerOptions); - Assert.NotNull(deserialized); - - JsonElement expectedData = JsonSerializer.Deserialize("{}"); - Models::RecipientPreferences expectedPreferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }; - Dictionary expectedProfile = new() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }; - string expectedRecipient = "recipient"; - Models::UserRecipient expectedTo = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }; - ApiEnum expectedStatus = Status.Pending; - string expectedMessageID = "messageId"; - - Assert.NotNull(deserialized.Data); - Assert.True(JsonElement.DeepEquals(expectedData, deserialized.Data.Value)); - Assert.Equal(expectedPreferences, deserialized.Preferences); - Assert.NotNull(deserialized.Profile); - Assert.Equal(expectedProfile.Count, deserialized.Profile.Count); - foreach (var item in expectedProfile) - { - Assert.True(deserialized.Profile.TryGetValue(item.Key, out var value)); - - Assert.True(JsonElement.DeepEquals(value, deserialized.Profile[item.Key])); - } - Assert.Equal(expectedRecipient, deserialized.Recipient); - Assert.Equal(expectedTo, deserialized.To); - Assert.Equal(expectedStatus, deserialized.Status); - Assert.Equal(expectedMessageID, deserialized.MessageID); - } - - [Fact] - public void Validation_Works() - { - var model = new Item - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }; - - model.Validate(); - } - - [Fact] - public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() - { - var model = new Item - { - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - Status = Status.Pending, - MessageID = "messageId", - }; - - Assert.Null(model.Data); - Assert.False(model.RawData.ContainsKey("data")); - Assert.Null(model.Preferences); - Assert.False(model.RawData.ContainsKey("preferences")); - Assert.Null(model.To); - Assert.False(model.RawData.ContainsKey("to")); - } - - [Fact] - public void OptionalNonNullablePropertiesUnsetValidation_Works() - { - var model = new Item - { - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - Status = Status.Pending, - MessageID = "messageId", - }; - - model.Validate(); - } - - [Fact] - public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() - { - var model = new Item - { - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - Status = Status.Pending, - MessageID = "messageId", - - // Null should be interpreted as omitted for these properties - Data = null, - Preferences = null, - To = null, - }; - - Assert.Null(model.Data); - Assert.False(model.RawData.ContainsKey("data")); - Assert.Null(model.Preferences); - Assert.False(model.RawData.ContainsKey("preferences")); - Assert.Null(model.To); - Assert.False(model.RawData.ContainsKey("to")); - } - - [Fact] - public void OptionalNonNullablePropertiesSetToNullValidation_Works() - { - var model = new Item - { - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - Status = Status.Pending, - MessageID = "messageId", - - // Null should be interpreted as omitted for these properties - Data = null, - Preferences = null, - To = null, - }; - - model.Validate(); - } - - [Fact] - public void OptionalNullablePropertiesUnsetAreNotSet_Works() - { - var model = new Item - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - }; - - Assert.Null(model.Profile); - Assert.False(model.RawData.ContainsKey("profile")); - Assert.Null(model.Recipient); - Assert.False(model.RawData.ContainsKey("recipient")); - Assert.Null(model.MessageID); - Assert.False(model.RawData.ContainsKey("messageId")); - } - - [Fact] - public void OptionalNullablePropertiesUnsetValidation_Works() - { - var model = new Item - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - }; - - model.Validate(); - } - - [Fact] - public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() - { - var model = new Item - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - - Profile = null, - Recipient = null, - MessageID = null, - }; - - Assert.Null(model.Profile); - Assert.True(model.RawData.ContainsKey("profile")); - Assert.Null(model.Recipient); - Assert.True(model.RawData.ContainsKey("recipient")); - Assert.Null(model.MessageID); - Assert.True(model.RawData.ContainsKey("messageId")); - } - - [Fact] - public void OptionalNullablePropertiesSetToNullValidation_Works() - { - var model = new Item - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - - Profile = null, - Recipient = null, - MessageID = null, - }; - - model.Validate(); - } - - [Fact] - public void CopyConstructor_Works() - { - var model = new Item - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = [new(Models::ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = Models::PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(Models::ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Models::Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - Status = Status.Pending, - MessageID = "messageId", - }; - - Item copied = new(model); - - Assert.Equal(model, copied); - } -} - -public class IntersectionMember1Test : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var model = new IntersectionMember1 { Status = Status.Pending, MessageID = "messageId" }; - - ApiEnum expectedStatus = Status.Pending; - string expectedMessageID = "messageId"; - - Assert.Equal(expectedStatus, model.Status); - Assert.Equal(expectedMessageID, model.MessageID); - } - - [Fact] - public void SerializationRoundtrip_Works() - { - var model = new IntersectionMember1 { Status = Status.Pending, MessageID = "messageId" }; - - string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(model, deserialized); - } - - [Fact] - public void FieldRoundtripThroughSerialization_Works() - { - var model = new IntersectionMember1 { Status = Status.Pending, MessageID = "messageId" }; - - string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - Assert.NotNull(deserialized); - - ApiEnum expectedStatus = Status.Pending; - string expectedMessageID = "messageId"; - - Assert.Equal(expectedStatus, deserialized.Status); - Assert.Equal(expectedMessageID, deserialized.MessageID); - } - - [Fact] - public void Validation_Works() - { - var model = new IntersectionMember1 { Status = Status.Pending, MessageID = "messageId" }; - - model.Validate(); - } - - [Fact] - public void OptionalNullablePropertiesUnsetAreNotSet_Works() - { - var model = new IntersectionMember1 { Status = Status.Pending }; - - Assert.Null(model.MessageID); - Assert.False(model.RawData.ContainsKey("messageId")); - } - - [Fact] - public void OptionalNullablePropertiesUnsetValidation_Works() - { - var model = new IntersectionMember1 { Status = Status.Pending }; - - model.Validate(); - } - - [Fact] - public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() - { - var model = new IntersectionMember1 - { - Status = Status.Pending, - - MessageID = null, - }; - - Assert.Null(model.MessageID); - Assert.True(model.RawData.ContainsKey("messageId")); - } - - [Fact] - public void OptionalNullablePropertiesSetToNullValidation_Works() - { - var model = new IntersectionMember1 - { - Status = Status.Pending, - - MessageID = null, - }; - - model.Validate(); - } - - [Fact] - public void CopyConstructor_Works() - { - var model = new IntersectionMember1 { Status = Status.Pending, MessageID = "messageId" }; - - IntersectionMember1 copied = new(model); - - Assert.Equal(model, copied); - } -} - -public class StatusTest : TestBase -{ - [Theory] - [InlineData(Status.Pending)] - [InlineData(Status.Enqueued)] - [InlineData(Status.Error)] - public void Validation_Works(Status rawValue) - { - // force implicit conversion because Theory can't do that for us - ApiEnum value = rawValue; - value.Validate(); - } - - [Fact] - public void InvalidEnumValidationThrows_Works() - { - var value = JsonSerializer.Deserialize>( - JsonSerializer.SerializeToElement("invalid value"), - ModelBase.SerializerOptions - ); - - Assert.NotNull(value); - Assert.Throws(() => value.Validate()); - } - - [Theory] - [InlineData(Status.Pending)] - [InlineData(Status.Enqueued)] - [InlineData(Status.Error)] - public void SerializationRoundtrip_Works(Status rawValue) - { - // force implicit conversion because Theory can't do that for us - ApiEnum value = rawValue; - - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize>( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(value, deserialized); - } - - [Fact] - public void InvalidEnumSerializationRoundtrip_Works() - { - var value = JsonSerializer.Deserialize>( - JsonSerializer.SerializeToElement("invalid value"), - ModelBase.SerializerOptions - ); - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize>( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(value, deserialized); - } -} diff --git a/src/TryCourier.Tests/Models/Bulk/BulkRetrieveJobParamsTest.cs b/src/TryCourier.Tests/Models/Bulk/BulkRetrieveJobParamsTest.cs deleted file mode 100644 index 3ac9530f..00000000 --- a/src/TryCourier.Tests/Models/Bulk/BulkRetrieveJobParamsTest.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using TryCourier.Models.Bulk; - -namespace TryCourier.Tests.Models.Bulk; - -public class BulkRetrieveJobParamsTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var parameters = new BulkRetrieveJobParams { JobID = "job_id" }; - - string expectedJobID = "job_id"; - - Assert.Equal(expectedJobID, parameters.JobID); - } - - [Fact] - public void Url_Works() - { - BulkRetrieveJobParams parameters = new() { JobID = "job_id" }; - - var url = parameters.Url(new() { ApiKey = "My API Key" }); - - Assert.True(TestBase.UrisEqual(new Uri("https://api.courier.com/bulk/job_id"), url)); - } - - [Fact] - public void CopyConstructor_Works() - { - var parameters = new BulkRetrieveJobParams { JobID = "job_id" }; - - BulkRetrieveJobParams copied = new(parameters); - - Assert.Equal(parameters, copied); - } -} diff --git a/src/TryCourier.Tests/Models/Bulk/BulkRetrieveJobResponseTest.cs b/src/TryCourier.Tests/Models/Bulk/BulkRetrieveJobResponseTest.cs deleted file mode 100644 index a39df198..00000000 --- a/src/TryCourier.Tests/Models/Bulk/BulkRetrieveJobResponseTest.cs +++ /dev/null @@ -1,639 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json; -using TryCourier.Core; -using TryCourier.Exceptions; -using TryCourier.Models; -using TryCourier.Models.Bulk; - -namespace TryCourier.Tests.Models.Bulk; - -public class BulkRetrieveJobResponseTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var model = new BulkRetrieveJobResponse - { - Job = new() - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }, - }; - - Job expectedJob = new() - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }; - - Assert.Equal(expectedJob, model.Job); - } - - [Fact] - public void SerializationRoundtrip_Works() - { - var model = new BulkRetrieveJobResponse - { - Job = new() - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }, - }; - - string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(model, deserialized); - } - - [Fact] - public void FieldRoundtripThroughSerialization_Works() - { - var model = new BulkRetrieveJobResponse - { - Job = new() - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }, - }; - - string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - Assert.NotNull(deserialized); - - Job expectedJob = new() - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }; - - Assert.Equal(expectedJob, deserialized.Job); - } - - [Fact] - public void Validation_Works() - { - var model = new BulkRetrieveJobResponse - { - Job = new() - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }, - }; - - model.Validate(); - } - - [Fact] - public void CopyConstructor_Works() - { - var model = new BulkRetrieveJobResponse - { - Job = new() - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }, - }; - - BulkRetrieveJobResponse copied = new(model); - - Assert.Equal(model, copied); - } -} - -public class JobTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var model = new Job - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }; - - InboundBulkMessage expectedDefinition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }; - long expectedEnqueued = 0; - long expectedFailures = 0; - long expectedReceived = 0; - ApiEnum expectedStatus = JobStatus.Created; - - Assert.Equal(expectedDefinition, model.Definition); - Assert.Equal(expectedEnqueued, model.Enqueued); - Assert.Equal(expectedFailures, model.Failures); - Assert.Equal(expectedReceived, model.Received); - Assert.Equal(expectedStatus, model.Status); - } - - [Fact] - public void SerializationRoundtrip_Works() - { - var model = new Job - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }; - - string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize(json, ModelBase.SerializerOptions); - - Assert.Equal(model, deserialized); - } - - [Fact] - public void FieldRoundtripThroughSerialization_Works() - { - var model = new Job - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }; - - string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize(element, ModelBase.SerializerOptions); - Assert.NotNull(deserialized); - - InboundBulkMessage expectedDefinition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }; - long expectedEnqueued = 0; - long expectedFailures = 0; - long expectedReceived = 0; - ApiEnum expectedStatus = JobStatus.Created; - - Assert.Equal(expectedDefinition, deserialized.Definition); - Assert.Equal(expectedEnqueued, deserialized.Enqueued); - Assert.Equal(expectedFailures, deserialized.Failures); - Assert.Equal(expectedReceived, deserialized.Received); - Assert.Equal(expectedStatus, deserialized.Status); - } - - [Fact] - public void Validation_Works() - { - var model = new Job - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }; - - model.Validate(); - } - - [Fact] - public void CopyConstructor_Works() - { - var model = new Job - { - Definition = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - Enqueued = 0, - Failures = 0, - Received = 0, - Status = JobStatus.Created, - }; - - Job copied = new(model); - - Assert.Equal(model, copied); - } -} - -public class JobStatusTest : TestBase -{ - [Theory] - [InlineData(JobStatus.Created)] - [InlineData(JobStatus.Processing)] - [InlineData(JobStatus.Completed)] - [InlineData(JobStatus.Error)] - public void Validation_Works(JobStatus rawValue) - { - // force implicit conversion because Theory can't do that for us - ApiEnum value = rawValue; - value.Validate(); - } - - [Fact] - public void InvalidEnumValidationThrows_Works() - { - var value = JsonSerializer.Deserialize>( - JsonSerializer.SerializeToElement("invalid value"), - ModelBase.SerializerOptions - ); - - Assert.NotNull(value); - Assert.Throws(() => value.Validate()); - } - - [Theory] - [InlineData(JobStatus.Created)] - [InlineData(JobStatus.Processing)] - [InlineData(JobStatus.Completed)] - [InlineData(JobStatus.Error)] - public void SerializationRoundtrip_Works(JobStatus rawValue) - { - // force implicit conversion because Theory can't do that for us - ApiEnum value = rawValue; - - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize>( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(value, deserialized); - } - - [Fact] - public void InvalidEnumSerializationRoundtrip_Works() - { - var value = JsonSerializer.Deserialize>( - JsonSerializer.SerializeToElement("invalid value"), - ModelBase.SerializerOptions - ); - string json = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize>( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(value, deserialized); - } -} diff --git a/src/TryCourier.Tests/Models/Bulk/BulkRunJobParamsTest.cs b/src/TryCourier.Tests/Models/Bulk/BulkRunJobParamsTest.cs deleted file mode 100644 index 1d734998..00000000 --- a/src/TryCourier.Tests/Models/Bulk/BulkRunJobParamsTest.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using TryCourier.Models.Bulk; - -namespace TryCourier.Tests.Models.Bulk; - -public class BulkRunJobParamsTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var parameters = new BulkRunJobParams { JobID = "job_id" }; - - string expectedJobID = "job_id"; - - Assert.Equal(expectedJobID, parameters.JobID); - } - - [Fact] - public void Url_Works() - { - BulkRunJobParams parameters = new() { JobID = "job_id" }; - - var url = parameters.Url(new() { ApiKey = "My API Key" }); - - Assert.True(TestBase.UrisEqual(new Uri("https://api.courier.com/bulk/job_id/run"), url)); - } - - [Fact] - public void CopyConstructor_Works() - { - var parameters = new BulkRunJobParams { JobID = "job_id" }; - - BulkRunJobParams copied = new(parameters); - - Assert.Equal(parameters, copied); - } -} diff --git a/src/TryCourier.Tests/Models/Bulk/InboundBulkMessageTest.cs b/src/TryCourier.Tests/Models/Bulk/InboundBulkMessageTest.cs deleted file mode 100644 index 694036b3..00000000 --- a/src/TryCourier.Tests/Models/Bulk/InboundBulkMessageTest.cs +++ /dev/null @@ -1,444 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json; -using TryCourier.Core; -using TryCourier.Models; -using TryCourier.Models.Bulk; - -namespace TryCourier.Tests.Models.Bulk; - -public class InboundBulkMessageTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var model = new InboundBulkMessage - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }; - - string expectedEvent = "event"; - string expectedBrand = "brand"; - Content expectedContent = new ElementalContentSugar() { Body = "body", Title = "title" }; - Dictionary expectedData = new() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }; - Dictionary> expectedLocale = new() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }; - Dictionary expectedOverride = new() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }; - string expectedTemplate = "template"; - - Assert.Equal(expectedEvent, model.Event); - Assert.Equal(expectedBrand, model.Brand); - Assert.Equal(expectedContent, model.Content); - Assert.NotNull(model.Data); - Assert.Equal(expectedData.Count, model.Data.Count); - foreach (var item in expectedData) - { - Assert.True(model.Data.TryGetValue(item.Key, out var value)); - - Assert.True(JsonElement.DeepEquals(value, model.Data[item.Key])); - } - Assert.NotNull(model.Locale); - Assert.Equal(expectedLocale.Count, model.Locale.Count); - foreach (var item in expectedLocale) - { - Assert.True(model.Locale.TryGetValue(item.Key, out var value)); - - Assert.Equal(value.Count, model.Locale[item.Key].Count); - foreach (var item1 in value) - { - Assert.True(model.Locale[item.Key].TryGetValue(item1.Key, out var value1)); - - Assert.True(JsonElement.DeepEquals(value1, model.Locale[item.Key][item1.Key])); - } - } - Assert.NotNull(model.Override); - Assert.Equal(expectedOverride.Count, model.Override.Count); - foreach (var item in expectedOverride) - { - Assert.True(model.Override.TryGetValue(item.Key, out var value)); - - Assert.True(JsonElement.DeepEquals(value, model.Override[item.Key])); - } - Assert.Equal(expectedTemplate, model.Template); - } - - [Fact] - public void SerializationRoundtrip_Works() - { - var model = new InboundBulkMessage - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }; - - string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(model, deserialized); - } - - [Fact] - public void FieldRoundtripThroughSerialization_Works() - { - var model = new InboundBulkMessage - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }; - - string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - Assert.NotNull(deserialized); - - string expectedEvent = "event"; - string expectedBrand = "brand"; - Content expectedContent = new ElementalContentSugar() { Body = "body", Title = "title" }; - Dictionary expectedData = new() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }; - Dictionary> expectedLocale = new() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }; - Dictionary expectedOverride = new() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }; - string expectedTemplate = "template"; - - Assert.Equal(expectedEvent, deserialized.Event); - Assert.Equal(expectedBrand, deserialized.Brand); - Assert.Equal(expectedContent, deserialized.Content); - Assert.NotNull(deserialized.Data); - Assert.Equal(expectedData.Count, deserialized.Data.Count); - foreach (var item in expectedData) - { - Assert.True(deserialized.Data.TryGetValue(item.Key, out var value)); - - Assert.True(JsonElement.DeepEquals(value, deserialized.Data[item.Key])); - } - Assert.NotNull(deserialized.Locale); - Assert.Equal(expectedLocale.Count, deserialized.Locale.Count); - foreach (var item in expectedLocale) - { - Assert.True(deserialized.Locale.TryGetValue(item.Key, out var value)); - - Assert.Equal(value.Count, deserialized.Locale[item.Key].Count); - foreach (var item1 in value) - { - Assert.True(deserialized.Locale[item.Key].TryGetValue(item1.Key, out var value1)); - - Assert.True( - JsonElement.DeepEquals(value1, deserialized.Locale[item.Key][item1.Key]) - ); - } - } - Assert.NotNull(deserialized.Override); - Assert.Equal(expectedOverride.Count, deserialized.Override.Count); - foreach (var item in expectedOverride) - { - Assert.True(deserialized.Override.TryGetValue(item.Key, out var value)); - - Assert.True(JsonElement.DeepEquals(value, deserialized.Override[item.Key])); - } - Assert.Equal(expectedTemplate, deserialized.Template); - } - - [Fact] - public void Validation_Works() - { - var model = new InboundBulkMessage - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }; - - model.Validate(); - } - - [Fact] - public void OptionalNullablePropertiesUnsetAreNotSet_Works() - { - var model = new InboundBulkMessage { Event = "event" }; - - Assert.Null(model.Brand); - Assert.False(model.RawData.ContainsKey("brand")); - Assert.Null(model.Content); - Assert.False(model.RawData.ContainsKey("content")); - Assert.Null(model.Data); - Assert.False(model.RawData.ContainsKey("data")); - Assert.Null(model.Locale); - Assert.False(model.RawData.ContainsKey("locale")); - Assert.Null(model.Override); - Assert.False(model.RawData.ContainsKey("override")); - Assert.Null(model.Template); - Assert.False(model.RawData.ContainsKey("template")); - } - - [Fact] - public void OptionalNullablePropertiesUnsetValidation_Works() - { - var model = new InboundBulkMessage { Event = "event" }; - - model.Validate(); - } - - [Fact] - public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() - { - var model = new InboundBulkMessage - { - Event = "event", - - Brand = null, - Content = null, - Data = null, - Locale = null, - Override = null, - Template = null, - }; - - Assert.Null(model.Brand); - Assert.True(model.RawData.ContainsKey("brand")); - Assert.Null(model.Content); - Assert.True(model.RawData.ContainsKey("content")); - Assert.Null(model.Data); - Assert.True(model.RawData.ContainsKey("data")); - Assert.Null(model.Locale); - Assert.True(model.RawData.ContainsKey("locale")); - Assert.Null(model.Override); - Assert.True(model.RawData.ContainsKey("override")); - Assert.Null(model.Template); - Assert.True(model.RawData.ContainsKey("template")); - } - - [Fact] - public void OptionalNullablePropertiesSetToNullValidation_Works() - { - var model = new InboundBulkMessage - { - Event = "event", - - Brand = null, - Content = null, - Data = null, - Locale = null, - Override = null, - Template = null, - }; - - model.Validate(); - } - - [Fact] - public void CopyConstructor_Works() - { - var model = new InboundBulkMessage - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }; - - InboundBulkMessage copied = new(model); - - Assert.Equal(model, copied); - } -} - -public class ContentTest : TestBase -{ - [Fact] - public void ElementalContentSugarValidationWorks() - { - Content value = new ElementalContentSugar() { Body = "body", Title = "title" }; - value.Validate(); - } - - [Fact] - public void ElementalValidationWorks() - { - Content value = new ElementalContent() - { - Elements = - [ - new ElementalTextNodeWithType() - { - Channels = ["string"], - If = "if", - Loop = "loop", - Ref = "ref", - Type = ElementalTextNodeWithTypeIntersectionMember1Type.Text, - }, - ], - Version = "version", - }; - value.Validate(); - } - - [Fact] - public void ElementalContentSugarSerializationRoundtripWorks() - { - Content value = new ElementalContentSugar() { Body = "body", Title = "title" }; - string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - - Assert.Equal(value, deserialized); - } - - [Fact] - public void ElementalSerializationRoundtripWorks() - { - Content value = new ElementalContent() - { - Elements = - [ - new ElementalTextNodeWithType() - { - Channels = ["string"], - If = "if", - Loop = "loop", - Ref = "ref", - Type = ElementalTextNodeWithTypeIntersectionMember1Type.Text, - }, - ], - Version = "version", - }; - string element = JsonSerializer.Serialize(value, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - - Assert.Equal(value, deserialized); - } -} diff --git a/src/TryCourier.Tests/Models/Bulk/InboundBulkMessageUserTest.cs b/src/TryCourier.Tests/Models/Bulk/InboundBulkMessageUserTest.cs deleted file mode 100644 index 7ea2de67..00000000 --- a/src/TryCourier.Tests/Models/Bulk/InboundBulkMessageUserTest.cs +++ /dev/null @@ -1,1071 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json; -using TryCourier.Core; -using TryCourier.Models; -using TryCourier.Models.Bulk; - -namespace TryCourier.Tests.Models.Bulk; - -public class InboundBulkMessageUserTest : TestBase -{ - [Fact] - public void FieldRoundtrip_Works() - { - var model = new InboundBulkMessageUser - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }; - - JsonElement expectedData = JsonSerializer.Deserialize("{}"); - RecipientPreferences expectedPreferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }; - Dictionary expectedProfile = new() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }; - string expectedRecipient = "recipient"; - UserRecipient expectedTo = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }; - - Assert.NotNull(model.Data); - Assert.True(JsonElement.DeepEquals(expectedData, model.Data.Value)); - Assert.Equal(expectedPreferences, model.Preferences); - Assert.NotNull(model.Profile); - Assert.Equal(expectedProfile.Count, model.Profile.Count); - foreach (var item in expectedProfile) - { - Assert.True(model.Profile.TryGetValue(item.Key, out var value)); - - Assert.True(JsonElement.DeepEquals(value, model.Profile[item.Key])); - } - Assert.Equal(expectedRecipient, model.Recipient); - Assert.Equal(expectedTo, model.To); - } - - [Fact] - public void SerializationRoundtrip_Works() - { - var model = new InboundBulkMessageUser - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }; - - string json = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - json, - ModelBase.SerializerOptions - ); - - Assert.Equal(model, deserialized); - } - - [Fact] - public void FieldRoundtripThroughSerialization_Works() - { - var model = new InboundBulkMessageUser - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }; - - string element = JsonSerializer.Serialize(model, ModelBase.SerializerOptions); - var deserialized = JsonSerializer.Deserialize( - element, - ModelBase.SerializerOptions - ); - Assert.NotNull(deserialized); - - JsonElement expectedData = JsonSerializer.Deserialize("{}"); - RecipientPreferences expectedPreferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }; - Dictionary expectedProfile = new() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }; - string expectedRecipient = "recipient"; - UserRecipient expectedTo = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }; - - Assert.NotNull(deserialized.Data); - Assert.True(JsonElement.DeepEquals(expectedData, deserialized.Data.Value)); - Assert.Equal(expectedPreferences, deserialized.Preferences); - Assert.NotNull(deserialized.Profile); - Assert.Equal(expectedProfile.Count, deserialized.Profile.Count); - foreach (var item in expectedProfile) - { - Assert.True(deserialized.Profile.TryGetValue(item.Key, out var value)); - - Assert.True(JsonElement.DeepEquals(value, deserialized.Profile[item.Key])); - } - Assert.Equal(expectedRecipient, deserialized.Recipient); - Assert.Equal(expectedTo, deserialized.To); - } - - [Fact] - public void Validation_Works() - { - var model = new InboundBulkMessageUser - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }; - - model.Validate(); - } - - [Fact] - public void OptionalNonNullablePropertiesUnsetAreNotSet_Works() - { - var model = new InboundBulkMessageUser - { - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }; - - Assert.Null(model.Data); - Assert.False(model.RawData.ContainsKey("data")); - } - - [Fact] - public void OptionalNonNullablePropertiesUnsetValidation_Works() - { - var model = new InboundBulkMessageUser - { - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }; - - model.Validate(); - } - - [Fact] - public void OptionalNonNullablePropertiesSetToNullAreNotSet_Works() - { - var model = new InboundBulkMessageUser - { - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - - // Null should be interpreted as omitted for these properties - Data = null, - }; - - Assert.Null(model.Data); - Assert.False(model.RawData.ContainsKey("data")); - } - - [Fact] - public void OptionalNonNullablePropertiesSetToNullValidation_Works() - { - var model = new InboundBulkMessageUser - { - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - - // Null should be interpreted as omitted for these properties - Data = null, - }; - - model.Validate(); - } - - [Fact] - public void OptionalNullablePropertiesUnsetAreNotSet_Works() - { - var model = new InboundBulkMessageUser - { - Data = JsonSerializer.Deserialize("{}"), - }; - - Assert.Null(model.Preferences); - Assert.False(model.RawData.ContainsKey("preferences")); - Assert.Null(model.Profile); - Assert.False(model.RawData.ContainsKey("profile")); - Assert.Null(model.Recipient); - Assert.False(model.RawData.ContainsKey("recipient")); - Assert.Null(model.To); - Assert.False(model.RawData.ContainsKey("to")); - } - - [Fact] - public void OptionalNullablePropertiesUnsetValidation_Works() - { - var model = new InboundBulkMessageUser - { - Data = JsonSerializer.Deserialize("{}"), - }; - - model.Validate(); - } - - [Fact] - public void OptionalNullablePropertiesSetToNullAreSetToNull_Works() - { - var model = new InboundBulkMessageUser - { - Data = JsonSerializer.Deserialize("{}"), - - Preferences = null, - Profile = null, - Recipient = null, - To = null, - }; - - Assert.Null(model.Preferences); - Assert.True(model.RawData.ContainsKey("preferences")); - Assert.Null(model.Profile); - Assert.True(model.RawData.ContainsKey("profile")); - Assert.Null(model.Recipient); - Assert.True(model.RawData.ContainsKey("recipient")); - Assert.Null(model.To); - Assert.True(model.RawData.ContainsKey("to")); - } - - [Fact] - public void OptionalNullablePropertiesSetToNullValidation_Works() - { - var model = new InboundBulkMessageUser - { - Data = JsonSerializer.Deserialize("{}"), - - Preferences = null, - Profile = null, - Recipient = null, - To = null, - }; - - model.Validate(); - } - - [Fact] - public void CopyConstructor_Works() - { - var model = new InboundBulkMessageUser - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = [new(ChannelClassification.DirectMessage)], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }; - - InboundBulkMessageUser copied = new(model); - - Assert.Equal(model, copied); - } -} diff --git a/src/TryCourier.Tests/Services/BulkServiceTest.cs b/src/TryCourier.Tests/Services/BulkServiceTest.cs deleted file mode 100644 index 8e4cd52a..00000000 --- a/src/TryCourier.Tests/Services/BulkServiceTest.cs +++ /dev/null @@ -1,182 +0,0 @@ -using System.Collections.Generic; -using System.Text.Json; -using System.Threading.Tasks; -using TryCourier.Models; - -namespace TryCourier.Tests.Services; - -public class BulkServiceTest : TestBase -{ - [Fact(Skip = "Mock server tests are disabled")] - public async Task AddUsers_Works() - { - await this.client.Bulk.AddUsers( - "job_id", - new() - { - Users = - [ - new() - { - Data = JsonSerializer.Deserialize("{}"), - Preferences = new() - { - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - } - }, - }, - }, - Profile = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Recipient = "recipient", - To = new() - { - AccountID = "account_id", - Context = new() { TenantID = "tenant_id" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Email = "email", - ListID = "list_id", - Locale = "locale", - PhoneNumber = "phone_number", - Preferences = new() - { - Notifications = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - Categories = new Dictionary() - { - { - "foo", - new() - { - Status = PreferenceStatus.OptedIn, - ChannelPreferences = - [ - new(ChannelClassification.DirectMessage), - ], - Rules = [new() { Until = "until", Start = "start" }], - Source = Source.Subscription, - } - }, - }, - TemplateID = "templateId", - }, - TenantID = "tenant_id", - UserID = "user_id", - }, - }, - ], - }, - TestContext.Current.CancellationToken - ); - } - - [Fact(Skip = "Mock server tests are disabled")] - public async Task CreateJob_Works() - { - var response = await this.client.Bulk.CreateJob( - new() - { - Message = new() - { - Event = "event", - Brand = "brand", - Content = new ElementalContentSugar() { Body = "body", Title = "title" }, - Data = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Locale = new Dictionary>() - { - { - "foo", - new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - } - }, - }, - Override = new Dictionary() - { - { "foo", JsonSerializer.SerializeToElement("bar") }, - }, - Template = "template", - }, - }, - TestContext.Current.CancellationToken - ); - response.Validate(); - } - - [Fact(Skip = "Mock server tests are disabled")] - public async Task ListUsers_Works() - { - var response = await this.client.Bulk.ListUsers( - "job_id", - new(), - TestContext.Current.CancellationToken - ); - response.Validate(); - } - - [Fact(Skip = "Mock server tests are disabled")] - public async Task RetrieveJob_Works() - { - var response = await this.client.Bulk.RetrieveJob( - "job_id", - new(), - TestContext.Current.CancellationToken - ); - response.Validate(); - } - - [Fact(Skip = "Mock server tests are disabled")] - public async Task RunJob_Works() - { - await this.client.Bulk.RunJob("job_id", new(), TestContext.Current.CancellationToken); - } -} diff --git a/src/TryCourier/Core/ModelBase.cs b/src/TryCourier/Core/ModelBase.cs index 87297b72..c43782fa 100644 --- a/src/TryCourier/Core/ModelBase.cs +++ b/src/TryCourier/Core/ModelBase.cs @@ -3,7 +3,7 @@ using TryCourier.Models; using TryCourier.Models.Automations; using TryCourier.Models.Brands; -using TryCourier.Models.Bulk; +using TryCourier.Models.Messages; using TryCourier.Models.WorkspacePreferences; using Audiences = TryCourier.Models.Audiences; using Digests = TryCourier.Models.Digests; @@ -12,7 +12,6 @@ using Items = TryCourier.Models.Tenants.Preferences.Items; using Journeys = TryCourier.Models.Journeys; using Lists = TryCourier.Models.Profiles.Lists; -using Messages = TryCourier.Models.Messages; using Notifications = TryCourier.Models.Notifications; using Profiles = TryCourier.Models.Profiles; using Send = TryCourier.Models.Send; @@ -136,14 +135,12 @@ protected ModelBase(ModelBase modelBase) Templates::TemplateReplaceParamsNotificationContentScope >(), new ApiEnumConverter(), - new ApiEnumConverter(), - new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), - new ApiEnumConverter(), - new ApiEnumConverter(), + new ApiEnumConverter(), + new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), new ApiEnumConverter(), diff --git a/src/TryCourier/CourierClient.cs b/src/TryCourier/CourierClient.cs index 2e3f8b59..72e933b0 100644 --- a/src/TryCourier/CourierClient.cs +++ b/src/TryCourier/CourierClient.cs @@ -120,12 +120,6 @@ public IBrandService Brands get { return _brands.Value; } } - readonly Lazy _bulk; - public IBulkService Bulk - { - get { return _bulk.Value; } - } - readonly Lazy _digests; public IDigestService Digests { @@ -213,7 +207,6 @@ public CourierClient() _automations = new(() => new AutomationService(this)); _journeys = new(() => new JourneyService(this)); _brands = new(() => new BrandService(this)); - _bulk = new(() => new BulkService(this)); _digests = new(() => new DigestService(this)); _inbound = new(() => new InboundService(this)); _lists = new(() => new ListService(this)); @@ -349,12 +342,6 @@ public IBrandServiceWithRawResponse Brands get { return _brands.Value; } } - readonly Lazy _bulk; - public IBulkServiceWithRawResponse Bulk - { - get { return _bulk.Value; } - } - readonly Lazy _digests; public IDigestServiceWithRawResponse Digests { @@ -633,7 +620,6 @@ public CourierClientWithRawResponse() _automations = new(() => new AutomationServiceWithRawResponse(this)); _journeys = new(() => new JourneyServiceWithRawResponse(this)); _brands = new(() => new BrandServiceWithRawResponse(this)); - _bulk = new(() => new BulkServiceWithRawResponse(this)); _digests = new(() => new DigestServiceWithRawResponse(this)); _inbound = new(() => new InboundServiceWithRawResponse(this)); _lists = new(() => new ListServiceWithRawResponse(this)); diff --git a/src/TryCourier/ICourierClient.cs b/src/TryCourier/ICourierClient.cs index f1de10d1..f830c142 100644 --- a/src/TryCourier/ICourierClient.cs +++ b/src/TryCourier/ICourierClient.cs @@ -67,8 +67,6 @@ public interface ICourierClient : IDisposable IBrandService Brands { get; } - IBulkService Bulk { get; } - IDigestService Digests { get; } IInboundService Inbound { get; } @@ -139,8 +137,6 @@ public interface ICourierClientWithRawResponse : IDisposable IBrandServiceWithRawResponse Brands { get; } - IBulkServiceWithRawResponse Bulk { get; } - IDigestServiceWithRawResponse Digests { get; } IInboundServiceWithRawResponse Inbound { get; } diff --git a/src/TryCourier/Models/Bulk/BulkAddUsersParams.cs b/src/TryCourier/Models/Bulk/BulkAddUsersParams.cs deleted file mode 100644 index f76243ca..00000000 --- a/src/TryCourier/Models/Bulk/BulkAddUsersParams.cs +++ /dev/null @@ -1,170 +0,0 @@ -using System; -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using TryCourier.Core; - -namespace TryCourier.Models.Bulk; - -/// -/// Ingest user data into a Bulk Job. -/// -/// **Important**: For email-based bulk jobs, each user must include `profile.email` -/// for provider routing to work correctly. The `to.email` field is not sufficient -/// for email provider routing. -/// -/// NOTE: Do not inherit from this type outside the SDK unless you're okay with -/// breaking changes in non-major versions. We may add new methods in the future that -/// cause existing derived classes to break. -/// -public record class BulkAddUsersParams : ParamsBase -{ - readonly JsonDictionary _rawBodyData = new(); - public IReadOnlyDictionary RawBodyData - { - get { return this._rawBodyData.Freeze(); } - } - - public string? JobID { get; init; } - - public required IReadOnlyList Users - { - get - { - this._rawBodyData.Freeze(); - return this._rawBodyData.GetNotNullStruct>( - "users" - ); - } - init - { - this._rawBodyData.Set>( - "users", - ImmutableArray.ToImmutableArray(value) - ); - } - } - - public BulkAddUsersParams() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public BulkAddUsersParams(BulkAddUsersParams bulkAddUsersParams) - : base(bulkAddUsersParams) - { - this.JobID = bulkAddUsersParams.JobID; - - this._rawBodyData = new(bulkAddUsersParams._rawBodyData); - } -#pragma warning restore CS8618 - - public BulkAddUsersParams( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData, - IReadOnlyDictionary rawBodyData - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - this._rawBodyData = new(rawBodyData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - BulkAddUsersParams( - FrozenDictionary rawHeaderData, - FrozenDictionary rawQueryData, - FrozenDictionary rawBodyData, - string jobID - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - this._rawBodyData = new(rawBodyData); - this.JobID = jobID; - } -#pragma warning restore CS8618 - - /// - public static BulkAddUsersParams FromRawUnchecked( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData, - IReadOnlyDictionary rawBodyData, - string jobID - ) - { - return new( - FrozenDictionary.ToFrozenDictionary(rawHeaderData), - FrozenDictionary.ToFrozenDictionary(rawQueryData), - FrozenDictionary.ToFrozenDictionary(rawBodyData), - jobID - ); - } - - public override string ToString() => - JsonSerializer.Serialize( - FriendlyJsonPrinter.PrintValue( - new Dictionary() - { - ["JobID"] = JsonSerializer.SerializeToElement(this.JobID), - ["HeaderData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawHeaderData.Freeze()) - ), - ["QueryData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawQueryData.Freeze()) - ), - ["BodyData"] = FriendlyJsonPrinter.PrintValue(this._rawBodyData.Freeze()), - } - ), - ModelBase.ToStringSerializerOptions - ); - - public virtual bool Equals(BulkAddUsersParams? other) - { - if (other == null) - { - return false; - } - return (this.JobID?.Equals(other.JobID) ?? other.JobID == null) - && this._rawHeaderData.Equals(other._rawHeaderData) - && this._rawQueryData.Equals(other._rawQueryData) - && this._rawBodyData.Equals(other._rawBodyData); - } - - public override Uri Url(ClientOptions options) - { - return new UriBuilder( - options.BaseUrl.ToString().TrimEnd('/') + string.Format("/bulk/{0}", this.JobID) - ) - { - Query = this.QueryString(options), - }.Uri; - } - - internal override HttpContent? BodyContent() - { - return new StringContent( - JsonSerializer.Serialize(this.RawBodyData, ModelBase.SerializerOptions), - Encoding.UTF8, - "application/json" - ); - } - - internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) - { - ParamsBase.AddDefaultHeaders(request, options); - foreach (var item in this.RawHeaderData) - { - ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); - } - } - - public override int GetHashCode() - { - return 0; - } -} diff --git a/src/TryCourier/Models/Bulk/BulkCreateJobParams.cs b/src/TryCourier/Models/Bulk/BulkCreateJobParams.cs deleted file mode 100644 index c1888878..00000000 --- a/src/TryCourier/Models/Bulk/BulkCreateJobParams.cs +++ /dev/null @@ -1,156 +0,0 @@ -using System; -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using TryCourier.Core; - -namespace TryCourier.Models.Bulk; - -/// -/// Creates a new bulk job for sending messages to multiple recipients. -/// -/// **Required**: `message.event` (event ID or notification ID) -/// -/// **Optional (V2 format)**: `message.template` (notification ID) or `message.content` -/// (Elemental content) can be provided to override the notification associated -/// with the event. -/// -/// NOTE: Do not inherit from this type outside the SDK unless you're okay with -/// breaking changes in non-major versions. We may add new methods in the future that -/// cause existing derived classes to break. -/// -public record class BulkCreateJobParams : ParamsBase -{ - readonly JsonDictionary _rawBodyData = new(); - public IReadOnlyDictionary RawBodyData - { - get { return this._rawBodyData.Freeze(); } - } - - /// - /// Bulk message definition. Supports two formats: - V1 format: Requires `event` - /// field (event ID or notification ID) - V2 format: Optionally use `template` - /// (notification ID) or `content` (Elemental content) in addition to `event` - /// - public required InboundBulkMessage Message - { - get - { - this._rawBodyData.Freeze(); - return this._rawBodyData.GetNotNullClass("message"); - } - init { this._rawBodyData.Set("message", value); } - } - - public BulkCreateJobParams() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public BulkCreateJobParams(BulkCreateJobParams bulkCreateJobParams) - : base(bulkCreateJobParams) - { - this._rawBodyData = new(bulkCreateJobParams._rawBodyData); - } -#pragma warning restore CS8618 - - public BulkCreateJobParams( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData, - IReadOnlyDictionary rawBodyData - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - this._rawBodyData = new(rawBodyData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - BulkCreateJobParams( - FrozenDictionary rawHeaderData, - FrozenDictionary rawQueryData, - FrozenDictionary rawBodyData - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - this._rawBodyData = new(rawBodyData); - } -#pragma warning restore CS8618 - - /// - public static BulkCreateJobParams FromRawUnchecked( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData, - IReadOnlyDictionary rawBodyData - ) - { - return new( - FrozenDictionary.ToFrozenDictionary(rawHeaderData), - FrozenDictionary.ToFrozenDictionary(rawQueryData), - FrozenDictionary.ToFrozenDictionary(rawBodyData) - ); - } - - public override string ToString() => - JsonSerializer.Serialize( - FriendlyJsonPrinter.PrintValue( - new Dictionary() - { - ["HeaderData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawHeaderData.Freeze()) - ), - ["QueryData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawQueryData.Freeze()) - ), - ["BodyData"] = FriendlyJsonPrinter.PrintValue(this._rawBodyData.Freeze()), - } - ), - ModelBase.ToStringSerializerOptions - ); - - public virtual bool Equals(BulkCreateJobParams? other) - { - if (other == null) - { - return false; - } - return this._rawHeaderData.Equals(other._rawHeaderData) - && this._rawQueryData.Equals(other._rawQueryData) - && this._rawBodyData.Equals(other._rawBodyData); - } - - public override Uri Url(ClientOptions options) - { - return new UriBuilder(options.BaseUrl.ToString().TrimEnd('/') + "/bulk") - { - Query = this.QueryString(options), - }.Uri; - } - - internal override HttpContent? BodyContent() - { - return new StringContent( - JsonSerializer.Serialize(this.RawBodyData, ModelBase.SerializerOptions), - Encoding.UTF8, - "application/json" - ); - } - - internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) - { - ParamsBase.AddDefaultHeaders(request, options); - foreach (var item in this.RawHeaderData) - { - ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); - } - } - - public override int GetHashCode() - { - return 0; - } -} diff --git a/src/TryCourier/Models/Bulk/BulkCreateJobResponse.cs b/src/TryCourier/Models/Bulk/BulkCreateJobResponse.cs deleted file mode 100644 index fa3487de..00000000 --- a/src/TryCourier/Models/Bulk/BulkCreateJobResponse.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Text.Json; -using System.Text.Json.Serialization; -using TryCourier.Core; - -namespace TryCourier.Models.Bulk; - -[JsonConverter(typeof(JsonModelConverter))] -public sealed record class BulkCreateJobResponse : JsonModel -{ - public required string JobID - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass("jobId"); - } - init { this._rawData.Set("jobId", value); } - } - - /// - public override void Validate() - { - _ = this.JobID; - } - - public BulkCreateJobResponse() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public BulkCreateJobResponse(BulkCreateJobResponse bulkCreateJobResponse) - : base(bulkCreateJobResponse) { } -#pragma warning restore CS8618 - - public BulkCreateJobResponse(IReadOnlyDictionary rawData) - { - this._rawData = new(rawData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - BulkCreateJobResponse(FrozenDictionary rawData) - { - this._rawData = new(rawData); - } -#pragma warning restore CS8618 - - /// - public static BulkCreateJobResponse FromRawUnchecked( - IReadOnlyDictionary rawData - ) - { - return new(FrozenDictionary.ToFrozenDictionary(rawData)); - } - - [SetsRequiredMembers] - public BulkCreateJobResponse(string jobID) - : this() - { - this.JobID = jobID; - } -} - -class BulkCreateJobResponseFromRaw : IFromRawJson -{ - /// - public BulkCreateJobResponse FromRawUnchecked( - IReadOnlyDictionary rawData - ) => BulkCreateJobResponse.FromRawUnchecked(rawData); -} diff --git a/src/TryCourier/Models/Bulk/BulkListUsersParams.cs b/src/TryCourier/Models/Bulk/BulkListUsersParams.cs deleted file mode 100644 index 90871ed4..00000000 --- a/src/TryCourier/Models/Bulk/BulkListUsersParams.cs +++ /dev/null @@ -1,135 +0,0 @@ -using System; -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Net.Http; -using System.Text.Json; -using TryCourier.Core; - -namespace TryCourier.Models.Bulk; - -/// -/// Get Bulk Job Users -/// -/// NOTE: Do not inherit from this type outside the SDK unless you're okay with -/// breaking changes in non-major versions. We may add new methods in the future that -/// cause existing derived classes to break. -/// -public record class BulkListUsersParams : ParamsBase -{ - public string? JobID { get; init; } - - /// - /// A unique identifier that allows for fetching the next set of users added to - /// the bulk job - /// - public string? Cursor - { - get - { - this._rawQueryData.Freeze(); - return this._rawQueryData.GetNullableClass("cursor"); - } - init { this._rawQueryData.Set("cursor", value); } - } - - public BulkListUsersParams() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public BulkListUsersParams(BulkListUsersParams bulkListUsersParams) - : base(bulkListUsersParams) - { - this.JobID = bulkListUsersParams.JobID; - } -#pragma warning restore CS8618 - - public BulkListUsersParams( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - BulkListUsersParams( - FrozenDictionary rawHeaderData, - FrozenDictionary rawQueryData, - string jobID - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - this.JobID = jobID; - } -#pragma warning restore CS8618 - - /// - public static BulkListUsersParams FromRawUnchecked( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData, - string jobID - ) - { - return new( - FrozenDictionary.ToFrozenDictionary(rawHeaderData), - FrozenDictionary.ToFrozenDictionary(rawQueryData), - jobID - ); - } - - public override string ToString() => - JsonSerializer.Serialize( - FriendlyJsonPrinter.PrintValue( - new Dictionary() - { - ["JobID"] = JsonSerializer.SerializeToElement(this.JobID), - ["HeaderData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawHeaderData.Freeze()) - ), - ["QueryData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawQueryData.Freeze()) - ), - } - ), - ModelBase.ToStringSerializerOptions - ); - - public virtual bool Equals(BulkListUsersParams? other) - { - if (other == null) - { - return false; - } - return (this.JobID?.Equals(other.JobID) ?? other.JobID == null) - && this._rawHeaderData.Equals(other._rawHeaderData) - && this._rawQueryData.Equals(other._rawQueryData); - } - - public override Uri Url(ClientOptions options) - { - return new UriBuilder( - options.BaseUrl.ToString().TrimEnd('/') + string.Format("/bulk/{0}/users", this.JobID) - ) - { - Query = this.QueryString(options), - }.Uri; - } - - internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) - { - ParamsBase.AddDefaultHeaders(request, options); - foreach (var item in this.RawHeaderData) - { - ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); - } - } - - public override int GetHashCode() - { - return 0; - } -} diff --git a/src/TryCourier/Models/Bulk/BulkListUsersResponse.cs b/src/TryCourier/Models/Bulk/BulkListUsersResponse.cs deleted file mode 100644 index 0363074b..00000000 --- a/src/TryCourier/Models/Bulk/BulkListUsersResponse.cs +++ /dev/null @@ -1,383 +0,0 @@ -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics.CodeAnalysis; -using System.Text.Json; -using System.Text.Json.Serialization; -using TryCourier.Core; -using TryCourier.Exceptions; -using System = System; - -namespace TryCourier.Models.Bulk; - -[JsonConverter(typeof(JsonModelConverter))] -public sealed record class BulkListUsersResponse : JsonModel -{ - public required IReadOnlyList Items - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullStruct>("items"); - } - init - { - this._rawData.Set>( - "items", - ImmutableArray.ToImmutableArray(value) - ); - } - } - - public required Paging Paging - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass("paging"); - } - init { this._rawData.Set("paging", value); } - } - - /// - public override void Validate() - { - foreach (var item in this.Items) - { - item.Validate(); - } - this.Paging.Validate(); - } - - public BulkListUsersResponse() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public BulkListUsersResponse(BulkListUsersResponse bulkListUsersResponse) - : base(bulkListUsersResponse) { } -#pragma warning restore CS8618 - - public BulkListUsersResponse(IReadOnlyDictionary rawData) - { - this._rawData = new(rawData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - BulkListUsersResponse(FrozenDictionary rawData) - { - this._rawData = new(rawData); - } -#pragma warning restore CS8618 - - /// - public static BulkListUsersResponse FromRawUnchecked( - IReadOnlyDictionary rawData - ) - { - return new(FrozenDictionary.ToFrozenDictionary(rawData)); - } -} - -class BulkListUsersResponseFromRaw : IFromRawJson -{ - /// - public BulkListUsersResponse FromRawUnchecked( - IReadOnlyDictionary rawData - ) => BulkListUsersResponse.FromRawUnchecked(rawData); -} - -[JsonConverter(typeof(JsonModelConverter))] -public sealed record class Item : JsonModel -{ - /// - /// User-specific data that will be merged with message.data - /// - public JsonElement? Data - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableStruct("data"); - } - init - { - if (value == null) - { - return; - } - - this._rawData.Set("data", value); - } - } - - public RecipientPreferences? Preferences - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("preferences"); - } - init - { - if (value == null) - { - return; - } - - this._rawData.Set("preferences", value); - } - } - - /// - /// User profile information. For email-based bulk jobs, `profile.email` is required - /// for provider routing to determine if the message can be delivered. The email - /// address should be provided here rather than in `to.email`. - /// - public IReadOnlyDictionary? Profile - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass>("profile"); - } - init - { - this._rawData.Set?>( - "profile", - value == null ? null : FrozenDictionary.ToFrozenDictionary(value) - ); - } - } - - /// - /// User ID (legacy field, use profile or to.user_id instead) - /// - public string? Recipient - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("recipient"); - } - init { this._rawData.Set("recipient", value); } - } - - public UserRecipient? To - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("to"); - } - init - { - if (value == null) - { - return; - } - - this._rawData.Set("to", value); - } - } - - public required ApiEnum Status - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass>("status"); - } - init { this._rawData.Set("status", value); } - } - - public string? MessageID - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("messageId"); - } - init { this._rawData.Set("messageId", value); } - } - - public static implicit operator InboundBulkMessageUser(Item item) => - new() - { - Data = item.Data, - Preferences = item.Preferences, - Profile = item.Profile, - Recipient = item.Recipient, - To = item.To, - }; - - /// - public override void Validate() - { - _ = this.Data; - this.Preferences?.Validate(); - _ = this.Profile; - _ = this.Recipient; - this.To?.Validate(); - this.Status.Validate(); - _ = this.MessageID; - } - - public Item() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public Item(Item item) - : base(item) { } -#pragma warning restore CS8618 - - public Item(IReadOnlyDictionary rawData) - { - this._rawData = new(rawData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - Item(FrozenDictionary rawData) - { - this._rawData = new(rawData); - } -#pragma warning restore CS8618 - - /// - public static Item FromRawUnchecked(IReadOnlyDictionary rawData) - { - return new(FrozenDictionary.ToFrozenDictionary(rawData)); - } - - [SetsRequiredMembers] - public Item(ApiEnum status) - : this() - { - this.Status = status; - } -} - -class ItemFromRaw : IFromRawJson -{ - /// - public Item FromRawUnchecked(IReadOnlyDictionary rawData) => - Item.FromRawUnchecked(rawData); -} - -[JsonConverter(typeof(JsonModelConverter))] -public sealed record class IntersectionMember1 : JsonModel -{ - public required ApiEnum Status - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass>("status"); - } - init { this._rawData.Set("status", value); } - } - - public string? MessageID - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("messageId"); - } - init { this._rawData.Set("messageId", value); } - } - - /// - public override void Validate() - { - this.Status.Validate(); - _ = this.MessageID; - } - - public IntersectionMember1() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public IntersectionMember1(IntersectionMember1 intersectionMember1) - : base(intersectionMember1) { } -#pragma warning restore CS8618 - - public IntersectionMember1(IReadOnlyDictionary rawData) - { - this._rawData = new(rawData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - IntersectionMember1(FrozenDictionary rawData) - { - this._rawData = new(rawData); - } -#pragma warning restore CS8618 - - /// - public static IntersectionMember1 FromRawUnchecked( - IReadOnlyDictionary rawData - ) - { - return new(FrozenDictionary.ToFrozenDictionary(rawData)); - } - - [SetsRequiredMembers] - public IntersectionMember1(ApiEnum status) - : this() - { - this.Status = status; - } -} - -class IntersectionMember1FromRaw : IFromRawJson -{ - /// - public IntersectionMember1 FromRawUnchecked(IReadOnlyDictionary rawData) => - IntersectionMember1.FromRawUnchecked(rawData); -} - -[JsonConverter(typeof(StatusConverter))] -public enum Status -{ - Pending, - Enqueued, - Error, -} - -sealed class StatusConverter : JsonConverter -{ - public override Status Read( - ref Utf8JsonReader reader, - System::Type typeToConvert, - JsonSerializerOptions options - ) - { - return JsonSerializer.Deserialize(ref reader, options) switch - { - "PENDING" => Status.Pending, - "ENQUEUED" => Status.Enqueued, - "ERROR" => Status.Error, - _ => (Status)(-1), - }; - } - - public override void Write(Utf8JsonWriter writer, Status value, JsonSerializerOptions options) - { - JsonSerializer.Serialize( - writer, - value switch - { - Status.Pending => "PENDING", - Status.Enqueued => "ENQUEUED", - Status.Error => "ERROR", - _ => throw new CourierInvalidDataException( - string.Format("Invalid value '{0}' in {1}", value, nameof(value)) - ), - }, - options - ); - } -} diff --git a/src/TryCourier/Models/Bulk/BulkRetrieveJobParams.cs b/src/TryCourier/Models/Bulk/BulkRetrieveJobParams.cs deleted file mode 100644 index 38d7708c..00000000 --- a/src/TryCourier/Models/Bulk/BulkRetrieveJobParams.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Net.Http; -using System.Text.Json; -using TryCourier.Core; - -namespace TryCourier.Models.Bulk; - -/// -/// Get a bulk job -/// -/// NOTE: Do not inherit from this type outside the SDK unless you're okay with -/// breaking changes in non-major versions. We may add new methods in the future that -/// cause existing derived classes to break. -/// -public record class BulkRetrieveJobParams : ParamsBase -{ - public string? JobID { get; init; } - - public BulkRetrieveJobParams() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public BulkRetrieveJobParams(BulkRetrieveJobParams bulkRetrieveJobParams) - : base(bulkRetrieveJobParams) - { - this.JobID = bulkRetrieveJobParams.JobID; - } -#pragma warning restore CS8618 - - public BulkRetrieveJobParams( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - BulkRetrieveJobParams( - FrozenDictionary rawHeaderData, - FrozenDictionary rawQueryData, - string jobID - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - this.JobID = jobID; - } -#pragma warning restore CS8618 - - /// - public static BulkRetrieveJobParams FromRawUnchecked( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData, - string jobID - ) - { - return new( - FrozenDictionary.ToFrozenDictionary(rawHeaderData), - FrozenDictionary.ToFrozenDictionary(rawQueryData), - jobID - ); - } - - public override string ToString() => - JsonSerializer.Serialize( - FriendlyJsonPrinter.PrintValue( - new Dictionary() - { - ["JobID"] = JsonSerializer.SerializeToElement(this.JobID), - ["HeaderData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawHeaderData.Freeze()) - ), - ["QueryData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawQueryData.Freeze()) - ), - } - ), - ModelBase.ToStringSerializerOptions - ); - - public virtual bool Equals(BulkRetrieveJobParams? other) - { - if (other == null) - { - return false; - } - return (this.JobID?.Equals(other.JobID) ?? other.JobID == null) - && this._rawHeaderData.Equals(other._rawHeaderData) - && this._rawQueryData.Equals(other._rawQueryData); - } - - public override Uri Url(ClientOptions options) - { - return new UriBuilder( - options.BaseUrl.ToString().TrimEnd('/') + string.Format("/bulk/{0}", this.JobID) - ) - { - Query = this.QueryString(options), - }.Uri; - } - - internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) - { - ParamsBase.AddDefaultHeaders(request, options); - foreach (var item in this.RawHeaderData) - { - ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); - } - } - - public override int GetHashCode() - { - return 0; - } -} diff --git a/src/TryCourier/Models/Bulk/BulkRetrieveJobResponse.cs b/src/TryCourier/Models/Bulk/BulkRetrieveJobResponse.cs deleted file mode 100644 index 1c3bb0c8..00000000 --- a/src/TryCourier/Models/Bulk/BulkRetrieveJobResponse.cs +++ /dev/null @@ -1,227 +0,0 @@ -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Text.Json; -using System.Text.Json.Serialization; -using TryCourier.Core; -using TryCourier.Exceptions; -using System = System; - -namespace TryCourier.Models.Bulk; - -[JsonConverter(typeof(JsonModelConverter))] -public sealed record class BulkRetrieveJobResponse : JsonModel -{ - public required Job Job - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass("job"); - } - init { this._rawData.Set("job", value); } - } - - /// - public override void Validate() - { - this.Job.Validate(); - } - - public BulkRetrieveJobResponse() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public BulkRetrieveJobResponse(BulkRetrieveJobResponse bulkRetrieveJobResponse) - : base(bulkRetrieveJobResponse) { } -#pragma warning restore CS8618 - - public BulkRetrieveJobResponse(IReadOnlyDictionary rawData) - { - this._rawData = new(rawData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - BulkRetrieveJobResponse(FrozenDictionary rawData) - { - this._rawData = new(rawData); - } -#pragma warning restore CS8618 - - /// - public static BulkRetrieveJobResponse FromRawUnchecked( - IReadOnlyDictionary rawData - ) - { - return new(FrozenDictionary.ToFrozenDictionary(rawData)); - } - - [SetsRequiredMembers] - public BulkRetrieveJobResponse(Job job) - : this() - { - this.Job = job; - } -} - -class BulkRetrieveJobResponseFromRaw : IFromRawJson -{ - /// - public BulkRetrieveJobResponse FromRawUnchecked( - IReadOnlyDictionary rawData - ) => BulkRetrieveJobResponse.FromRawUnchecked(rawData); -} - -[JsonConverter(typeof(JsonModelConverter))] -public sealed record class Job : JsonModel -{ - /// - /// Bulk message definition. Supports two formats: - V1 format: Requires `event` - /// field (event ID or notification ID) - V2 format: Optionally use `template` - /// (notification ID) or `content` (Elemental content) in addition to `event` - /// - public required InboundBulkMessage Definition - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass("definition"); - } - init { this._rawData.Set("definition", value); } - } - - public required long Enqueued - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullStruct("enqueued"); - } - init { this._rawData.Set("enqueued", value); } - } - - public required long Failures - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullStruct("failures"); - } - init { this._rawData.Set("failures", value); } - } - - public required long Received - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullStruct("received"); - } - init { this._rawData.Set("received", value); } - } - - public required ApiEnum Status - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass>("status"); - } - init { this._rawData.Set("status", value); } - } - - /// - public override void Validate() - { - this.Definition.Validate(); - _ = this.Enqueued; - _ = this.Failures; - _ = this.Received; - this.Status.Validate(); - } - - public Job() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public Job(Job job) - : base(job) { } -#pragma warning restore CS8618 - - public Job(IReadOnlyDictionary rawData) - { - this._rawData = new(rawData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - Job(FrozenDictionary rawData) - { - this._rawData = new(rawData); - } -#pragma warning restore CS8618 - - /// - public static Job FromRawUnchecked(IReadOnlyDictionary rawData) - { - return new(FrozenDictionary.ToFrozenDictionary(rawData)); - } -} - -class JobFromRaw : IFromRawJson -{ - /// - public Job FromRawUnchecked(IReadOnlyDictionary rawData) => - Job.FromRawUnchecked(rawData); -} - -[JsonConverter(typeof(JobStatusConverter))] -public enum JobStatus -{ - Created, - Processing, - Completed, - Error, -} - -sealed class JobStatusConverter : JsonConverter -{ - public override JobStatus Read( - ref Utf8JsonReader reader, - System::Type typeToConvert, - JsonSerializerOptions options - ) - { - return JsonSerializer.Deserialize(ref reader, options) switch - { - "CREATED" => JobStatus.Created, - "PROCESSING" => JobStatus.Processing, - "COMPLETED" => JobStatus.Completed, - "ERROR" => JobStatus.Error, - _ => (JobStatus)(-1), - }; - } - - public override void Write( - Utf8JsonWriter writer, - JobStatus value, - JsonSerializerOptions options - ) - { - JsonSerializer.Serialize( - writer, - value switch - { - JobStatus.Created => "CREATED", - JobStatus.Processing => "PROCESSING", - JobStatus.Completed => "COMPLETED", - JobStatus.Error => "ERROR", - _ => throw new CourierInvalidDataException( - string.Format("Invalid value '{0}' in {1}", value, nameof(value)) - ), - }, - options - ); - } -} diff --git a/src/TryCourier/Models/Bulk/BulkRunJobParams.cs b/src/TryCourier/Models/Bulk/BulkRunJobParams.cs deleted file mode 100644 index 5bc07d2f..00000000 --- a/src/TryCourier/Models/Bulk/BulkRunJobParams.cs +++ /dev/null @@ -1,121 +0,0 @@ -using System; -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Net.Http; -using System.Text.Json; -using TryCourier.Core; - -namespace TryCourier.Models.Bulk; - -/// -/// Run a bulk job -/// -/// NOTE: Do not inherit from this type outside the SDK unless you're okay with -/// breaking changes in non-major versions. We may add new methods in the future that -/// cause existing derived classes to break. -/// -public record class BulkRunJobParams : ParamsBase -{ - public string? JobID { get; init; } - - public BulkRunJobParams() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public BulkRunJobParams(BulkRunJobParams bulkRunJobParams) - : base(bulkRunJobParams) - { - this.JobID = bulkRunJobParams.JobID; - } -#pragma warning restore CS8618 - - public BulkRunJobParams( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - BulkRunJobParams( - FrozenDictionary rawHeaderData, - FrozenDictionary rawQueryData, - string jobID - ) - { - this._rawHeaderData = new(rawHeaderData); - this._rawQueryData = new(rawQueryData); - this.JobID = jobID; - } -#pragma warning restore CS8618 - - /// - public static BulkRunJobParams FromRawUnchecked( - IReadOnlyDictionary rawHeaderData, - IReadOnlyDictionary rawQueryData, - string jobID - ) - { - return new( - FrozenDictionary.ToFrozenDictionary(rawHeaderData), - FrozenDictionary.ToFrozenDictionary(rawQueryData), - jobID - ); - } - - public override string ToString() => - JsonSerializer.Serialize( - FriendlyJsonPrinter.PrintValue( - new Dictionary() - { - ["JobID"] = JsonSerializer.SerializeToElement(this.JobID), - ["HeaderData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawHeaderData.Freeze()) - ), - ["QueryData"] = FriendlyJsonPrinter.PrintValue( - JsonSerializer.SerializeToElement(this._rawQueryData.Freeze()) - ), - } - ), - ModelBase.ToStringSerializerOptions - ); - - public virtual bool Equals(BulkRunJobParams? other) - { - if (other == null) - { - return false; - } - return (this.JobID?.Equals(other.JobID) ?? other.JobID == null) - && this._rawHeaderData.Equals(other._rawHeaderData) - && this._rawQueryData.Equals(other._rawQueryData); - } - - public override Uri Url(ClientOptions options) - { - return new UriBuilder( - options.BaseUrl.ToString().TrimEnd('/') + string.Format("/bulk/{0}/run", this.JobID) - ) - { - Query = this.QueryString(options), - }.Uri; - } - - internal override void AddHeadersToRequest(HttpRequestMessage request, ClientOptions options) - { - ParamsBase.AddDefaultHeaders(request, options); - foreach (var item in this.RawHeaderData) - { - ParamsBase.AddHeaderElementToRequest(request, item.Key, item.Value); - } - } - - public override int GetHashCode() - { - return 0; - } -} diff --git a/src/TryCourier/Models/Bulk/InboundBulkMessage.cs b/src/TryCourier/Models/Bulk/InboundBulkMessage.cs deleted file mode 100644 index 122dd5bf..00000000 --- a/src/TryCourier/Models/Bulk/InboundBulkMessage.cs +++ /dev/null @@ -1,448 +0,0 @@ -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Text.Json; -using System.Text.Json.Serialization; -using TryCourier.Core; -using TryCourier.Exceptions; -using System = System; - -namespace TryCourier.Models.Bulk; - -/// -/// Bulk message definition. Supports two formats: - V1 format: Requires `event` field -/// (event ID or notification ID) - V2 format: Optionally use `template` (notification -/// ID) or `content` (Elemental content) in addition to `event` -/// -[JsonConverter(typeof(JsonModelConverter))] -public sealed record class InboundBulkMessage : JsonModel -{ - /// - /// Event ID or Notification ID (required). Can be either a Notification ID - /// (e.g., "FRH3QXM9E34W4RKP7MRC8NZ1T8V8") or a custom Event ID (e.g., "welcome-email") - /// mapped to a notification. - /// - public required string Event - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNotNullClass("event"); - } - init { this._rawData.Set("event", value); } - } - - public string? Brand - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("brand"); - } - init { this._rawData.Set("brand", value); } - } - - /// - /// Elemental content (optional, for V2 format). When provided, this will be used - /// instead of the notification associated with the `event` field. - /// - public Content? Content - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("content"); - } - init { this._rawData.Set("content", value); } - } - - public IReadOnlyDictionary? Data - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass>("data"); - } - init - { - this._rawData.Set?>( - "data", - value == null ? null : FrozenDictionary.ToFrozenDictionary(value) - ); - } - } - - public IReadOnlyDictionary>? Locale - { - get - { - this._rawData.Freeze(); - var value = this._rawData.GetNullableClass< - FrozenDictionary> - >("locale"); - if (value == null) - { - return null; - } - - return FrozenDictionary.ToFrozenDictionary( - value, - entry => entry.Key, - (entry) => (IReadOnlyDictionary)entry.Value - ); - } - init - { - this._rawData.Set>?>( - "locale", - value == null - ? null - : FrozenDictionary.ToFrozenDictionary( - value, - entry => entry.Key, - (entry) => FrozenDictionary.ToFrozenDictionary(entry.Value) - ) - ); - } - } - - public IReadOnlyDictionary? Override - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass>( - "override" - ); - } - init - { - this._rawData.Set?>( - "override", - value == null ? null : FrozenDictionary.ToFrozenDictionary(value) - ); - } - } - - /// - /// Notification ID or template ID (optional, for V2 format). When provided, - /// this will be used instead of the notification associated with the `event` - /// field. - /// - public string? Template - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("template"); - } - init { this._rawData.Set("template", value); } - } - - /// - public override void Validate() - { - _ = this.Event; - _ = this.Brand; - this.Content?.Validate(); - _ = this.Data; - _ = this.Locale; - _ = this.Override; - _ = this.Template; - } - - public InboundBulkMessage() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public InboundBulkMessage(InboundBulkMessage inboundBulkMessage) - : base(inboundBulkMessage) { } -#pragma warning restore CS8618 - - public InboundBulkMessage(IReadOnlyDictionary rawData) - { - this._rawData = new(rawData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - InboundBulkMessage(FrozenDictionary rawData) - { - this._rawData = new(rawData); - } -#pragma warning restore CS8618 - - /// - public static InboundBulkMessage FromRawUnchecked( - IReadOnlyDictionary rawData - ) - { - return new(FrozenDictionary.ToFrozenDictionary(rawData)); - } - - [SetsRequiredMembers] - public InboundBulkMessage(string event_) - : this() - { - this.Event = event_; - } -} - -class InboundBulkMessageFromRaw : IFromRawJson -{ - /// - public InboundBulkMessage FromRawUnchecked(IReadOnlyDictionary rawData) => - InboundBulkMessage.FromRawUnchecked(rawData); -} - -/// -/// Elemental content (optional, for V2 format). When provided, this will be used -/// instead of the notification associated with the `event` field. -/// -[JsonConverter(typeof(ContentConverter))] -public record class Content : ModelBase -{ - public object? Value { get; } = null; - - JsonElement? _element = null; - - public JsonElement Json - { - get - { - return this._element ??= JsonSerializer.SerializeToElement( - this.Value, - ModelBase.SerializerOptions - ); - } - } - - public Content(ElementalContentSugar value, JsonElement? element = null) - { - this.Value = value; - this._element = element; - } - - public Content(ElementalContent value, JsonElement? element = null) - { - this.Value = value; - this._element = element; - } - - public Content(JsonElement element) - { - this._element = element; - } - - /// - /// Returns true and sets the out parameter if the instance was constructed with a variant of - /// type . - /// - /// Consider using or if you need to handle every variant. - /// - /// - /// - /// if (instance.TryPickElementalContentSugar(out var value)) { - /// // `value` is of type `ElementalContentSugar` - /// Console.WriteLine(value); - /// } - /// - /// - /// - public bool TryPickElementalContentSugar([NotNullWhen(true)] out ElementalContentSugar? value) - { - value = this.Value as ElementalContentSugar; - return value != null; - } - - /// - /// Returns true and sets the out parameter if the instance was constructed with a variant of - /// type . - /// - /// Consider using or if you need to handle every variant. - /// - /// - /// - /// if (instance.TryPickElemental(out var value)) { - /// // `value` is of type `ElementalContent` - /// Console.WriteLine(value); - /// } - /// - /// - /// - public bool TryPickElemental([NotNullWhen(true)] out ElementalContent? value) - { - value = this.Value as ElementalContent; - return value != null; - } - - /// - /// Calls the function parameter corresponding to the variant the instance was constructed with. - /// - /// Use the TryPick method(s) if you don't need to handle every variant, or - /// if you need your function parameters to return something. - /// - /// - /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data - /// that doesn't match any variant's expected shape). - /// - /// - /// - /// - /// instance.Switch( - /// (ElementalContentSugar value) => {...}, - /// (ElementalContent value) => {...} - /// ); - /// - /// - /// - public void Switch( - System::Action elementalContentSugar, - System::Action elemental - ) - { - switch (this.Value) - { - case ElementalContentSugar value: - elementalContentSugar(value); - break; - case ElementalContent value: - elemental(value); - break; - default: - throw new CourierInvalidDataException("Data did not match any variant of Content"); - } - } - - /// - /// Calls the function parameter corresponding to the variant the instance was constructed with and - /// returns its result. - /// - /// Use the TryPick method(s) if you don't need to handle every variant, or - /// if you don't need your function parameters to return a value. - /// - /// - /// Thrown when the instance was constructed with an unknown variant (e.g. deserialized from raw data - /// that doesn't match any variant's expected shape). - /// - /// - /// - /// - /// var result = instance.Match( - /// (ElementalContentSugar value) => {...}, - /// (ElementalContent value) => {...} - /// ); - /// - /// - /// - public T Match( - System::Func elementalContentSugar, - System::Func elemental - ) - { - return this.Value switch - { - ElementalContentSugar value => elementalContentSugar(value), - ElementalContent value => elemental(value), - _ => throw new CourierInvalidDataException("Data did not match any variant of Content"), - }; - } - - public static implicit operator Content(ElementalContentSugar value) => new(value); - - public static implicit operator Content(ElementalContent value) => new(value); - - /// - /// Validates that the instance was constructed with a known variant and that this variant is valid - /// (based on its own Validate method). - /// - /// This is useful for instances constructed from raw JSON data (e.g. deserialized from an API response). - /// - /// - /// Thrown when the instance does not pass validation. - /// - /// - public override void Validate() - { - if (this.Value == null) - { - throw new CourierInvalidDataException("Data did not match any variant of Content"); - } - this.Switch( - (elementalContentSugar) => elementalContentSugar.Validate(), - (elemental) => elemental.Validate() - ); - } - - public virtual bool Equals(Content? other) => - other != null - && this.VariantIndex() == other.VariantIndex() - && JsonElement.DeepEquals(this.Json, other.Json); - - public override int GetHashCode() - { - return 0; - } - - public override string ToString() => - JsonSerializer.Serialize( - FriendlyJsonPrinter.PrintValue(this.Json), - ModelBase.ToStringSerializerOptions - ); - - int VariantIndex() - { - return this.Value switch - { - ElementalContentSugar _ => 0, - ElementalContent _ => 1, - _ => -1, - }; - } -} - -sealed class ContentConverter : JsonConverter -{ - public override Content? Read( - ref Utf8JsonReader reader, - System::Type typeToConvert, - JsonSerializerOptions options - ) - { - var element = JsonSerializer.Deserialize(ref reader, options); - try - { - var deserialized = JsonSerializer.Deserialize(element, options); - if (deserialized != null) - { - deserialized.Validate(); - return new(deserialized, element); - } - } - catch (System::Exception e) when (e is JsonException || e is CourierInvalidDataException) - { - // ignore - } - - try - { - var deserialized = JsonSerializer.Deserialize(element, options); - if (deserialized != null) - { - deserialized.Validate(); - return new(deserialized, element); - } - } - catch (System::Exception e) when (e is JsonException || e is CourierInvalidDataException) - { - // ignore - } - - return new(element); - } - - public override void Write(Utf8JsonWriter writer, Content? value, JsonSerializerOptions options) - { - JsonSerializer.Serialize(writer, value?.Json, options); - } -} diff --git a/src/TryCourier/Models/Bulk/InboundBulkMessageUser.cs b/src/TryCourier/Models/Bulk/InboundBulkMessageUser.cs deleted file mode 100644 index f319e758..00000000 --- a/src/TryCourier/Models/Bulk/InboundBulkMessageUser.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Text.Json; -using System.Text.Json.Serialization; -using TryCourier.Core; - -namespace TryCourier.Models.Bulk; - -[JsonConverter(typeof(JsonModelConverter))] -public sealed record class InboundBulkMessageUser : JsonModel -{ - /// - /// User-specific data that will be merged with message.data - /// - public JsonElement? Data - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableStruct("data"); - } - init - { - if (value == null) - { - return; - } - - this._rawData.Set("data", value); - } - } - - public RecipientPreferences? Preferences - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("preferences"); - } - init { this._rawData.Set("preferences", value); } - } - - /// - /// User profile information. For email-based bulk jobs, `profile.email` is required - /// for provider routing to determine if the message can be delivered. The email - /// address should be provided here rather than in `to.email`. - /// - public IReadOnlyDictionary? Profile - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass>("profile"); - } - init - { - this._rawData.Set?>( - "profile", - value == null ? null : FrozenDictionary.ToFrozenDictionary(value) - ); - } - } - - /// - /// User ID (legacy field, use profile or to.user_id instead) - /// - public string? Recipient - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("recipient"); - } - init { this._rawData.Set("recipient", value); } - } - - /// - /// Optional recipient information. Note: For email provider routing, use `profile.email` - /// instead of `to.email`. The `to` field is primarily used for recipient identification - /// and data merging. - /// - public UserRecipient? To - { - get - { - this._rawData.Freeze(); - return this._rawData.GetNullableClass("to"); - } - init { this._rawData.Set("to", value); } - } - - /// - public override void Validate() - { - _ = this.Data; - this.Preferences?.Validate(); - _ = this.Profile; - _ = this.Recipient; - this.To?.Validate(); - } - - public InboundBulkMessageUser() { } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - public InboundBulkMessageUser(InboundBulkMessageUser inboundBulkMessageUser) - : base(inboundBulkMessageUser) { } -#pragma warning restore CS8618 - - public InboundBulkMessageUser(IReadOnlyDictionary rawData) - { - this._rawData = new(rawData); - } - -#pragma warning disable CS8618 - [SetsRequiredMembers] - InboundBulkMessageUser(FrozenDictionary rawData) - { - this._rawData = new(rawData); - } -#pragma warning restore CS8618 - - /// - public static InboundBulkMessageUser FromRawUnchecked( - IReadOnlyDictionary rawData - ) - { - return new(FrozenDictionary.ToFrozenDictionary(rawData)); - } -} - -class InboundBulkMessageUserFromRaw : IFromRawJson -{ - /// - public InboundBulkMessageUser FromRawUnchecked( - IReadOnlyDictionary rawData - ) => InboundBulkMessageUser.FromRawUnchecked(rawData); -} diff --git a/src/TryCourier/Services/BulkService.cs b/src/TryCourier/Services/BulkService.cs deleted file mode 100644 index 9e5d9f12..00000000 --- a/src/TryCourier/Services/BulkService.cs +++ /dev/null @@ -1,330 +0,0 @@ -using System; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using TryCourier.Core; -using TryCourier.Exceptions; -using TryCourier.Models.Bulk; - -namespace TryCourier.Services; - -/// -public sealed class BulkService : IBulkService -{ - readonly Lazy _withRawResponse; - - /// - public IBulkServiceWithRawResponse WithRawResponse - { - get { return _withRawResponse.Value; } - } - - readonly ICourierClient _client; - - /// - public IBulkService WithOptions(Func modifier) - { - return new BulkService(this._client.WithOptions(modifier)); - } - - public BulkService(ICourierClient client) - { - _client = client; - - _withRawResponse = new(() => new BulkServiceWithRawResponse(client.WithRawResponse)); - } - - /// - public Task AddUsers( - BulkAddUsersParams parameters, - CancellationToken cancellationToken = default - ) - { - return this.WithRawResponse.AddUsers(parameters, cancellationToken); - } - - /// - public async Task AddUsers( - string jobID, - BulkAddUsersParams parameters, - CancellationToken cancellationToken = default - ) - { - await this.AddUsers(parameters with { JobID = jobID }, cancellationToken) - .ConfigureAwait(false); - } - - /// - public async Task CreateJob( - BulkCreateJobParams parameters, - CancellationToken cancellationToken = default - ) - { - using var response = await this - .WithRawResponse.CreateJob(parameters, cancellationToken) - .ConfigureAwait(false); - return await response.Deserialize(cancellationToken).ConfigureAwait(false); - } - - /// - public async Task ListUsers( - BulkListUsersParams parameters, - CancellationToken cancellationToken = default - ) - { - using var response = await this - .WithRawResponse.ListUsers(parameters, cancellationToken) - .ConfigureAwait(false); - return await response.Deserialize(cancellationToken).ConfigureAwait(false); - } - - /// - public Task ListUsers( - string jobID, - BulkListUsersParams? parameters = null, - CancellationToken cancellationToken = default - ) - { - parameters ??= new(); - - return this.ListUsers(parameters with { JobID = jobID }, cancellationToken); - } - - /// - public async Task RetrieveJob( - BulkRetrieveJobParams parameters, - CancellationToken cancellationToken = default - ) - { - using var response = await this - .WithRawResponse.RetrieveJob(parameters, cancellationToken) - .ConfigureAwait(false); - return await response.Deserialize(cancellationToken).ConfigureAwait(false); - } - - /// - public Task RetrieveJob( - string jobID, - BulkRetrieveJobParams? parameters = null, - CancellationToken cancellationToken = default - ) - { - parameters ??= new(); - - return this.RetrieveJob(parameters with { JobID = jobID }, cancellationToken); - } - - /// - public Task RunJob(BulkRunJobParams parameters, CancellationToken cancellationToken = default) - { - return this.WithRawResponse.RunJob(parameters, cancellationToken); - } - - /// - public async Task RunJob( - string jobID, - BulkRunJobParams? parameters = null, - CancellationToken cancellationToken = default - ) - { - parameters ??= new(); - - await this.RunJob(parameters with { JobID = jobID }, cancellationToken) - .ConfigureAwait(false); - } -} - -/// -public sealed class BulkServiceWithRawResponse : IBulkServiceWithRawResponse -{ - readonly ICourierClientWithRawResponse _client; - - /// - public IBulkServiceWithRawResponse WithOptions(Func modifier) - { - return new BulkServiceWithRawResponse(this._client.WithOptions(modifier)); - } - - public BulkServiceWithRawResponse(ICourierClientWithRawResponse client) - { - _client = client; - } - - /// - public Task AddUsers( - BulkAddUsersParams parameters, - CancellationToken cancellationToken = default - ) - { - if (parameters.JobID == null) - { - throw new CourierInvalidDataException("'parameters.JobID' cannot be null"); - } - - HttpRequest request = new() - { - Method = HttpMethod.Post, - Params = parameters, - }; - return this._client.Execute(request, cancellationToken); - } - - /// - public Task AddUsers( - string jobID, - BulkAddUsersParams parameters, - CancellationToken cancellationToken = default - ) - { - return this.AddUsers(parameters with { JobID = jobID }, cancellationToken); - } - - /// - public async Task> CreateJob( - BulkCreateJobParams parameters, - CancellationToken cancellationToken = default - ) - { - HttpRequest request = new() - { - Method = HttpMethod.Post, - Params = parameters, - }; - var response = await this._client.Execute(request, cancellationToken).ConfigureAwait(false); - return new( - response, - async (token) => - { - var deserializedResponse = await response - .Deserialize(token) - .ConfigureAwait(false); - if (this._client.ResponseValidation) - { - deserializedResponse.Validate(); - } - return deserializedResponse; - } - ); - } - - /// - public async Task> ListUsers( - BulkListUsersParams parameters, - CancellationToken cancellationToken = default - ) - { - if (parameters.JobID == null) - { - throw new CourierInvalidDataException("'parameters.JobID' cannot be null"); - } - - HttpRequest request = new() - { - Method = HttpMethod.Get, - Params = parameters, - }; - var response = await this._client.Execute(request, cancellationToken).ConfigureAwait(false); - return new( - response, - async (token) => - { - var deserializedResponse = await response - .Deserialize(token) - .ConfigureAwait(false); - if (this._client.ResponseValidation) - { - deserializedResponse.Validate(); - } - return deserializedResponse; - } - ); - } - - /// - public Task> ListUsers( - string jobID, - BulkListUsersParams? parameters = null, - CancellationToken cancellationToken = default - ) - { - parameters ??= new(); - - return this.ListUsers(parameters with { JobID = jobID }, cancellationToken); - } - - /// - public async Task> RetrieveJob( - BulkRetrieveJobParams parameters, - CancellationToken cancellationToken = default - ) - { - if (parameters.JobID == null) - { - throw new CourierInvalidDataException("'parameters.JobID' cannot be null"); - } - - HttpRequest request = new() - { - Method = HttpMethod.Get, - Params = parameters, - }; - var response = await this._client.Execute(request, cancellationToken).ConfigureAwait(false); - return new( - response, - async (token) => - { - var deserializedResponse = await response - .Deserialize(token) - .ConfigureAwait(false); - if (this._client.ResponseValidation) - { - deserializedResponse.Validate(); - } - return deserializedResponse; - } - ); - } - - /// - public Task> RetrieveJob( - string jobID, - BulkRetrieveJobParams? parameters = null, - CancellationToken cancellationToken = default - ) - { - parameters ??= new(); - - return this.RetrieveJob(parameters with { JobID = jobID }, cancellationToken); - } - - /// - public Task RunJob( - BulkRunJobParams parameters, - CancellationToken cancellationToken = default - ) - { - if (parameters.JobID == null) - { - throw new CourierInvalidDataException("'parameters.JobID' cannot be null"); - } - - HttpRequest request = new() - { - Method = HttpMethod.Post, - Params = parameters, - }; - return this._client.Execute(request, cancellationToken); - } - - /// - public Task RunJob( - string jobID, - BulkRunJobParams? parameters = null, - CancellationToken cancellationToken = default - ) - { - parameters ??= new(); - - return this.RunJob(parameters with { JobID = jobID }, cancellationToken); - } -} diff --git a/src/TryCourier/Services/IBulkService.cs b/src/TryCourier/Services/IBulkService.cs deleted file mode 100644 index 746c2167..00000000 --- a/src/TryCourier/Services/IBulkService.cs +++ /dev/null @@ -1,187 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; -using TryCourier.Core; -using TryCourier.Models.Bulk; - -namespace TryCourier.Services; - -/// -/// NOTE: Do not inherit from this type outside the SDK unless you're okay with breaking -/// changes in non-major versions. We may add new methods in the future that cause -/// existing derived classes to break. -/// -public interface IBulkService -{ - /// - /// Returns a view of this service that provides access to raw HTTP responses - /// for each method. - /// - IBulkServiceWithRawResponse WithRawResponse { get; } - - /// - /// Returns a view of this service with the given option modifications applied. - /// - /// The original service is not modified. - /// - IBulkService WithOptions(Func modifier); - - /// - /// Ingest user data into a Bulk Job. - /// - /// **Important**: For email-based bulk jobs, each user must include - /// `profile.email` for provider routing to work correctly. The `to.email` field is - /// not sufficient for email provider routing. - /// - Task AddUsers(BulkAddUsersParams parameters, CancellationToken cancellationToken = default); - - /// - Task AddUsers( - string jobID, - BulkAddUsersParams parameters, - CancellationToken cancellationToken = default - ); - - /// - /// Creates a new bulk job for sending messages to multiple recipients. - /// - /// **Required**: `message.event` (event ID or notification ID) - /// - /// **Optional (V2 format)**: `message.template` (notification ID) or - /// `message.content` (Elemental content) can be provided to override the notification - /// associated with the event. - /// - Task CreateJob( - BulkCreateJobParams parameters, - CancellationToken cancellationToken = default - ); - - /// - /// Get Bulk Job Users - /// - Task ListUsers( - BulkListUsersParams parameters, - CancellationToken cancellationToken = default - ); - - /// - Task ListUsers( - string jobID, - BulkListUsersParams? parameters = null, - CancellationToken cancellationToken = default - ); - - /// - /// Get a bulk job - /// - Task RetrieveJob( - BulkRetrieveJobParams parameters, - CancellationToken cancellationToken = default - ); - - /// - Task RetrieveJob( - string jobID, - BulkRetrieveJobParams? parameters = null, - CancellationToken cancellationToken = default - ); - - /// - /// Run a bulk job - /// - Task RunJob(BulkRunJobParams parameters, CancellationToken cancellationToken = default); - - /// - Task RunJob( - string jobID, - BulkRunJobParams? parameters = null, - CancellationToken cancellationToken = default - ); -} - -/// -/// A view of that provides access to raw -/// HTTP responses for each method. -/// -public interface IBulkServiceWithRawResponse -{ - /// - /// Returns a view of this service with the given option modifications applied. - /// - /// The original service is not modified. - /// - IBulkServiceWithRawResponse WithOptions(Func modifier); - - /// - /// Returns a raw HTTP response for post /bulk/{job_id}, but is otherwise the - /// same as . - /// - Task AddUsers( - BulkAddUsersParams parameters, - CancellationToken cancellationToken = default - ); - - /// - Task AddUsers( - string jobID, - BulkAddUsersParams parameters, - CancellationToken cancellationToken = default - ); - - /// - /// Returns a raw HTTP response for post /bulk, but is otherwise the - /// same as . - /// - Task> CreateJob( - BulkCreateJobParams parameters, - CancellationToken cancellationToken = default - ); - - /// - /// Returns a raw HTTP response for get /bulk/{job_id}/users, but is otherwise the - /// same as . - /// - Task> ListUsers( - BulkListUsersParams parameters, - CancellationToken cancellationToken = default - ); - - /// - Task> ListUsers( - string jobID, - BulkListUsersParams? parameters = null, - CancellationToken cancellationToken = default - ); - - /// - /// Returns a raw HTTP response for get /bulk/{job_id}, but is otherwise the - /// same as . - /// - Task> RetrieveJob( - BulkRetrieveJobParams parameters, - CancellationToken cancellationToken = default - ); - - /// - Task> RetrieveJob( - string jobID, - BulkRetrieveJobParams? parameters = null, - CancellationToken cancellationToken = default - ); - - /// - /// Returns a raw HTTP response for post /bulk/{job_id}/run, but is otherwise the - /// same as . - /// - Task RunJob( - BulkRunJobParams parameters, - CancellationToken cancellationToken = default - ); - - /// - Task RunJob( - string jobID, - BulkRunJobParams? parameters = null, - CancellationToken cancellationToken = default - ); -} From 86d844a9c54f000163c8074282bc12fa826c3b91 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 19:48:46 +0000 Subject: [PATCH 2/2] release: 5.18.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ src/TryCourier/TryCourier.csproj | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d237ad28..e52c9a17 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "5.17.0" + ".": "5.18.0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index bd0fc64a..a61f5895 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 5.18.0 (2026-07-23) + +Full Changelog: [v5.17.0...v5.18.0](https://github.com/trycourier/courier-csharp/compare/v5.17.0...v5.18.0) + +### Features + +* Remove /bulk endpoints from api-spec (C-19507) ([#171](https://github.com/trycourier/courier-csharp/issues/171)) ([7bd3478](https://github.com/trycourier/courier-csharp/commit/7bd347875defd21e3d0223089d3f0b5a06925740)) + ## 5.17.0 (2026-07-20) Full Changelog: [v5.16.2...v5.17.0](https://github.com/trycourier/courier-csharp/compare/v5.16.2...v5.17.0) diff --git a/src/TryCourier/TryCourier.csproj b/src/TryCourier/TryCourier.csproj index 2bd839a8..935810f3 100644 --- a/src/TryCourier/TryCourier.csproj +++ b/src/TryCourier/TryCourier.csproj @@ -3,7 +3,7 @@ Courier C# TryCourier - 5.17.0 + 5.18.0 The official .NET library for the Courier API. Library README.md