From d3215a92f4ef553a694ced80d755954d170697f3 Mon Sep 17 00:00:00 2001 From: Kenny Kaplan Date: Fri, 13 Mar 2015 14:23:14 -0600 Subject: [PATCH 1/8] Added DripCampaignActivate --- .../Component/ComponentTestsBase.cs | 24 ++ .../EndToEnd/BatchAsyncTests.cs | 32 ++ .../Data/DripCampaignActivateRequest.xml | 19 ++ .../EndToEnd/Data/SendRequest.xml | 8 +- SendWithUs.Client.Tests/EndToEnd/TestData.cs | 5 + .../SendWithUs.Client.Tests.csproj | 10 + ...ipCampaignActivateRequestConverterTests.cs | 311 ++++++++++++++++++ .../Unit/DripCampaignActivateRequestTests.cs | 218 ++++++++++++ .../Unit/DripCampaignActivateResponseTests.cs | 87 +++++ .../Unit/SendWithUsClientTests.cs | 18 + .../Helpers/ValidationFailureMode.cs | 3 +- .../Requests/DripCampaignActivateRequest.cs | 174 ++++++++++ .../DripCampaignActivateRequestConverter.cs | 152 +++++++++ .../Requests/IDripCampaignActivateRequest.cs | 101 ++++++ .../Responses/DripCampaignActivateResponse.cs | 87 +++++ .../IDripCampaignActivateResponse.cs | 35 ++ SendWithUs.Client/SendWithUs.Client.csproj | 5 + SendWithUs.Client/SendWithUsClient.cs | 15 +- 18 files changed, 1296 insertions(+), 8 deletions(-) create mode 100644 SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignActivateRequest.xml create mode 100644 SendWithUs.Client.Tests/Unit/DripCampaignActivateRequestConverterTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/DripCampaignActivateRequestTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/DripCampaignActivateResponseTests.cs create mode 100644 SendWithUs.Client/Requests/DripCampaignActivateRequest.cs create mode 100644 SendWithUs.Client/Requests/DripCampaignActivateRequestConverter.cs create mode 100644 SendWithUs.Client/Requests/IDripCampaignActivateRequest.cs create mode 100644 SendWithUs.Client/Responses/DripCampaignActivateResponse.cs create mode 100644 SendWithUs.Client/Responses/IDripCampaignActivateResponse.cs diff --git a/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs b/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs index 40d7ae3..1a41011 100755 --- a/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs +++ b/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs @@ -56,5 +56,29 @@ protected void ValidateSendRequest(JObject jsonObject, string expectedEmailId, s Assert.IsTrue(emailIdFound); Assert.IsTrue(recipientAddressFound); } + + protected void ValidateDripCampaignActivateRequest(JObject jsonObject, string expectedRecipientAddress, bool allowOtherProperties) + { + var recipientAddressFound = false; + + foreach(var pair in jsonObject) + { + switch (pair.Key) + { + case "recipient": + Assert.AreEqual(expectedRecipientAddress, pair.Value["address"].Value()); + recipientAddressFound = true; + break; + default: + if (!allowOtherProperties) + { + Assert.Fail("Unexpected object property '{0}'", pair.Key); + } + break; + } + } + + Assert.IsTrue(recipientAddressFound); + } } } diff --git a/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs b/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs index 5923688..a79370b 100755 --- a/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs +++ b/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs @@ -47,5 +47,37 @@ public void BatchAsync_OneSendRequest_Succeeds() Assert.AreEqual("OK", sendResponse.Status, true); Assert.AreEqual(true, sendResponse.Success); } + + [TestMethod] + public void BatchAsync_SendMultipleDifferentTypes_Succeeds() + { + // Item 1 + var subject = "BatchAsync " + TestHelper.GetUniqueId(); + var testData = new TestData("EndToEnd/Data/DripCampaignActivateRequest.xml"); + var request1 = new DripCampaignActivateRequest(testData.CampaignId, testData.RecipientAddress, testData.Data.Upsert("subject", subject)); + + // Item 2 + subject = "BatchAsync " + TestHelper.GetUniqueId(); + testData = new TestData("EndToEnd/Data/SendRequest.xml"); + var request2 = new SendRequest(testData.TemplateId, testData.RecipientAddress, testData.Data.Upsert("subject", subject)); + + var client = new SendWithUsClient(testData.ApiKey); + + var batchResponse = client.BatchAsync(new List { request1, request2 }).Result; + + Assert.AreEqual(HttpStatusCode.OK, batchResponse.StatusCode); + Assert.AreEqual(2, batchResponse.Items.Count()); + + var dripCampaignActivateResponse = batchResponse.Items.First() as IDripCampaignActivateResponse; + Assert.AreEqual(HttpStatusCode.OK, dripCampaignActivateResponse.StatusCode); + Assert.AreEqual("OK", dripCampaignActivateResponse.Status, true); + Assert.AreEqual(true, dripCampaignActivateResponse.Success); + batchResponse.Items.RemoveAt(0); + + var sendResponse = batchResponse.Items.First() as ISendResponse; + Assert.AreEqual(HttpStatusCode.OK, sendResponse.StatusCode); + Assert.AreEqual("OK", sendResponse.Status, true); + Assert.AreEqual(true, sendResponse.Success); + } } } diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignActivateRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignActivateRequest.xml new file mode 100644 index 0000000..a95f0f9 --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignActivateRequest.xml @@ -0,0 +1,19 @@ + + + test_64afdf86aa571c901db5c70cf7a953727132599e + dc_pZ5niXSbnCCv3FbojQ7F4G + kkaplan@hattonpoint.com + kkaplan@hattonpoint.com + + + + + + + + \ No newline at end of file diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/SendRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/SendRequest.xml index fae59cd..8eedd80 100755 --- a/SendWithUs.Client.Tests/EndToEnd/Data/SendRequest.xml +++ b/SendWithUs.Client.Tests/EndToEnd/Data/SendRequest.xml @@ -1,9 +1,9 @@  - - - - + test_64afdf86aa571c901db5c70cf7a953727132599e + tem_PUuDKzcTLQrG7hroMxbwWB + kkaplan@hattonpoint.com + kkaplan@hattonpoint.com EndToEnd/Data/mimeo-logo-black.png diff --git a/SendWithUs.Client.Tests/EndToEnd/TestData.cs b/SendWithUs.Client.Tests/EndToEnd/TestData.cs index 1c95434..23f4c13 100755 --- a/SendWithUs.Client.Tests/EndToEnd/TestData.cs +++ b/SendWithUs.Client.Tests/EndToEnd/TestData.cs @@ -36,6 +36,11 @@ public string TemplateId get { return this.GetString("TemplateId"); } } + public string CampaignId + { + get { return this.GetString("CampaignId"); } + } + public string SenderAddress { get { return this.GetString("SenderAddress"); } diff --git a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj index 7fd019a..dfe8b3d 100755 --- a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj +++ b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj @@ -77,11 +77,13 @@ + + @@ -94,6 +96,9 @@ + + + @@ -114,6 +119,11 @@ Always + + + Always + + diff --git a/SendWithUs.Client.Tests/Unit/DripCampaignActivateRequestConverterTests.cs b/SendWithUs.Client.Tests/Unit/DripCampaignActivateRequestConverterTests.cs new file mode 100644 index 0000000..d2a44dc --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/DripCampaignActivateRequestConverterTests.cs @@ -0,0 +1,311 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json; + using SendWithUs.Client; + using Names = DripCampaignActivateRequestConverter.PropertyNames; + + [TestClass] + public class DripCampaignActivateRequestConverterTests + { + public class NonDripCampaignActivateRequest { } + + public interface IDripCampaignActivateRequestSubtype : IDripCampaignActivateRequest { } + + [TestMethod] + public void CanRead_Getter_ReturnsFalse() + { + // Arrange + var converter = new DripCampaignActivateRequestConverter(); + + // Act + var canRead = converter.CanRead; + + // Assert + Assert.IsFalse(canRead); + } + + [TestMethod] + public void CanWrite_Getter_ReturnsTrue() + { + // Arrange + var converter = new DripCampaignActivateRequestConverter(); + + // Act + var canWrite = converter.CanWrite; + + // Assert + Assert.IsTrue(canWrite); + } + + [TestMethod] + public void CanConvert_IDripCampaignActivateRequestType_ReturnsTrue() + { + // Arrange + var type = typeof(IDripCampaignActivateRequest); + var converter = new DripCampaignActivateRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_IDripCampaignActivateRequestSubtype_ReturnsTrue() + { + // Arrange + var type = typeof(IDripCampaignActivateRequestSubtype); + var converter = new DripCampaignActivateRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_NonIDripCampaignActivateRequestType_ReturnsFalse() + { + // Arrange + var type = typeof(NonDripCampaignActivateRequest); + var converter = new DripCampaignActivateRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsFalse(canConvert); + } + + [TestMethod] + public void ReadJson_Always_Throws() + { + // Arrange + var reader = new Mock().Object; + var serializer = new Mock().Object; + var request = new Mock().Object; + var converter = new DripCampaignActivateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.ReadJson(reader, request.GetType(), request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(NotImplementedException)); + } + + [TestMethod] + public void WriteJson_NullWriter_Throws() + { + // Arrange + var serializer = new Mock(null).Object; + var request = new Mock().Object; + var converter = new DripCampaignActivateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(null, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentNullException)); + } + + [TestMethod] + public void WriteJson_NullSerializer_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = null as SerializerProxy; + var request = new Mock().Object; + var converter = new DripCampaignActivateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentNullException)); + } + + [TestMethod] + public void WriteJson_NonIDripCampaignActivateRequestValue_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = new Mock(null).Object; + var value = new NonDripCampaignActivateRequest(); + var converter = new DripCampaignActivateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, value, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentException)); + } + + [TestMethod] + public void WriteJson_Normally_WritesObject() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new DripCampaignActivateRequestConverter(); + + // Act + converter.WriteJson(writer.Object, request.Object, serializer.Object); + + // Assert + writer.Verify(w => w.WriteStartObject(), Times.AtLeastOnce); + writer.Verify(w => w.WriteEndObject(), Times.AtLeastOnce); + } + + [TestMethod] + public void WriteJson_Normally_CallsHelpers() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new Mock() { CallBase = true }; + var campaignId = TestHelper.GetUniqueId(); + var providerId = TestHelper.GetUniqueId(); + var language = TestHelper.GetUniqueId(); + var data = (object)null; + var tags = (IEnumerable)null; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.ProviderId).Returns(providerId); + request.SetupGet(r => r.Locale).Returns(language); + request.SetupGet(r => r.Data).Returns(data); + request.SetupGet(r => r.Tags).Returns(tags); + + // Act + converter.Object.WriteJson(writer.Object, request.Object, serializer.Object); + + // Assert + converter.Verify(c => c.WriteProperty(writer.Object, serializer.Object, Names.ProviderId, providerId, true), Times.Once); + converter.Verify(c => c.WriteProperty(writer.Object, serializer.Object, Names.Locale, language, true), Times.Once); + converter.Verify(c => c.WriteProperty(writer.Object, serializer.Object, Names.Data, data, true), Times.Once); + converter.Verify(c => c.WriteProperty(writer.Object, serializer.Object, Names.Tags, tags, true), Times.Once); + converter.Verify(c => c.WritePrimaryRecipient(writer.Object, serializer.Object, request.Object), Times.Once); + converter.Verify(c => c.WriteCcRecipients(writer.Object, serializer.Object, request.Object), Times.Once); + converter.Verify(c => c.WriteBccRecipients(writer.Object, serializer.Object, request.Object), Times.Once); + } + + [TestMethod] + public void WritePrimaryRecipient_Normally_WritesObjectValuedProperty() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new DripCampaignActivateRequestConverter(); + + // Act + converter.WritePrimaryRecipient(writer.Object, serializer.Object, request.Object); + + // Assert + writer.Verify(w => w.WritePropertyName(Names.Recipient)); + writer.Verify(w => w.WriteStartObject()); + writer.Verify(w => w.WriteEndObject()); + } + + [TestMethod] + public void WritePrimaryRecipient_Normally_CallsHelpers() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new Mock() { CallBase = true }; + var recipientName = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + + request.SetupGet(r => r.RecipientName).Returns(recipientName); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + converter.Object.WritePrimaryRecipient(writer.Object, serializer.Object, request.Object); + + // Assert + converter.Verify(c => c.WriteProperty(writer.Object, serializer.Object, Names.Name, recipientName, true)); + converter.Verify(c => c.WriteProperty(writer.Object, serializer.Object, Names.Address, recipientAddress, false)); + } + + [TestMethod] + public void WriteCcRecipients_Always_CallsWriteRecipientsList() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new Mock() { CallBase = true }; + var recipients = new List(); + + request.SetupGet(r => r.CopyTo).Returns(recipients); + + // Act + converter.Object.WriteCcRecipients(writer.Object, serializer.Object, request.Object); + + // Assert + converter.Verify(c => c.WriteRecipientsList(writer.Object, serializer.Object, Names.CopyTo, recipients)); + } + + [TestMethod] + public void WriteBccRecipients_Always_CallsWriteRecipientsList() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new Mock() { CallBase = true }; + var recipients = new List(); + + request.SetupGet(r => r.CopyTo).Returns(recipients); + + // Act + converter.Object.WriteBccRecipients(writer.Object, serializer.Object, request.Object); + + // Assert + converter.Verify(c => c.WriteRecipientsList(writer.Object, serializer.Object, Names.BlindCopyTo, recipients)); + } + + [TestMethod] + public void WriteRecipientsList_NullRecipients_DoesNotWrite() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var converter = new DripCampaignActivateRequestConverter(); + var name = TestHelper.GetUniqueId(); + + // Act + converter.WriteRecipientsList(writer.Object, serializer.Object, name, null); + + // Assert + writer.Verify(w => w.WritePropertyName(name), Times.Never); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/DripCampaignActivateRequestTests.cs b/SendWithUs.Client.Tests/Unit/DripCampaignActivateRequestTests.cs new file mode 100644 index 0000000..0c3a0de --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/DripCampaignActivateRequestTests.cs @@ -0,0 +1,218 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class DripCampaignActivateRequestTests + { + [TestMethod] + public void IsValid_Getter_CallsValidate() + { + // Arrange + var request = new Mock() { CallBase = true }; + + // Act + var isValid = request.Object.IsValid; + + // Assert + request.Verify(r => r.Validate(false), Times.Once); + } + + [TestMethod] + public void GetResponseType_Always_ReturnsDripCampaignActivateResponseType() + { + // Arrange + var request = new DripCampaignActivateRequest(); + + // Act + var responseType = request.GetResponseType(); + + // Assert + Assert.AreEqual(typeof(DripCampaignActivateResponse), responseType); + } + + [TestMethod] + public void Validate_Always_CallsValidateBool() + { + // Arrange + var request = new Mock(); + + // Act + var self = request.Object.Validate(); + + // Assert + request.Verify(r => r.Validate(true), Times.Once); + } + + [TestMethod] + public void Validate_Always_ReturnsSelf() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var request = new DripCampaignActivateRequest(campaignId, recipientAddress); + + // Act + var self = request.Validate(); + + // Assert + Assert.AreSame(request, self); + } + + [TestMethod] + public void ValidateBool_Normally_ReturnsTrue() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var isValid = request.Object.Validate(false); + + // Assert + Assert.IsTrue(isValid); + } + + [TestMethod] + public void ValidateBool_TrueFlagAndEmptyCampaignId_Throws() + { + // Arrange + var campaignId = String.Empty; + var recipientAddress = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var exception = TestHelper.CaptureException(() => request.Object.Validate(true)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ValidationException)); + var invalid = exception as ValidationException; + Assert.AreEqual(ValidationFailureMode.MissingCampaignId, invalid.FailureMode); + } + + [TestMethod] + public void ValidateBool_TrueFlagAndEmptyRecipientAddress_Throws() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = String.Empty; + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var exception = TestHelper.CaptureException(() => request.Object.Validate(true)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ValidationException)); + var invalid = exception as ValidationException; + Assert.AreEqual(ValidationFailureMode.MissingRecipientAddress, invalid.FailureMode); + } + + [TestMethod] + public void ValidateBool_TrueFlagAndInconsistentSenderValues_Throws() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var senderName = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + request.SetupGet(r => r.SenderName).Returns(senderName); + + // Act + var exception = TestHelper.CaptureException(() => request.Object.Validate(true)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ValidationException)); + var invalid = exception as ValidationException; + Assert.AreEqual(ValidationFailureMode.MissingSenderAddress, invalid.FailureMode); + } + + [TestMethod] + public void ValidateBool_FalseFlagAndEmptyCampaignId_ReturnsFalse() + { + // Arrange + var campaignId = String.Empty; + var recipientAddress = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var isValid = request.Object.Validate(false); + + // Assert + Assert.AreEqual(false, isValid); + } + + [TestMethod] + public void ValidateBool_FalseFlagAndEmptyRecipientAddress_ReturnsFalse() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = String.Empty; + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var isValid = request.Object.Validate(false); + + // Assert + Assert.AreEqual(false, isValid); + } + + [TestMethod] + public void ValidateBool_FalseFlagAndInconsistentSenderValues_ReturnsFalse() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var senderName = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + request.SetupGet(r => r.SenderName).Returns(senderName); + + // Act + var isValid = request.Object.Validate(false); + + // Assert + Assert.AreEqual(false, isValid); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/DripCampaignActivateResponseTests.cs b/SendWithUs.Client.Tests/Unit/DripCampaignActivateResponseTests.cs new file mode 100644 index 0000000..a33e4f4 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/DripCampaignActivateResponseTests.cs @@ -0,0 +1,87 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json.Linq; + using Names = SendWithUs.Client.DripCampaignActivateResponse.PropertyNames; + + [TestClass] + public class DripCampaignActivateResponseTests + { + [TestMethod] + public void Populate_NullJson_DoesNotSetProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var json = null as JObject; + + // Act + response.Object.Populate(json); + + // Assert + response.VerifySet(r => r.Success = It.IsAny(), Times.Never); + response.VerifySet(r => r.Status = It.IsAny(), Times.Never); + response.VerifySet(r => r.DripCampaignId = It.IsAny(), Times.Never); + response.VerifySet(r => r.DripCampaignName = It.IsAny(), Times.Never); + response.VerifySet(r => r.RecipientAddress = It.IsAny(), Times.Never); + response.VerifySet(r => r.Message = It.IsAny(), Times.Never); + } + + [TestMethod] + public void Populate_ValidJson_SetsProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var success = true; + var status = TestHelper.GetUniqueId(); + var dripCampaignId = TestHelper.GetUniqueId(); + var dripCampaignName = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var message = TestHelper.GetUniqueId(); + var json = new Mock(); + var details = new Mock(); + + json.Setup(j => j.Value(Names.Success)).Returns(success); + json.Setup(j => j.Value(Names.Status)).Returns(status); + json.Setup(j => j.Value(Names.RecipientAddress)).Returns(recipientAddress); + json.Setup(j => j.Value(Names.Message)).Returns(message); + response.Setup(r => r.GetPropertyValue(json.Object, Names.Details)).Returns(details.Object); + details.Setup(d => d.Value(Names.DripCampaignId)).Returns(dripCampaignId); + details.Setup(d => d.Value(Names.DripCampaignName)).Returns(dripCampaignName); + + // Act + response.Object.Populate(json.Object); + + // Assert + response.VerifySet(r => r.Success = success, Times.Once); + response.VerifySet(r => r.Status = status, Times.Once); + response.VerifySet(r => r.RecipientAddress = recipientAddress, Times.Once); + response.VerifySet(r => r.Message = message, Times.Once); + response.VerifySet(r => r.DripCampaignId = dripCampaignId, Times.Once); + response.VerifySet(r => r.DripCampaignName = dripCampaignName, Times.Once); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/SendWithUsClientTests.cs b/SendWithUs.Client.Tests/Unit/SendWithUsClientTests.cs index dee4280..32a63fb 100755 --- a/SendWithUs.Client.Tests/Unit/SendWithUsClientTests.cs +++ b/SendWithUs.Client.Tests/Unit/SendWithUsClientTests.cs @@ -45,6 +45,24 @@ public void SendAsync_NullRequest_Throws() #endregion + #region DripCampaignActivateAsync + + [TestMethod] + public void DripCampaignActivateAsync_NullRequest_Throws() + { + // Arrange + var apiKey = TestHelper.GetUniqueId(); + var client = new SendWithUsClient(apiKey); + + // Act + var exception = TestHelper.CaptureException(() => client.DripCampaignActivateAsync(null)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentNullException)); + } + + #endregion + #region BatchAsync [TestMethod] diff --git a/SendWithUs.Client/Helpers/ValidationFailureMode.cs b/SendWithUs.Client/Helpers/ValidationFailureMode.cs index 367a43c..752b7ea 100755 --- a/SendWithUs.Client/Helpers/ValidationFailureMode.cs +++ b/SendWithUs.Client/Helpers/ValidationFailureMode.cs @@ -25,6 +25,7 @@ public enum ValidationFailureMode None, MissingTemplateId, MissingRecipientAddress, - MissingSenderAddress + MissingSenderAddress, + MissingCampaignId } } diff --git a/SendWithUs.Client/Requests/DripCampaignActivateRequest.cs b/SendWithUs.Client/Requests/DripCampaignActivateRequest.cs new file mode 100644 index 0000000..e1332e7 --- /dev/null +++ b/SendWithUs.Client/Requests/DripCampaignActivateRequest.cs @@ -0,0 +1,174 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + + /// + /// Represents the data necessary to make API requests to activate a drip campaign. + /// + [JsonConverter(typeof(DripCampaignActivateRequestConverter))] + public class DripCampaignActivateRequest : IDripCampaignActivateRequest + { + #region Constructors + + public DripCampaignActivateRequest() + { } + + public DripCampaignActivateRequest(string campaignId, string recipientAddress) : this(campaignId, recipientAddress, null) + { } + + public DripCampaignActivateRequest(string campaignId, string recipientAddress, object data) + { + EnsureArgument.NotNullOrEmpty(campaignId, "campaignId"); + EnsureArgument.NotNullOrEmpty(recipientAddress, "recipientAddress"); + + this.CampaignId = campaignId; + this.RecipientAddress = recipientAddress; + this.Data = data; + } + + #endregion + + #region IDripCampaignActivateRequest members + + public virtual string CampaignId { get; set; } + + public virtual string SenderAddress { get; set; } + + public virtual string SenderName { get; set; } + + public virtual string SenderReplyTo { get; set; } + + public virtual string RecipientAddress { get; set; } + + public virtual string RecipientName { get; set; } + + public virtual IEnumerable CopyTo { get; set; } + + public virtual IEnumerable BlindCopyTo { get; set; } + + public virtual object Data { get; set; } + + public virtual IEnumerable Tags { get; set; } + + public virtual string ProviderId { get; set; } + + public virtual string Locale { get; set; } + + public virtual bool IsValid + { + get { return this.Validate(false); } + } + + #endregion + + #region IRequest members + + public string GetUriPath() + { + return "/api/v1/" + string.Format("drip_campaigns/{0}/activate", this.CampaignId); + } + + public string GetHttpMethod() + { + return "POST"; + } + + public Type GetResponseType() + { + return typeof(DripCampaignActivateResponse); + } + + public IRequest Validate() + { + this.Validate(true); + return this; + } + + protected internal virtual bool Validate(bool throwOnFailure) + { + Func fail = (f) => + { + if (throwOnFailure) + { + throw new ValidationException(f); + } + + return false; + }; + + // Template ID is required. + if (String.IsNullOrEmpty(this.CampaignId)) + { + return fail(ValidationFailureMode.MissingCampaignId); + } + + // Recipient address is required. + if (String.IsNullOrEmpty(this.RecipientAddress)) + { + return fail(ValidationFailureMode.MissingRecipientAddress); + } + + // If sender name or reply-to are specified, then sender address is required. + if ((!String.IsNullOrEmpty(this.SenderName) || !String.IsNullOrEmpty(this.SenderReplyTo)) + && String.IsNullOrEmpty(this.SenderAddress)) + { + return fail(ValidationFailureMode.MissingSenderAddress); + } + + return true; + } + + #endregion + } + + /// + /// Represents the data necessary to make API requests to activate a drip campaign. + /// + /// The type of the Data property. + public class DripCampaignActivateRequest : DripCampaignActivateRequest + { + #region Constructors + + public DripCampaignActivateRequest() + : base() + { } + + public DripCampaignActivateRequest(string campaignId, string recipientAddress) + : base(campaignId, recipientAddress) + { } + + public DripCampaignActivateRequest(string campaignId, string recipientAddress, TData data) + : base(campaignId, recipientAddress, data) + { } + + #endregion + + public new TData Data + { + get { return (TData)base.Data; } + set { base.Data = value; } + } + } +} diff --git a/SendWithUs.Client/Requests/DripCampaignActivateRequestConverter.cs b/SendWithUs.Client/Requests/DripCampaignActivateRequestConverter.cs new file mode 100644 index 0000000..8cd0be1 --- /dev/null +++ b/SendWithUs.Client/Requests/DripCampaignActivateRequestConverter.cs @@ -0,0 +1,152 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using System.Reflection; + using Newtonsoft.Json; + + /// + /// Converts a DripCampaignActivate object to JSON. + /// + public class DripCampaignActivateRequestConverter : JsonConverter + { + public static class PropertyNames + { + public const string ProviderId = "esp_account"; + public const string Locale = "locale"; + public const string Recipient = "recipient"; + public const string Name = "name"; + public const string Address = "address"; + public const string Data = "email_data"; + public const string CopyTo = "cc"; + public const string BlindCopyTo = "bcc"; + public const string Tags = "tags"; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override bool CanConvert(Type objectType) + { + return typeof(IDripCampaignActivateRequest).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + // KLUGE: JsonSerializer is not mockable, so we resort to the bad practice of inserting + // code (i.e., the proxy) merely to support unit testing. + this.WriteJson(writer, value, new SerializerProxy(serializer)); + } + + protected internal virtual void WriteJson(JsonWriter writer, object value, SerializerProxy serializer) + { + EnsureArgument.NotNull(writer, "writer"); + EnsureArgument.NotNull(serializer, "serializer"); + + var request = EnsureArgument.Of(value, "value"); + + writer.WriteStartObject(); + + this.WriteProperty(writer, serializer, PropertyNames.ProviderId, request.ProviderId, true); + this.WriteProperty(writer, serializer, PropertyNames.Locale, request.Locale, true); + this.WriteProperty(writer, serializer, PropertyNames.Data, request.Data, true); + this.WriteProperty(writer, serializer, PropertyNames.Tags, request.Tags, true); + this.WritePrimaryRecipient(writer, serializer, request); + this.WriteCcRecipients(writer, serializer, request); + this.WriteBccRecipients(writer, serializer, request); + + writer.WriteEndObject(); + } + + protected internal virtual void WritePrimaryRecipient(JsonWriter writer, SerializerProxy serializer, IDripCampaignActivateRequest request) + { + writer.WritePropertyName(PropertyNames.Recipient); + writer.WriteStartObject(); + this.WriteProperty(writer, serializer, PropertyNames.Name, request.RecipientName, true); + this.WriteProperty(writer, serializer, PropertyNames.Address, request.RecipientAddress, false); + writer.WriteEndObject(); + } + + protected internal virtual void WriteCcRecipients(JsonWriter writer, SerializerProxy serializer, IDripCampaignActivateRequest request) + { + this.WriteRecipientsList(writer, serializer, PropertyNames.CopyTo, request.CopyTo); + } + + protected internal virtual void WriteBccRecipients(JsonWriter writer, SerializerProxy serializer, IDripCampaignActivateRequest request) + { + this.WriteRecipientsList(writer, serializer, PropertyNames.BlindCopyTo, request.BlindCopyTo); + } + + protected internal virtual void WriteRecipientsList(JsonWriter writer, SerializerProxy serializer, string name, IEnumerable recipients) + { + if (recipients == null) + { + return; + } + + writer.WritePropertyName(name); + writer.WriteStartArray(); + + foreach (var address in recipients) + { + writer.WriteStartObject(); + this.WriteProperty(writer, serializer, PropertyNames.Address, address, false); + writer.WriteEndObject(); + } + + writer.WriteEndArray(); + } + + protected internal virtual void WriteProperty(JsonWriter writer, SerializerProxy serializer, string name, object value, bool isOptional) + { + if (isOptional && value == null) + { + return; + } + + writer.WritePropertyName(name); + serializer.Serialize(writer, value); + } + + protected internal virtual void WriteProperty(JsonWriter writer, SerializerProxy serializer, string name, string value, bool isOptional) + { + if (isOptional && String.IsNullOrEmpty(value)) + { + return; + } + + writer.WritePropertyName(name); + serializer.Serialize(writer, value); + } + } +} diff --git a/SendWithUs.Client/Requests/IDripCampaignActivateRequest.cs b/SendWithUs.Client/Requests/IDripCampaignActivateRequest.cs new file mode 100644 index 0000000..aed4dd5 --- /dev/null +++ b/SendWithUs.Client/Requests/IDripCampaignActivateRequest.cs @@ -0,0 +1,101 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +namespace SendWithUs.Client +{ + using System.Collections.Generic; + + /// + /// Describes the interface of objects used to make API requests to activate drip campaigns. + /// + /// This interface roughly corresponds to the JSON object used with the /drip_campaigns/(drip_campaign_id)/activate route + /// in the REST API, with some properties flattened or renamed. + public interface IDripCampaignActivateRequest : IRequest + { + /// + /// Gets the unique identifier of an email template. + /// + /// Corresponds to the "drip_campaign_id" property in the SendWithUs API route. + string CampaignId { get; } + + /// + /// Gets the email address of the message sender. + /// + string SenderAddress { get; } + + /// + /// Gets the name of the message sender. + /// + string SenderName { get; } + + /// + /// Gets the email address to which replies should be sent. + /// + string SenderReplyTo { get; } + + /// + /// Gets the email address of the message recipient. + /// + string RecipientAddress { get; } + + /// + /// Gets the name of the message recipient. + /// + string RecipientName { get; } + + /// + /// Gets the set of "carbon copy" email addresses. + /// + /// Corresponds to the "cc" property in the SendWithUs API. + IEnumerable CopyTo { get; } + + /// + /// Gets the set of "blind carbon copy" email addresses. + /// + /// Corresponds to the "bcc" property in the SendWithUs API. + IEnumerable BlindCopyTo { get; } + + /// + /// Gets the data to use when expanding the message template. + /// + /// Corresponds to the "email_data" property in the SendWithUs API. + object Data { get; } + + /// + /// Gets the set of tags to associate with the message. + /// + IEnumerable Tags { get; } + + /// + /// Gets the unique identifier for the provider of email transport services. + /// + /// Corresponds to the "esp_account" property in the SendWithUs API. + string ProviderId { get; } + + /// + /// Gets the language tag for a localized variant of the template identified by TemplateId. + /// + string Locale { get; } + + /// + /// Gets a value indicating whether the request object is valid (well-formed). + /// + bool IsValid { get; } + } +} diff --git a/SendWithUs.Client/Responses/DripCampaignActivateResponse.cs b/SendWithUs.Client/Responses/DripCampaignActivateResponse.cs new file mode 100644 index 0000000..6761597 --- /dev/null +++ b/SendWithUs.Client/Responses/DripCampaignActivateResponse.cs @@ -0,0 +1,87 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using Newtonsoft.Json.Linq; + + public class DripCampaignActivateResponse : BaseResponse, IDripCampaignActivateResponse + { + public static class PropertyNames + { + public const string Success = "success"; + public const string Status = "status"; + public const string Details = "drip_campaign"; + public const string DripCampaignId = "id"; + public const string DripCampaignName = "name"; + public const string RecipientAddress = "recipient_address"; + public const string Message = "message"; + } + + public virtual bool Success { get; set; } + + public virtual string Status { get; set; } + + public virtual string DripCampaignId { get; set; } + + public virtual string DripCampaignName { get; set; } + + public virtual string RecipientAddress { get; set; } + + public virtual string Message { get; set; } + + #region Base class overrides + + protected internal override void Populate(JObject json) + { + if (json == null) + { + return; + } + + this.Success = json.Value(PropertyNames.Success); + this.Status = json.Value(PropertyNames.Status); + this.RecipientAddress = json.Value(PropertyNames.RecipientAddress); + this.Message = json.Value(PropertyNames.Message); + + var details = this.GetPropertyValue(json, PropertyNames.Details); + + if (details != null) + { + this.DripCampaignId = details.Value(PropertyNames.DripCampaignId); + this.DripCampaignName = details.Value(PropertyNames.DripCampaignName); + } + } + + /// + /// Gets the value of the named property on the specified object. + /// + /// The object from which to get the property value. + /// The property value. + /// This method exists to aid unit testing of Populate(), because JObject.GetValue() + /// is not virtual and therefore cannot be mocked. + protected internal virtual JToken GetPropertyValue(JObject json, string propertyName) + { + //var details = json.Property(propertyName); + //return (details != null && details.HasValues) ? details.Value : null; + return json.GetValue(propertyName); + } + + #endregion + } +} diff --git a/SendWithUs.Client/Responses/IDripCampaignActivateResponse.cs b/SendWithUs.Client/Responses/IDripCampaignActivateResponse.cs new file mode 100644 index 0000000..e796d22 --- /dev/null +++ b/SendWithUs.Client/Responses/IDripCampaignActivateResponse.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + public interface IDripCampaignActivateResponse : IResponse + { + bool Success { get; } + + string Status { get; } + + string DripCampaignId { get; } + + string DripCampaignName { get; } + + string RecipientAddress { get; } + + string Message { get; } + } +} diff --git a/SendWithUs.Client/SendWithUs.Client.csproj b/SendWithUs.Client/SendWithUs.Client.csproj index 92dd713..16ebf33 100755 --- a/SendWithUs.Client/SendWithUs.Client.csproj +++ b/SendWithUs.Client/SendWithUs.Client.csproj @@ -46,13 +46,18 @@ + + + + + diff --git a/SendWithUs.Client/SendWithUsClient.cs b/SendWithUs.Client/SendWithUsClient.cs index 718af94..dd4fe7f 100755 --- a/SendWithUs.Client/SendWithUsClient.cs +++ b/SendWithUs.Client/SendWithUsClient.cs @@ -44,7 +44,7 @@ public class SendWithUsClient : ISendWithUsClient /// The base URI of the SendWithUs service. /// /// MUST have a trailing slash. - protected const string BaseUri = "https://api.sendwithus.com/api/v1/"; + protected const string BaseUri = "https://api.sendwithus.com"; /// /// Gets or sets the HTTP implementation. @@ -122,11 +122,20 @@ public virtual async Task SendAsync(ISendRequest request) { EnsureArgument.NotNull(request, "request"); - var httpResponse = await this.PostJsonAsync("send", request.Validate()).ConfigureAwait(false); + var httpResponse = await this.PostJsonAsync(request.GetUriPath(), request.Validate()).ConfigureAwait(false); var json = await this.ReadJsonAsync(httpResponse); return this.ResponseFactory.Create(httpResponse.StatusCode, json); } + public virtual async Task DripCampaignActivateAsync(IDripCampaignActivateRequest request) + { + EnsureArgument.NotNull(request, "request"); + + var httpResponse = await this.PostJsonAsync(request.GetUriPath(), request.Validate()).ConfigureAwait(false); + var json = await this.ReadJsonAsync(httpResponse); + return this.ResponseFactory.Create(httpResponse.StatusCode, json); + } + /// /// Submits a batch request comprising the given set of request objects. /// @@ -138,7 +147,7 @@ public virtual async Task BatchAsync(IEnumerable reque EnsureArgument.NotNullOrEmpty(requests, "requests", false); var batchRequest = requests.Select(r => new BatchRequestWrapper(r.Validate())); - var httpResponse = await this.PostJsonAsync("batch", batchRequest).ConfigureAwait(false); + var httpResponse = await this.PostJsonAsync("/api/v1/batch", batchRequest).ConfigureAwait(false); var json = await this.ReadJsonAsync(httpResponse); var responseSequence = requests.Select(r => r.GetResponseType()); return this.ResponseFactory.Create(responseSequence, httpResponse.StatusCode, json); From 113eaaaffe528b4bf542921fc0e1b3543a29be66 Mon Sep 17 00:00:00 2001 From: Kenny Kaplan Date: Fri, 13 Mar 2015 16:12:33 -0600 Subject: [PATCH 2/8] Added DripCampaignDeactivateRequest and DripCampaignDeactivateAllRequest --- .../Component/ComponentTestsBase.cs | 48 +++++ ...DripCampaignDeactivateAllConverterTests.cs | 54 +++++ .../DripCampaignDeactivateConverterTests.cs | 55 +++++ .../Data/DripCampaignDeactivateAllRequest.xml | 5 + .../Data/DripCampaignDeactivateRequest.xml | 6 + .../DripCampaignActivateAsyncTests.cs | 70 ++++++ .../DripCampaignDeactivateAllAsyncTests.cs | 50 +++++ .../DripCampaignDeactivateAsyncTests.cs | 50 +++++ .../SendWithUs.Client.Tests.csproj | 16 ++ ...paignDeactivateAllRequestConverterTests.cs | 203 ++++++++++++++++++ .../DripCampaignDeactivateAllRequestTests.cs | 131 +++++++++++ .../DripCampaignDeactivateAllResponseTests.cs | 80 +++++++ ...CampaignDeactivateRequestConverterTests.cs | 203 ++++++++++++++++++ .../DripCampaignDeactivateRequestTests.cs | 176 +++++++++++++++ .../DripCampaignDeactivateResponseTests.cs | 87 ++++++++ .../Unit/SendWithUsClientTests.cs | 4 +- SendWithUs.Client/ISendWithUsClient.cs | 7 + .../Requests/DripCampaignActivateRequest.cs | 2 +- .../DripCampaignDeactivateAllRequest.cs | 104 +++++++++ ...ipCampaignDeactivateAllRequestConverter.cs | 99 +++++++++ .../Requests/DripCampaignDeactivateRequest.cs | 114 ++++++++++ .../DripCampaignDeactivateRequestConverter.cs | 99 +++++++++ .../IDripCampaignDeactivateAllRequest.cs | 41 ++++ .../IDripCampaignDeactivateRequest.cs | 47 ++++ .../DripCampaignDeactivateAllResponse.cs | 72 +++++++ .../DripCampaignDeactivateResponse.cs | 87 ++++++++ .../IDripCampaignDeactivateAllResponse.cs | 31 +++ .../IDripCampaignDeactivateResponse.cs | 35 +++ SendWithUs.Client/SendWithUs.Client.csproj | 10 + SendWithUs.Client/SendWithUsClient.cs | 10 +- 30 files changed, 1991 insertions(+), 5 deletions(-) create mode 100644 SendWithUs.Client.Tests/Component/DripCampaignDeactivateAllConverterTests.cs create mode 100644 SendWithUs.Client.Tests/Component/DripCampaignDeactivateConverterTests.cs create mode 100644 SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateAllRequest.xml create mode 100644 SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateRequest.xml create mode 100644 SendWithUs.Client.Tests/EndToEnd/DripCampaignActivateAsyncTests.cs create mode 100644 SendWithUs.Client.Tests/EndToEnd/DripCampaignDeactivateAllAsyncTests.cs create mode 100644 SendWithUs.Client.Tests/EndToEnd/DripCampaignDeactivateAsyncTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllRequestConverterTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllRequestTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllResponseTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/DripCampaignDeactivateRequestConverterTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/DripCampaignDeactivateRequestTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/DripCampaignDeactivateResponseTests.cs create mode 100644 SendWithUs.Client/Requests/DripCampaignDeactivateAllRequest.cs create mode 100644 SendWithUs.Client/Requests/DripCampaignDeactivateAllRequestConverter.cs create mode 100644 SendWithUs.Client/Requests/DripCampaignDeactivateRequest.cs create mode 100644 SendWithUs.Client/Requests/DripCampaignDeactivateRequestConverter.cs create mode 100644 SendWithUs.Client/Requests/IDripCampaignDeactivateAllRequest.cs create mode 100644 SendWithUs.Client/Requests/IDripCampaignDeactivateRequest.cs create mode 100644 SendWithUs.Client/Responses/DripCampaignDeactivateAllResponse.cs create mode 100644 SendWithUs.Client/Responses/DripCampaignDeactivateResponse.cs create mode 100644 SendWithUs.Client/Responses/IDripCampaignDeactivateAllResponse.cs create mode 100644 SendWithUs.Client/Responses/IDripCampaignDeactivateResponse.cs diff --git a/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs b/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs index 1a41011..d2b05ba 100755 --- a/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs +++ b/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs @@ -80,5 +80,53 @@ protected void ValidateDripCampaignActivateRequest(JObject jsonObject, string ex Assert.IsTrue(recipientAddressFound); } + + protected void ValidateDripCampaignDeactivateRequest(JObject jsonObject, string expectedRecipientAddress, bool allowOtherProperties) + { + var recipientAddressFound = false; + + foreach (var pair in jsonObject) + { + switch (pair.Key) + { + case "recipient_address": + Assert.AreEqual(expectedRecipientAddress, pair.Value); + recipientAddressFound = true; + break; + default: + if (!allowOtherProperties) + { + Assert.Fail("Unexpected object property '{0}'", pair.Key); + } + break; + } + } + + Assert.IsTrue(recipientAddressFound); + } + + protected void ValidateDripCampaignDeactivateAllRequest(JObject jsonObject, string expectedRecipientAddress, bool allowOtherProperties) + { + var recipientAddressFound = false; + + foreach (var pair in jsonObject) + { + switch (pair.Key) + { + case "recipient_address": + Assert.AreEqual(expectedRecipientAddress, pair.Value); + recipientAddressFound = true; + break; + default: + if (!allowOtherProperties) + { + Assert.Fail("Unexpected object property '{0}'", pair.Key); + } + break; + } + } + + Assert.IsTrue(recipientAddressFound); + } } } diff --git a/SendWithUs.Client.Tests/Component/DripCampaignDeactivateAllConverterTests.cs b/SendWithUs.Client.Tests/Component/DripCampaignDeactivateAllConverterTests.cs new file mode 100644 index 0000000..4a0a2a2 --- /dev/null +++ b/SendWithUs.Client.Tests/Component/DripCampaignDeactivateAllConverterTests.cs @@ -0,0 +1,54 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Component +{ + using System.Collections.Generic; + using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using SendWithUs.Client; + + [TestClass] + public class DripCampaignDeactivateAllConverterTests : ComponentTestsBase + { + #region Helpers + + #endregion + + #region Test methods + + [TestMethod] + public void WriteJson_MinimalDripCampaignDeactivateAllRequest_Succeeds() + { + var recipientAddress = TestHelper.GetUniqueId(); + var request = new DripCampaignDeactivateAllRequest(recipientAddress); + var writer = BufferedJsonStringWriter.Create(); + var serializer = JsonSerializer.Create(); + var converter = new DripCampaignDeactivateAllRequestConverter(); + + converter.WriteJson(writer, request, serializer); + var jsonObject = writer.GetBufferAs(); + + Assert.IsNotNull(jsonObject); + this.ValidateDripCampaignDeactivateAllRequest(jsonObject, recipientAddress, false); + } + #endregion + } +} diff --git a/SendWithUs.Client.Tests/Component/DripCampaignDeactivateConverterTests.cs b/SendWithUs.Client.Tests/Component/DripCampaignDeactivateConverterTests.cs new file mode 100644 index 0000000..4ee4369 --- /dev/null +++ b/SendWithUs.Client.Tests/Component/DripCampaignDeactivateConverterTests.cs @@ -0,0 +1,55 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Component +{ + using System.Collections.Generic; + using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using SendWithUs.Client; + + [TestClass] + public class DripCampaignDeactivateConverterTests : ComponentTestsBase + { + #region Helpers + + #endregion + + #region Test methods + + [TestMethod] + public void WriteJson_MinimalDripCampaignDeactivateRequest_Succeeds() + { + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var request = new DripCampaignDeactivateRequest(campaignId, recipientAddress); + var writer = BufferedJsonStringWriter.Create(); + var serializer = JsonSerializer.Create(); + var converter = new DripCampaignDeactivateRequestConverter(); + + converter.WriteJson(writer, request, serializer); + var jsonObject = writer.GetBufferAs(); + + Assert.IsNotNull(jsonObject); + this.ValidateDripCampaignDeactivateRequest(jsonObject, recipientAddress, false); + } + #endregion + } +} diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateAllRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateAllRequest.xml new file mode 100644 index 0000000..680be01 --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateAllRequest.xml @@ -0,0 +1,5 @@ + + + test_64afdf86aa571c901db5c70cf7a953727132599e + kkaplan@hattonpoint.com + \ No newline at end of file diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateRequest.xml new file mode 100644 index 0000000..5f2d25d --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateRequest.xml @@ -0,0 +1,6 @@ + + + test_64afdf86aa571c901db5c70cf7a953727132599e + dc_pZ5niXSbnCCv3FbojQ7F4G + kkaplan@hattonpoint.com + \ No newline at end of file diff --git a/SendWithUs.Client.Tests/EndToEnd/DripCampaignActivateAsyncTests.cs b/SendWithUs.Client.Tests/EndToEnd/DripCampaignActivateAsyncTests.cs new file mode 100644 index 0000000..6b9a52f --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/DripCampaignActivateAsyncTests.cs @@ -0,0 +1,70 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.EndToEnd +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Net; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using SendWithUs.Client; + + [TestClass] + public class DripCampaignActivateAsyncTests + { + [TestMethod] + public void DripCampaignActivateAsync_MinimalRequest_Succeeds() + { + // Arrange + var testData = new TestData("EndToEnd/Data/DripCampaignActivateRequest.xml"); + var request = new DripCampaignActivateRequest(testData.CampaignId, testData.RecipientAddress); + var client = new SendWithUsClient(testData.ApiKey); + + // Act + var response = client.SingleAsync(request).Result; + + // Assert + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + Assert.AreEqual(typeof(DripCampaignActivateResponse), response.GetType()); + var typedResponse = (DripCampaignActivateResponse)response; + Assert.AreEqual("OK", typedResponse.Status, true); + Assert.AreEqual(true, typedResponse.Success); + } + + [TestMethod] + public void DripCampaignActivateAsync_WithData_Succeeds() + { + // Arrange + var testData = new TestData("EndToEnd/Data/DripCampaignActivateRequest.xml"); + var subject = "DripCampaignActivateAsync_WithData " + TestHelper.GetUniqueId(); + var request = new DripCampaignActivateRequest(testData.CampaignId, testData.RecipientAddress, testData.Data.Upsert("subject", subject)); + var client = new SendWithUsClient(testData.ApiKey); + + // Act + var response = client.SingleAsync(request).Result; + + // Assert + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + Assert.AreEqual(typeof(DripCampaignActivateResponse), response.GetType()); + var typedResponse = (DripCampaignActivateResponse)response; + Assert.AreEqual("OK", typedResponse.Status, true); + Assert.AreEqual(true, typedResponse.Success); + } + } +} diff --git a/SendWithUs.Client.Tests/EndToEnd/DripCampaignDeactivateAllAsyncTests.cs b/SendWithUs.Client.Tests/EndToEnd/DripCampaignDeactivateAllAsyncTests.cs new file mode 100644 index 0000000..acb8076 --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/DripCampaignDeactivateAllAsyncTests.cs @@ -0,0 +1,50 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.EndToEnd +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Net; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using SendWithUs.Client; + + [TestClass] + public class DripCampaignDeactivateAllAsyncTests + { + [TestMethod] + public void DripCampaignDeactivateAllAsync_MinimalRequest_Succeeds() + { + // Arrange + var testData = new TestData("EndToEnd/Data/DripCampaignDeactivateAllRequest.xml"); + var request = new DripCampaignDeactivateAllRequest(testData.RecipientAddress); + var client = new SendWithUsClient(testData.ApiKey); + + // Act + var response = client.SingleAsync(request).Result; + + // Assert + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + Assert.AreEqual(typeof(DripCampaignDeactivateAllResponse), response.GetType()); + var typedResponse = (DripCampaignDeactivateAllResponse)response; + Assert.AreEqual("OK", typedResponse.Status, true); + Assert.AreEqual(true, typedResponse.Success); + } + } +} diff --git a/SendWithUs.Client.Tests/EndToEnd/DripCampaignDeactivateAsyncTests.cs b/SendWithUs.Client.Tests/EndToEnd/DripCampaignDeactivateAsyncTests.cs new file mode 100644 index 0000000..c592d07 --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/DripCampaignDeactivateAsyncTests.cs @@ -0,0 +1,50 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.EndToEnd +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Net; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using SendWithUs.Client; + + [TestClass] + public class DripCampaignDeactivateAsyncTests + { + [TestMethod] + public void DripCampaignDeactivateAsync_MinimalRequest_Succeeds() + { + // Arrange + var testData = new TestData("EndToEnd/Data/DripCampaignDeactivateRequest.xml"); + var request = new DripCampaignDeactivateRequest(testData.CampaignId, testData.RecipientAddress); + var client = new SendWithUsClient(testData.ApiKey); + + // Act + var response = client.SingleAsync(request).Result; + + // Assert + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + Assert.AreEqual(typeof(DripCampaignDeactivateResponse), response.GetType()); + var typedResponse = (DripCampaignDeactivateResponse)response; + Assert.AreEqual("OK", typedResponse.Status, true); + Assert.AreEqual(true, typedResponse.Success); + } + } +} diff --git a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj index dfe8b3d..2ac1d17 100755 --- a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj +++ b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj @@ -78,12 +78,16 @@ + + + + @@ -99,6 +103,12 @@ + + + + + + @@ -123,6 +133,12 @@ Always + + Always + + + Always + diff --git a/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllRequestConverterTests.cs b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllRequestConverterTests.cs new file mode 100644 index 0000000..dd939b8 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllRequestConverterTests.cs @@ -0,0 +1,203 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json; + using SendWithUs.Client; + using Names = DripCampaignDeactivateAllRequestConverter.PropertyNames; + + [TestClass] + public class DripCampaignDeactivateAllRequestConverterTests + { + public class NonDripCampaignDeactivateAllRequest { } + + public interface IDripCampaignDeactivateAllRequestSubtype : IDripCampaignDeactivateAllRequest { } + + [TestMethod] + public void CanRead_Getter_ReturnsFalse() + { + // Arrange + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + var canRead = converter.CanRead; + + // Assert + Assert.IsFalse(canRead); + } + + [TestMethod] + public void CanWrite_Getter_ReturnsTrue() + { + // Arrange + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + var canWrite = converter.CanWrite; + + // Assert + Assert.IsTrue(canWrite); + } + + [TestMethod] + public void CanConvert_IDripCampaignDeactivateAllRequestType_ReturnsTrue() + { + // Arrange + var type = typeof(IDripCampaignDeactivateAllRequest); + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_IDripCampaignDeactivateAllRequestSubtype_ReturnsTrue() + { + // Arrange + var type = typeof(IDripCampaignDeactivateAllRequestSubtype); + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_NonIDripCampaignDeactivateAllRequestType_ReturnsFalse() + { + // Arrange + var type = typeof(NonDripCampaignDeactivateAllRequest); + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsFalse(canConvert); + } + + [TestMethod] + public void ReadJson_Always_Throws() + { + // Arrange + var reader = new Mock().Object; + var serializer = new Mock().Object; + var request = new Mock().Object; + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.ReadJson(reader, request.GetType(), request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(NotImplementedException)); + } + + [TestMethod] + public void WriteJson_NullWriter_Throws() + { + // Arrange + var serializer = new Mock(null).Object; + var request = new Mock().Object; + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(null, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentNullException)); + } + + [TestMethod] + public void WriteJson_NullSerializer_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = null as SerializerProxy; + var request = new Mock().Object; + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentNullException)); + } + + [TestMethod] + public void WriteJson_NonIDripCampaignDeactivateAllRequestValue_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = new Mock(null).Object; + var value = new NonDripCampaignDeactivateAllRequest(); + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, value, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentException)); + } + + [TestMethod] + public void WriteJson_Normally_WritesObject() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new DripCampaignDeactivateAllRequestConverter(); + + // Act + converter.WriteJson(writer.Object, request.Object, serializer.Object); + + // Assert + writer.Verify(w => w.WriteStartObject(), Times.AtLeastOnce); + writer.Verify(w => w.WriteEndObject(), Times.AtLeastOnce); + } + + [TestMethod] + public void WriteJson_Normally_CallsHelpers() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new Mock() { CallBase = true }; + var recipientAddress = TestHelper.GetUniqueId(); + + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + converter.Object.WriteJson(writer.Object, request.Object, serializer.Object); + + // Assert + converter.Verify(c => c.WriteProperty(writer.Object, serializer.Object, Names.RecipientAddress, recipientAddress, true), Times.Once); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllRequestTests.cs b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllRequestTests.cs new file mode 100644 index 0000000..a0a2e0a --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllRequestTests.cs @@ -0,0 +1,131 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class DripCampaignDeactivateAllRequestTests + { + [TestMethod] + public void IsValid_Getter_CallsValidate() + { + // Arrange + var request = new Mock() { CallBase = true }; + + // Act + var isValid = request.Object.IsValid; + + // Assert + request.Verify(r => r.Validate(false), Times.Once); + } + + [TestMethod] + public void GetResponseType_Always_ReturnsDripCampaignDeactivateAllResponseType() + { + // Arrange + var request = new DripCampaignDeactivateAllRequest(); + + // Act + var responseType = request.GetResponseType(); + + // Assert + Assert.AreEqual(typeof(DripCampaignDeactivateAllResponse), responseType); + } + + [TestMethod] + public void Validate_Always_CallsValidateBool() + { + // Arrange + var request = new Mock(); + + // Act + var self = request.Object.Validate(); + + // Assert + request.Verify(r => r.Validate(true), Times.Once); + } + + [TestMethod] + public void Validate_Always_ReturnsSelf() + { + // Arrange + var recipientAddress = TestHelper.GetUniqueId(); + var request = new DripCampaignDeactivateAllRequest(recipientAddress); + + // Act + var self = request.Validate(); + + // Assert + Assert.AreSame(request, self); + } + + [TestMethod] + public void ValidateBool_Normally_ReturnsTrue() + { + // Arrange + var recipientAddress = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var isValid = request.Object.Validate(false); + + // Assert + Assert.IsTrue(isValid); + } + + [TestMethod] + public void ValidateBool_TrueFlagAndEmptyRecipientAddress_Throws() + { + // Arrange + var recipientAddress = String.Empty; + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var exception = TestHelper.CaptureException(() => request.Object.Validate(true)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ValidationException)); + var invalid = exception as ValidationException; + Assert.AreEqual(ValidationFailureMode.MissingRecipientAddress, invalid.FailureMode); + } + + [TestMethod] + public void ValidateBool_FalseFlagAndEmptyRecipientAddress_ReturnsFalse() + { + // Arrange + var recipientAddress = String.Empty; + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var isValid = request.Object.Validate(false); + + // Assert + Assert.AreEqual(false, isValid); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllResponseTests.cs b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllResponseTests.cs new file mode 100644 index 0000000..a7f9ff7 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateAllResponseTests.cs @@ -0,0 +1,80 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json.Linq; + using Names = SendWithUs.Client.DripCampaignDeactivateAllResponse.PropertyNames; + + [TestClass] + public class DripCampaignDeactivateAllResponseTests + { + [TestMethod] + public void Populate_NullJson_DoesNotSetProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var json = null as JObject; + + // Act + response.Object.Populate(json); + + // Assert + response.VerifySet(r => r.Success = It.IsAny(), Times.Never); + response.VerifySet(r => r.Status = It.IsAny(), Times.Never); + response.VerifySet(r => r.RecipientAddress = It.IsAny(), Times.Never); + response.VerifySet(r => r.UnsubscribedCount = It.IsAny(), Times.Never); + } + + [TestMethod] + public void Populate_ValidJson_SetsProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var success = true; + var status = TestHelper.GetUniqueId(); + var dripCampaignId = TestHelper.GetUniqueId(); + var dripCampaignName = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var unsubscribedCount = TestHelper.GetRandomInteger(0,1000); + var json = new Mock(); + var details = new Mock(); + + json.Setup(j => j.Value(Names.Success)).Returns(success); + json.Setup(j => j.Value(Names.Status)).Returns(status); + json.Setup(j => j.Value(Names.RecipientAddress)).Returns(recipientAddress); + json.Setup(j => j.Value(Names.UnsubscribedCount)).Returns(unsubscribedCount); + + // Act + response.Object.Populate(json.Object); + + // Assert + response.VerifySet(r => r.Success = success, Times.Once); + response.VerifySet(r => r.Status = status, Times.Once); + response.VerifySet(r => r.RecipientAddress = recipientAddress, Times.Once); + response.VerifySet(r => r.UnsubscribedCount = unsubscribedCount, Times.Once); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateRequestConverterTests.cs b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateRequestConverterTests.cs new file mode 100644 index 0000000..f35dfe8 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateRequestConverterTests.cs @@ -0,0 +1,203 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json; + using SendWithUs.Client; + using Names = DripCampaignDeactivateRequestConverter.PropertyNames; + + [TestClass] + public class DripCampaignDeactivateRequestConverterTests + { + public class NonDripCampaignDeactivateRequest { } + + public interface IDripCampaignDeactivateRequestSubtype : IDripCampaignDeactivateRequest { } + + [TestMethod] + public void CanRead_Getter_ReturnsFalse() + { + // Arrange + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + var canRead = converter.CanRead; + + // Assert + Assert.IsFalse(canRead); + } + + [TestMethod] + public void CanWrite_Getter_ReturnsTrue() + { + // Arrange + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + var canWrite = converter.CanWrite; + + // Assert + Assert.IsTrue(canWrite); + } + + [TestMethod] + public void CanConvert_IDripCampaignDeactivateRequestType_ReturnsTrue() + { + // Arrange + var type = typeof(IDripCampaignDeactivateRequest); + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_IDripCampaignDeactivateRequestSubtype_ReturnsTrue() + { + // Arrange + var type = typeof(IDripCampaignDeactivateRequestSubtype); + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_NonIDripCampaignDeactivateRequestType_ReturnsFalse() + { + // Arrange + var type = typeof(NonDripCampaignDeactivateRequest); + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsFalse(canConvert); + } + + [TestMethod] + public void ReadJson_Always_Throws() + { + // Arrange + var reader = new Mock().Object; + var serializer = new Mock().Object; + var request = new Mock().Object; + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.ReadJson(reader, request.GetType(), request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(NotImplementedException)); + } + + [TestMethod] + public void WriteJson_NullWriter_Throws() + { + // Arrange + var serializer = new Mock(null).Object; + var request = new Mock().Object; + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(null, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentNullException)); + } + + [TestMethod] + public void WriteJson_NullSerializer_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = null as SerializerProxy; + var request = new Mock().Object; + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentNullException)); + } + + [TestMethod] + public void WriteJson_NonIDripCampaignDeactivateRequestValue_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = new Mock(null).Object; + var value = new NonDripCampaignDeactivateRequest(); + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, value, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentException)); + } + + [TestMethod] + public void WriteJson_Normally_WritesObject() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new DripCampaignDeactivateRequestConverter(); + + // Act + converter.WriteJson(writer.Object, request.Object, serializer.Object); + + // Assert + writer.Verify(w => w.WriteStartObject(), Times.AtLeastOnce); + writer.Verify(w => w.WriteEndObject(), Times.AtLeastOnce); + } + + [TestMethod] + public void WriteJson_Normally_CallsHelpers() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new Mock() { CallBase = true }; + var recipientAddress = TestHelper.GetUniqueId(); + + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + converter.Object.WriteJson(writer.Object, request.Object, serializer.Object); + + // Assert + converter.Verify(c => c.WriteProperty(writer.Object, serializer.Object, Names.RecipientAddress, recipientAddress, true), Times.Once); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateRequestTests.cs b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateRequestTests.cs new file mode 100644 index 0000000..5793c43 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateRequestTests.cs @@ -0,0 +1,176 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class DripCampaignDeactivateRequestTests + { + [TestMethod] + public void IsValid_Getter_CallsValidate() + { + // Arrange + var request = new Mock() { CallBase = true }; + + // Act + var isValid = request.Object.IsValid; + + // Assert + request.Verify(r => r.Validate(false), Times.Once); + } + + [TestMethod] + public void GetResponseType_Always_ReturnsDripCampaignDeactivateResponseType() + { + // Arrange + var request = new DripCampaignDeactivateRequest(); + + // Act + var responseType = request.GetResponseType(); + + // Assert + Assert.AreEqual(typeof(DripCampaignDeactivateResponse), responseType); + } + + [TestMethod] + public void Validate_Always_CallsValidateBool() + { + // Arrange + var request = new Mock(); + + // Act + var self = request.Object.Validate(); + + // Assert + request.Verify(r => r.Validate(true), Times.Once); + } + + [TestMethod] + public void Validate_Always_ReturnsSelf() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var request = new DripCampaignDeactivateRequest(campaignId, recipientAddress); + + // Act + var self = request.Validate(); + + // Assert + Assert.AreSame(request, self); + } + + [TestMethod] + public void ValidateBool_Normally_ReturnsTrue() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var isValid = request.Object.Validate(false); + + // Assert + Assert.IsTrue(isValid); + } + + [TestMethod] + public void ValidateBool_TrueFlagAndEmptyCampaignId_Throws() + { + // Arrange + var campaignId = String.Empty; + var recipientAddress = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var exception = TestHelper.CaptureException(() => request.Object.Validate(true)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ValidationException)); + var invalid = exception as ValidationException; + Assert.AreEqual(ValidationFailureMode.MissingCampaignId, invalid.FailureMode); + } + + [TestMethod] + public void ValidateBool_TrueFlagAndEmptyRecipientAddress_Throws() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = String.Empty; + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var exception = TestHelper.CaptureException(() => request.Object.Validate(true)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ValidationException)); + var invalid = exception as ValidationException; + Assert.AreEqual(ValidationFailureMode.MissingRecipientAddress, invalid.FailureMode); + } + + [TestMethod] + public void ValidateBool_FalseFlagAndEmptyCampaignId_ReturnsFalse() + { + // Arrange + var campaignId = String.Empty; + var recipientAddress = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var isValid = request.Object.Validate(false); + + // Assert + Assert.AreEqual(false, isValid); + } + + [TestMethod] + public void ValidateBool_FalseFlagAndEmptyRecipientAddress_ReturnsFalse() + { + // Arrange + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = String.Empty; + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.CampaignId).Returns(campaignId); + request.SetupGet(r => r.RecipientAddress).Returns(recipientAddress); + + // Act + var isValid = request.Object.Validate(false); + + // Assert + Assert.AreEqual(false, isValid); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateResponseTests.cs b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateResponseTests.cs new file mode 100644 index 0000000..5cfdb9b --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/DripCampaignDeactivateResponseTests.cs @@ -0,0 +1,87 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json.Linq; + using Names = SendWithUs.Client.DripCampaignDeactivateResponse.PropertyNames; + + [TestClass] + public class DripCampaignDeactivateResponseTests + { + [TestMethod] + public void Populate_NullJson_DoesNotSetProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var json = null as JObject; + + // Act + response.Object.Populate(json); + + // Assert + response.VerifySet(r => r.Success = It.IsAny(), Times.Never); + response.VerifySet(r => r.Status = It.IsAny(), Times.Never); + response.VerifySet(r => r.DripCampaignId = It.IsAny(), Times.Never); + response.VerifySet(r => r.DripCampaignName = It.IsAny(), Times.Never); + response.VerifySet(r => r.RecipientAddress = It.IsAny(), Times.Never); + response.VerifySet(r => r.Message = It.IsAny(), Times.Never); + } + + [TestMethod] + public void Populate_ValidJson_SetsProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var success = true; + var status = TestHelper.GetUniqueId(); + var dripCampaignId = TestHelper.GetUniqueId(); + var dripCampaignName = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var message = TestHelper.GetUniqueId(); + var json = new Mock(); + var details = new Mock(); + + json.Setup(j => j.Value(Names.Success)).Returns(success); + json.Setup(j => j.Value(Names.Status)).Returns(status); + json.Setup(j => j.Value(Names.RecipientAddress)).Returns(recipientAddress); + json.Setup(j => j.Value(Names.Message)).Returns(message); + response.Setup(r => r.GetPropertyValue(json.Object, Names.Details)).Returns(details.Object); + details.Setup(d => d.Value(Names.DripCampaignId)).Returns(dripCampaignId); + details.Setup(d => d.Value(Names.DripCampaignName)).Returns(dripCampaignName); + + // Act + response.Object.Populate(json.Object); + + // Assert + response.VerifySet(r => r.Success = success, Times.Once); + response.VerifySet(r => r.Status = status, Times.Once); + response.VerifySet(r => r.RecipientAddress = recipientAddress, Times.Once); + response.VerifySet(r => r.Message = message, Times.Once); + response.VerifySet(r => r.DripCampaignId = dripCampaignId, Times.Once); + response.VerifySet(r => r.DripCampaignName = dripCampaignName, Times.Once); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/SendWithUsClientTests.cs b/SendWithUs.Client.Tests/Unit/SendWithUsClientTests.cs index 32a63fb..67150d4 100755 --- a/SendWithUs.Client.Tests/Unit/SendWithUsClientTests.cs +++ b/SendWithUs.Client.Tests/Unit/SendWithUsClientTests.cs @@ -48,14 +48,14 @@ public void SendAsync_NullRequest_Throws() #region DripCampaignActivateAsync [TestMethod] - public void DripCampaignActivateAsync_NullRequest_Throws() + public void SingleAsync_NullRequest_Throws() { // Arrange var apiKey = TestHelper.GetUniqueId(); var client = new SendWithUsClient(apiKey); // Act - var exception = TestHelper.CaptureException(() => client.DripCampaignActivateAsync(null)); + var exception = TestHelper.CaptureException(() => client.SingleAsync(null)); // Assert Assert.IsInstanceOfType(exception, typeof(ArgumentNullException)); diff --git a/SendWithUs.Client/ISendWithUsClient.cs b/SendWithUs.Client/ISendWithUsClient.cs index 65cb76e..1958fe4 100755 --- a/SendWithUs.Client/ISendWithUsClient.cs +++ b/SendWithUs.Client/ISendWithUsClient.cs @@ -35,6 +35,13 @@ public interface ISendWithUsClient /// A response object. Task SendAsync(ISendRequest request); + /// + /// Sends a request to the API + /// + /// A request object describing what you want to do + /// A response object. + Task SingleAsync(IRequest request); + /// /// Submits a batch request comprising the given set of request objects. /// diff --git a/SendWithUs.Client/Requests/DripCampaignActivateRequest.cs b/SendWithUs.Client/Requests/DripCampaignActivateRequest.cs index e1332e7..61fe0ba 100644 --- a/SendWithUs.Client/Requests/DripCampaignActivateRequest.cs +++ b/SendWithUs.Client/Requests/DripCampaignActivateRequest.cs @@ -118,7 +118,7 @@ protected internal virtual bool Validate(bool throwOnFailure) return false; }; - // Template ID is required. + // Campaign ID is required. if (String.IsNullOrEmpty(this.CampaignId)) { return fail(ValidationFailureMode.MissingCampaignId); diff --git a/SendWithUs.Client/Requests/DripCampaignDeactivateAllRequest.cs b/SendWithUs.Client/Requests/DripCampaignDeactivateAllRequest.cs new file mode 100644 index 0000000..d803ac4 --- /dev/null +++ b/SendWithUs.Client/Requests/DripCampaignDeactivateAllRequest.cs @@ -0,0 +1,104 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + + /// + /// Represents the data necessary to make API requests to deactivate all drip campaigns for a user. + /// + [JsonConverter(typeof(DripCampaignDeactivateAllRequestConverter))] + public class DripCampaignDeactivateAllRequest : IDripCampaignDeactivateAllRequest + { + #region Constructors + + public DripCampaignDeactivateAllRequest() + { } + + public DripCampaignDeactivateAllRequest(string recipientAddress) + { + EnsureArgument.NotNullOrEmpty(recipientAddress, "recipientAddress"); + + this.RecipientAddress = recipientAddress; + } + + #endregion + + #region IDripCampaignActivateRequest members + + public virtual string RecipientAddress { get; set; } + + public virtual bool IsValid + { + get { return this.Validate(false); } + } + + #endregion + + #region IRequest members + + public string GetUriPath() + { + return "/api/v1/drip_campaigns/deactivate"; + } + + public string GetHttpMethod() + { + return "POST"; + } + + public Type GetResponseType() + { + return typeof(DripCampaignDeactivateAllResponse); + } + + public IRequest Validate() + { + this.Validate(true); + return this; + } + + protected internal virtual bool Validate(bool throwOnFailure) + { + Func fail = (f) => + { + if (throwOnFailure) + { + throw new ValidationException(f); + } + + return false; + }; + + // Recipient address is required. + if (String.IsNullOrEmpty(this.RecipientAddress)) + { + return fail(ValidationFailureMode.MissingRecipientAddress); + } + + return true; + } + + #endregion + } +} diff --git a/SendWithUs.Client/Requests/DripCampaignDeactivateAllRequestConverter.cs b/SendWithUs.Client/Requests/DripCampaignDeactivateAllRequestConverter.cs new file mode 100644 index 0000000..51c7e29 --- /dev/null +++ b/SendWithUs.Client/Requests/DripCampaignDeactivateAllRequestConverter.cs @@ -0,0 +1,99 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using System.Reflection; + using Newtonsoft.Json; + + /// + /// Converts a DripCampaignDectivateAll object to JSON. + /// + public class DripCampaignDeactivateAllRequestConverter : JsonConverter + { + public static class PropertyNames + { + public const string RecipientAddress = "recipient_address"; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override bool CanConvert(Type objectType) + { + return typeof(IDripCampaignDeactivateAllRequest).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + // KLUGE: JsonSerializer is not mockable, so we resort to the bad practice of inserting + // code (i.e., the proxy) merely to support unit testing. + this.WriteJson(writer, value, new SerializerProxy(serializer)); + } + + protected internal virtual void WriteJson(JsonWriter writer, object value, SerializerProxy serializer) + { + EnsureArgument.NotNull(writer, "writer"); + EnsureArgument.NotNull(serializer, "serializer"); + + var request = EnsureArgument.Of(value, "value"); + + writer.WriteStartObject(); + + this.WriteProperty(writer, serializer, PropertyNames.RecipientAddress, request.RecipientAddress, true); + + writer.WriteEndObject(); + } + + protected internal virtual void WriteProperty(JsonWriter writer, SerializerProxy serializer, string name, object value, bool isOptional) + { + if (isOptional && value == null) + { + return; + } + + writer.WritePropertyName(name); + serializer.Serialize(writer, value); + } + + protected internal virtual void WriteProperty(JsonWriter writer, SerializerProxy serializer, string name, string value, bool isOptional) + { + if (isOptional && String.IsNullOrEmpty(value)) + { + return; + } + + writer.WritePropertyName(name); + serializer.Serialize(writer, value); + } + } +} diff --git a/SendWithUs.Client/Requests/DripCampaignDeactivateRequest.cs b/SendWithUs.Client/Requests/DripCampaignDeactivateRequest.cs new file mode 100644 index 0000000..cfb2892 --- /dev/null +++ b/SendWithUs.Client/Requests/DripCampaignDeactivateRequest.cs @@ -0,0 +1,114 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + + /// + /// Represents the data necessary to make API requests to deactivate a drip campaign. + /// + [JsonConverter(typeof(DripCampaignDeactivateRequestConverter))] + public class DripCampaignDeactivateRequest : IDripCampaignDeactivateRequest + { + #region Constructors + + public DripCampaignDeactivateRequest() + { } + + public DripCampaignDeactivateRequest(string campaignId, string recipientAddress) + { + EnsureArgument.NotNullOrEmpty(campaignId, "campaignId"); + EnsureArgument.NotNullOrEmpty(recipientAddress, "recipientAddress"); + + this.CampaignId = campaignId; + this.RecipientAddress = recipientAddress; + } + + #endregion + + #region IDripCampaignActivateRequest members + + public virtual string CampaignId { get; set; } + + public virtual string RecipientAddress { get; set; } + + public virtual bool IsValid + { + get { return this.Validate(false); } + } + + #endregion + + #region IRequest members + + public string GetUriPath() + { + return "/api/v1/" + string.Format("drip_campaigns/{0}/deactivate", this.CampaignId); + } + + public string GetHttpMethod() + { + return "POST"; + } + + public Type GetResponseType() + { + return typeof(DripCampaignDeactivateResponse); + } + + public IRequest Validate() + { + this.Validate(true); + return this; + } + + protected internal virtual bool Validate(bool throwOnFailure) + { + Func fail = (f) => + { + if (throwOnFailure) + { + throw new ValidationException(f); + } + + return false; + }; + + // Campaign ID is required. + if (String.IsNullOrEmpty(this.CampaignId)) + { + return fail(ValidationFailureMode.MissingCampaignId); + } + + // Recipient address is required. + if (String.IsNullOrEmpty(this.RecipientAddress)) + { + return fail(ValidationFailureMode.MissingRecipientAddress); + } + + return true; + } + + #endregion + } +} diff --git a/SendWithUs.Client/Requests/DripCampaignDeactivateRequestConverter.cs b/SendWithUs.Client/Requests/DripCampaignDeactivateRequestConverter.cs new file mode 100644 index 0000000..5f0ed07 --- /dev/null +++ b/SendWithUs.Client/Requests/DripCampaignDeactivateRequestConverter.cs @@ -0,0 +1,99 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using System.Reflection; + using Newtonsoft.Json; + + /// + /// Converts a DripCampaignDeactivate object to JSON. + /// + public class DripCampaignDeactivateRequestConverter : JsonConverter + { + public static class PropertyNames + { + public const string RecipientAddress = "recipient_address"; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override bool CanConvert(Type objectType) + { + return typeof(IDripCampaignDeactivateRequest).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotImplementedException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + // KLUGE: JsonSerializer is not mockable, so we resort to the bad practice of inserting + // code (i.e., the proxy) merely to support unit testing. + this.WriteJson(writer, value, new SerializerProxy(serializer)); + } + + protected internal virtual void WriteJson(JsonWriter writer, object value, SerializerProxy serializer) + { + EnsureArgument.NotNull(writer, "writer"); + EnsureArgument.NotNull(serializer, "serializer"); + + var request = EnsureArgument.Of(value, "value"); + + writer.WriteStartObject(); + + this.WriteProperty(writer, serializer, PropertyNames.RecipientAddress, request.RecipientAddress, true); + + writer.WriteEndObject(); + } + + protected internal virtual void WriteProperty(JsonWriter writer, SerializerProxy serializer, string name, object value, bool isOptional) + { + if (isOptional && value == null) + { + return; + } + + writer.WritePropertyName(name); + serializer.Serialize(writer, value); + } + + protected internal virtual void WriteProperty(JsonWriter writer, SerializerProxy serializer, string name, string value, bool isOptional) + { + if (isOptional && String.IsNullOrEmpty(value)) + { + return; + } + + writer.WritePropertyName(name); + serializer.Serialize(writer, value); + } + } +} diff --git a/SendWithUs.Client/Requests/IDripCampaignDeactivateAllRequest.cs b/SendWithUs.Client/Requests/IDripCampaignDeactivateAllRequest.cs new file mode 100644 index 0000000..10b526d --- /dev/null +++ b/SendWithUs.Client/Requests/IDripCampaignDeactivateAllRequest.cs @@ -0,0 +1,41 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +namespace SendWithUs.Client +{ + using System.Collections.Generic; + + /// + /// Describes the interface of objects used to make API requests to deactivate all drip campaigns. + /// + /// This interface roughly corresponds to the JSON object used with the /drip_campaigns/deactivate route + /// in the REST API, with some properties flattened or renamed. + public interface IDripCampaignDeactivateAllRequest : IRequest + { + /// + /// Gets the email address of the message recipient. + /// + string RecipientAddress { get; } + + /// + /// Gets a value indicating whether the request object is valid (well-formed). + /// + bool IsValid { get; } + } +} diff --git a/SendWithUs.Client/Requests/IDripCampaignDeactivateRequest.cs b/SendWithUs.Client/Requests/IDripCampaignDeactivateRequest.cs new file mode 100644 index 0000000..0f338b0 --- /dev/null +++ b/SendWithUs.Client/Requests/IDripCampaignDeactivateRequest.cs @@ -0,0 +1,47 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + + +namespace SendWithUs.Client +{ + using System.Collections.Generic; + + /// + /// Describes the interface of objects used to make API requests to deactivate drip campaigns. + /// + /// This interface roughly corresponds to the JSON object used with the /drip_campaigns/(drip_campaign_id)/deactivate route + /// in the REST API, with some properties flattened or renamed. + public interface IDripCampaignDeactivateRequest : IRequest + { + /// + /// Gets the unique identifier of an email template. + /// + /// Corresponds to the "drip_campaign_id" property in the SendWithUs API route. + string CampaignId { get; } + + /// + /// Gets the email address of the message recipient. + /// + string RecipientAddress { get; } + + /// + /// Gets a value indicating whether the request object is valid (well-formed). + /// + bool IsValid { get; } + } +} diff --git a/SendWithUs.Client/Responses/DripCampaignDeactivateAllResponse.cs b/SendWithUs.Client/Responses/DripCampaignDeactivateAllResponse.cs new file mode 100644 index 0000000..dfd7afd --- /dev/null +++ b/SendWithUs.Client/Responses/DripCampaignDeactivateAllResponse.cs @@ -0,0 +1,72 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using Newtonsoft.Json.Linq; + + public class DripCampaignDeactivateAllResponse : BaseResponse, IDripCampaignDeactivateAllResponse + { + public static class PropertyNames + { + public const string Success = "success"; + public const string Status = "status"; + public const string RecipientAddress = "recipient_address"; + public const string UnsubscribedCount = "unsubscribed_count"; + } + + public virtual bool Success { get; set; } + + public virtual string Status { get; set; } + + public virtual string RecipientAddress { get; set; } + + public virtual int UnsubscribedCount { get; set; } + + #region Base class overrides + + protected internal override void Populate(JObject json) + { + if (json == null) + { + return; + } + + this.Success = json.Value(PropertyNames.Success); + this.Status = json.Value(PropertyNames.Status); + this.RecipientAddress = json.Value(PropertyNames.RecipientAddress); + this.UnsubscribedCount = json.Value(PropertyNames.UnsubscribedCount); + } + + /// + /// Gets the value of the named property on the specified object. + /// + /// The object from which to get the property value. + /// The property value. + /// This method exists to aid unit testing of Populate(), because JObject.GetValue() + /// is not virtual and therefore cannot be mocked. + protected internal virtual JToken GetPropertyValue(JObject json, string propertyName) + { + //var details = json.Property(propertyName); + //return (details != null && details.HasValues) ? details.Value : null; + return json.GetValue(propertyName); + } + + #endregion + } +} diff --git a/SendWithUs.Client/Responses/DripCampaignDeactivateResponse.cs b/SendWithUs.Client/Responses/DripCampaignDeactivateResponse.cs new file mode 100644 index 0000000..a2a1eaa --- /dev/null +++ b/SendWithUs.Client/Responses/DripCampaignDeactivateResponse.cs @@ -0,0 +1,87 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using Newtonsoft.Json.Linq; + + public class DripCampaignDeactivateResponse : BaseResponse, IDripCampaignDeactivateResponse + { + public static class PropertyNames + { + public const string Success = "success"; + public const string Status = "status"; + public const string Details = "drip_campaign"; + public const string DripCampaignId = "id"; + public const string DripCampaignName = "name"; + public const string RecipientAddress = "recipient_address"; + public const string Message = "message"; + } + + public virtual bool Success { get; set; } + + public virtual string Status { get; set; } + + public virtual string DripCampaignId { get; set; } + + public virtual string DripCampaignName { get; set; } + + public virtual string RecipientAddress { get; set; } + + public virtual string Message { get; set; } + + #region Base class overrides + + protected internal override void Populate(JObject json) + { + if (json == null) + { + return; + } + + this.Success = json.Value(PropertyNames.Success); + this.Status = json.Value(PropertyNames.Status); + this.RecipientAddress = json.Value(PropertyNames.RecipientAddress); + this.Message = json.Value(PropertyNames.Message); + + var details = this.GetPropertyValue(json, PropertyNames.Details); + + if (details != null) + { + this.DripCampaignId = details.Value(PropertyNames.DripCampaignId); + this.DripCampaignName = details.Value(PropertyNames.DripCampaignName); + } + } + + /// + /// Gets the value of the named property on the specified object. + /// + /// The object from which to get the property value. + /// The property value. + /// This method exists to aid unit testing of Populate(), because JObject.GetValue() + /// is not virtual and therefore cannot be mocked. + protected internal virtual JToken GetPropertyValue(JObject json, string propertyName) + { + //var details = json.Property(propertyName); + //return (details != null && details.HasValues) ? details.Value : null; + return json.GetValue(propertyName); + } + + #endregion + } +} diff --git a/SendWithUs.Client/Responses/IDripCampaignDeactivateAllResponse.cs b/SendWithUs.Client/Responses/IDripCampaignDeactivateAllResponse.cs new file mode 100644 index 0000000..80f466e --- /dev/null +++ b/SendWithUs.Client/Responses/IDripCampaignDeactivateAllResponse.cs @@ -0,0 +1,31 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + public interface IDripCampaignDeactivateAllResponse : IResponse + { + bool Success { get; } + + string Status { get; } + + string RecipientAddress { get; } + + int UnsubscribedCount { get; } + } +} diff --git a/SendWithUs.Client/Responses/IDripCampaignDeactivateResponse.cs b/SendWithUs.Client/Responses/IDripCampaignDeactivateResponse.cs new file mode 100644 index 0000000..e297552 --- /dev/null +++ b/SendWithUs.Client/Responses/IDripCampaignDeactivateResponse.cs @@ -0,0 +1,35 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + public interface IDripCampaignDeactivateResponse : IResponse + { + bool Success { get; } + + string Status { get; } + + string DripCampaignId { get; } + + string DripCampaignName { get; } + + string RecipientAddress { get; } + + string Message { get; } + } +} diff --git a/SendWithUs.Client/SendWithUs.Client.csproj b/SendWithUs.Client/SendWithUs.Client.csproj index 16ebf33..31350c4 100755 --- a/SendWithUs.Client/SendWithUs.Client.csproj +++ b/SendWithUs.Client/SendWithUs.Client.csproj @@ -48,7 +48,13 @@ + + + + + + @@ -56,8 +62,12 @@ + + + + diff --git a/SendWithUs.Client/SendWithUsClient.cs b/SendWithUs.Client/SendWithUsClient.cs index dd4fe7f..c2c4004 100755 --- a/SendWithUs.Client/SendWithUsClient.cs +++ b/SendWithUs.Client/SendWithUsClient.cs @@ -127,13 +127,19 @@ public virtual async Task SendAsync(ISendRequest request) return this.ResponseFactory.Create(httpResponse.StatusCode, json); } - public virtual async Task DripCampaignActivateAsync(IDripCampaignActivateRequest request) + /// + /// Sends a request to the API + /// + /// A request object describing what you want to do + /// A response object. + /// The request argument was null. + public virtual async Task SingleAsync(IRequest request) { EnsureArgument.NotNull(request, "request"); var httpResponse = await this.PostJsonAsync(request.GetUriPath(), request.Validate()).ConfigureAwait(false); var json = await this.ReadJsonAsync(httpResponse); - return this.ResponseFactory.Create(httpResponse.StatusCode, json); + return this.ResponseFactory.Create(request.GetResponseType(), httpResponse.StatusCode, json); } /// From e96a19b618610b3dadf74f7f0bb7c625871a90c2 Mon Sep 17 00:00:00 2001 From: Kenny Kaplan Date: Mon, 23 Mar 2015 10:44:08 -0600 Subject: [PATCH 3/8] DripCampaignActivateConverterTests --- .../DripCampaignActivateConverterTests.cs | 77 +++++++++++++++++++ .../SendWithUs.Client.Tests.csproj | 1 + SendWithUs.Client.sln | 4 +- 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 SendWithUs.Client.Tests/Component/DripCampaignActivateConverterTests.cs diff --git a/SendWithUs.Client.Tests/Component/DripCampaignActivateConverterTests.cs b/SendWithUs.Client.Tests/Component/DripCampaignActivateConverterTests.cs new file mode 100644 index 0000000..73b69e8 --- /dev/null +++ b/SendWithUs.Client.Tests/Component/DripCampaignActivateConverterTests.cs @@ -0,0 +1,77 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Component +{ + using System.Collections.Generic; + using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using SendWithUs.Client; + + [TestClass] + public class DripCampaignActivateConverterTests : ComponentTestsBase + { + #region Helpers + + #endregion + + #region Test methods + + [TestMethod] + public void WriteJson_MinimalDripCampaignActivateRequest_Succeeds() + { + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var request = new DripCampaignActivateRequest(campaignId, recipientAddress); + var writer = BufferedJsonStringWriter.Create(); + var serializer = JsonSerializer.Create(); + var converter = new DripCampaignActivateRequestConverter(); + + converter.WriteJson(writer, request, serializer); + var jsonObject = writer.GetBufferAs(); + + Assert.IsNotNull(jsonObject); + this.ValidateDripCampaignActivateRequest(jsonObject, recipientAddress, false); + } + + [TestMethod] + public void WriteJson_WithData_IncludesAllData() + { + var campaignId = TestHelper.GetUniqueId(); + var recipientAddress = TestHelper.GetUniqueId(); + var data = TestHelper.GetRandomDictionary(); + var request = new DripCampaignActivateRequest(campaignId, recipientAddress, data); + var writer = BufferedJsonStringWriter.Create(); + var serializer = new JsonSerializer(); + var converter = new DripCampaignActivateRequestConverter(); + + converter.WriteJson(writer, request, serializer); + var jsonObject = writer.GetBufferAs(); + + Assert.IsNotNull(jsonObject); + this.ValidateDripCampaignActivateRequest(jsonObject, recipientAddress, true); + var jsonData = jsonObject.GetValue("email_data") as JObject; + Assert.IsNotNull(jsonData); + Assert.AreEqual(data.Count, jsonData.Count); + } + + #endregion + } +} diff --git a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj index 2ac1d17..d3dbd32 100755 --- a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj +++ b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj @@ -30,6 +30,7 @@ DEBUG;TRACE prompt 4 + false pdbonly diff --git a/SendWithUs.Client.sln b/SendWithUs.Client.sln index c708de3..b6eecbf 100755 --- a/SendWithUs.Client.sln +++ b/SendWithUs.Client.sln @@ -25,8 +25,8 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Debug|Any CPU.ActiveCfg = Release|Any CPU + {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Debug|Any CPU.Build.0 = Release|Any CPU {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Release|Any CPU.ActiveCfg = Release|Any CPU {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Release|Any CPU.Build.0 = Release|Any CPU {C3059E9E-CE97-4E9B-B778-D78EFD1E448A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU From 21add2771ed02ab12baebe9150b793a14194ee99 Mon Sep 17 00:00:00 2001 From: Kenny Kaplan Date: Fri, 3 Apr 2015 08:36:30 -0600 Subject: [PATCH 4/8] Removed IDs --- .../EndToEnd/Data/DripCampaignActivateRequest.xml | 8 ++++---- .../EndToEnd/Data/DripCampaignDeactivateAllRequest.xml | 4 ++-- .../EndToEnd/Data/DripCampaignDeactivateRequest.xml | 6 +++--- SendWithUs.Client.Tests/EndToEnd/Data/SendRequest.xml | 8 ++++---- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignActivateRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignActivateRequest.xml index a95f0f9..b2260f2 100644 --- a/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignActivateRequest.xml +++ b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignActivateRequest.xml @@ -1,9 +1,9 @@  - test_64afdf86aa571c901db5c70cf7a953727132599e - dc_pZ5niXSbnCCv3FbojQ7F4G - kkaplan@hattonpoint.com - kkaplan@hattonpoint.com + + + + diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateAllRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateAllRequest.xml index 680be01..0978337 100644 --- a/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateAllRequest.xml +++ b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateAllRequest.xml @@ -1,5 +1,5 @@  - test_64afdf86aa571c901db5c70cf7a953727132599e - kkaplan@hattonpoint.com + + \ No newline at end of file diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateRequest.xml index 5f2d25d..20cbe9d 100644 --- a/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateRequest.xml +++ b/SendWithUs.Client.Tests/EndToEnd/Data/DripCampaignDeactivateRequest.xml @@ -1,6 +1,6 @@  - test_64afdf86aa571c901db5c70cf7a953727132599e - dc_pZ5niXSbnCCv3FbojQ7F4G - kkaplan@hattonpoint.com + + + \ No newline at end of file diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/SendRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/SendRequest.xml index 8eedd80..fae59cd 100755 --- a/SendWithUs.Client.Tests/EndToEnd/Data/SendRequest.xml +++ b/SendWithUs.Client.Tests/EndToEnd/Data/SendRequest.xml @@ -1,9 +1,9 @@  - test_64afdf86aa571c901db5c70cf7a953727132599e - tem_PUuDKzcTLQrG7hroMxbwWB - kkaplan@hattonpoint.com - kkaplan@hattonpoint.com + + + + EndToEnd/Data/mimeo-logo-black.png From 090805d31c48104498d19b189c3b901d4a935ebd Mon Sep 17 00:00:00 2001 From: Kenny Kaplan Date: Thu, 8 Sep 2016 13:23:55 -0600 Subject: [PATCH 5/8] Add CustomerUpdateRequest --- .../Component/ComponentTestsBase.cs | 29 ++++- .../CustomerUpdateRequestConverterTests.cs | 74 ++++++++++++ .../SendWithUs.Client.Tests.csproj | 1 + .../Helpers/ValidationFailureMode.cs | 3 +- .../Requests/CustomerUpdateRequest.cs | 110 ++++++++++++++++++ .../CustomerUpdateRequestConverter.cs | 72 ++++++++++++ .../Requests/ICustomerUpdateRequest.cs | 53 +++++++++ .../Responses/CustomerUpdateResponse.cs | 56 +++++++++ .../Responses/ICustomerUpdateResponse.cs | 29 +++++ SendWithUs.Client/SendWithUs.Client.csproj | 5 + 10 files changed, 429 insertions(+), 3 deletions(-) create mode 100644 SendWithUs.Client.Tests/Component/CustomerUpdateRequestConverterTests.cs create mode 100644 SendWithUs.Client/Requests/CustomerUpdateRequest.cs create mode 100644 SendWithUs.Client/Requests/CustomerUpdateRequestConverter.cs create mode 100644 SendWithUs.Client/Requests/ICustomerUpdateRequest.cs create mode 100644 SendWithUs.Client/Responses/CustomerUpdateResponse.cs create mode 100644 SendWithUs.Client/Responses/ICustomerUpdateResponse.cs diff --git a/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs b/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs index 91f89c5..8095174 100755 --- a/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs +++ b/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs @@ -26,7 +26,8 @@ namespace SendWithUs.Client.Tests.Component using System.Collections.Generic; using RenderNames = SendWithUs.Client.RenderRequestConverter.PropertyNames; using SendNames = SendWithUs.Client.SendRequestConverter.PropertyNames; - + using CustomerUpdateNames = SendWithUs.Client.CustomerUpdateRequestConverter.PropertyNames; + using System.Linq; public abstract class ComponentTestsBase { protected void ValidateSendRequest(SendRequest request, JObject jsonObject) @@ -115,8 +116,32 @@ protected void ValidateRenderRequest(JObject jsonObject, string expectedTemplate } Assert.IsTrue(templateIdFound); + } + + protected void ValidateCustomerUpdateRequest(CustomerUpdateRequest request, JObject jsonObject) + { + var emailFound = false; + + foreach(var pair in jsonObject) + { + switch (pair.Key) + { + case CustomerUpdateNames.Email: + Assert.AreEqual(request.Email, pair.Value.Value()); + emailFound = true; + break; + case CustomerUpdateNames.Locale: + Assert.AreEqual(request.Locale, pair.Value.Value()); + break; + case CustomerUpdateNames.Groups: + Assert.IsTrue(Enumerable.SequenceEqual(request.Groups, pair.Value.Values())); + break; + } } + Assert.IsTrue(emailFound); + } + protected void ValidateRequestData(JObject actualData, IDictionary expectedData) { Assert.AreEqual(expectedData.Count, actualData.Count); @@ -132,7 +157,7 @@ protected void ValidateDripCampaignActivateRequest(JObject jsonObject, string ex { var recipientAddressFound = false; - foreach(var pair in jsonObject) + foreach (var pair in jsonObject) { switch (pair.Key) { diff --git a/SendWithUs.Client.Tests/Component/CustomerUpdateRequestConverterTests.cs b/SendWithUs.Client.Tests/Component/CustomerUpdateRequestConverterTests.cs new file mode 100644 index 0000000..4ab2b48 --- /dev/null +++ b/SendWithUs.Client.Tests/Component/CustomerUpdateRequestConverterTests.cs @@ -0,0 +1,74 @@ +// Copyright © 2015 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Component +{ + using System.Collections.Generic; + using System.Linq; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using SendWithUs.Client; + + [TestClass] + public class CustomerUpdateRequestConverterTests : ComponentTestsBase + { + [TestMethod] + public void WriteJson_MinimalCustomerUpdateRequest_Succeeds() + { + var email = TestHelper.GetUniqueId(); + var request = new CustomerUpdateRequest(email); + var writer = BufferedJsonStringWriter.Create(); + var serializer = JsonSerializer.Create(); + var converter = new CustomerUpdateRequestConverter(); + + converter.WriteJson(writer, request, serializer); + var jsonObject = writer.GetBufferAs(); + + Assert.IsNotNull(jsonObject); + this.ValidateCustomerUpdateRequest(request, jsonObject); + } + + [TestMethod] + public void WriteJson_WithData_IncludesAllData() + { + var email = TestHelper.GetUniqueId(); + var data = TestHelper.GetRandomDictionary(); + var dataAsKeyPair = data.Select(d => new KeyValuePair(d.Key, d.Value)); + var request = new CustomerUpdateRequest(email, dataAsKeyPair); + request.Locale = "US"; + request.Groups = new List + { + "Hello", + "World" + }; + + var writer = BufferedJsonStringWriter.Create(); + var serializer = JsonSerializer.Create(); + var converter = new CustomerUpdateRequestConverter(); + + converter.WriteJson(writer, request, serializer); + var jsonObject = writer.GetBufferAs(); + + Assert.IsNotNull(jsonObject); + this.ValidateCustomerUpdateRequest(request, jsonObject); + } + } +} diff --git a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj index e43f365..db2961c 100755 --- a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj +++ b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj @@ -79,6 +79,7 @@ + diff --git a/SendWithUs.Client/Helpers/ValidationFailureMode.cs b/SendWithUs.Client/Helpers/ValidationFailureMode.cs index b053187..761e27d 100755 --- a/SendWithUs.Client/Helpers/ValidationFailureMode.cs +++ b/SendWithUs.Client/Helpers/ValidationFailureMode.cs @@ -27,6 +27,7 @@ public enum ValidationFailureMode MissingRecipientAddress, MissingSenderAddress, MissingCampaignId, - MissingData + MissingData, + MissingCustomerAddress } } diff --git a/SendWithUs.Client/Requests/CustomerUpdateRequest.cs b/SendWithUs.Client/Requests/CustomerUpdateRequest.cs new file mode 100644 index 0000000..20ab803 --- /dev/null +++ b/SendWithUs.Client/Requests/CustomerUpdateRequest.cs @@ -0,0 +1,110 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// Represents the data necessary to make API requests to send email messages. + /// + [JsonConverter(typeof(CustomerUpdateRequestConverter))] + public class CustomerUpdateRequest : ICustomerUpdateRequest + { + #region Constructors + + public CustomerUpdateRequest() + { } + + public CustomerUpdateRequest(string email) : this(email, (IEnumerable>)null) + { } + + public CustomerUpdateRequest(string email, IEnumerable> data) + { + EnsureArgument.NotNullOrEmpty(email, "email"); + + this.Email = email; + this.Data = data; + } + + #endregion + + #region ISendRequest members + + public virtual string Email { get; set; } + + public virtual IEnumerable> Data { get; set; } + + public virtual IEnumerable Groups { get; set; } + + public virtual string Locale { get; set; } + + #endregion + + #region IRequest members + + public string GetUriPath() + { + return "/api/v1/customers"; + } + + public string GetHttpMethod() + { + return "POST"; + } + + public Type GetResponseType() + { + return typeof(SendResponse); + } + + public virtual IRequest Validate() + { + // Customer email is required. + if (String.IsNullOrEmpty(this.Email)) + { + throw new ValidationException(ValidationFailureMode.MissingCustomerAddress); + } + + return this; + } + + public virtual bool IsValid + { + get + { + try + { + this.Validate(); + } + catch (ValidationException) + { + return false; + } + + return true; + } + } + + #endregion + } +} diff --git a/SendWithUs.Client/Requests/CustomerUpdateRequestConverter.cs b/SendWithUs.Client/Requests/CustomerUpdateRequestConverter.cs new file mode 100644 index 0000000..c38c303 --- /dev/null +++ b/SendWithUs.Client/Requests/CustomerUpdateRequestConverter.cs @@ -0,0 +1,72 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using System.Reflection; + using Newtonsoft.Json; + + public class CustomerUpdateRequestConverter : BaseConverter + { + internal static class PropertyNames + { + public const string Email = "email"; + public const string Data = "data"; + public const string Locale = "locale"; + public const string Groups = "groups"; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override bool CanConvert(Type objectType) + { + return typeof(ICustomerUpdateRequest).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotSupportedException(); + } + + protected internal override void WriteJson(JsonWriter writer, object value, SerializerProxy serializer) + { + var request = EnsureArgument.Of(value, "value"); + + writer.WriteStartObject(); + + this.WriteProperty(writer, serializer, PropertyNames.Email, request.Email, false); + this.WriteProperty(writer, serializer, PropertyNames.Locale, request.Locale, true); + this.WriteProperty(writer, serializer, PropertyNames.Data, request.Data, true); + this.WriteProperty(writer, serializer, PropertyNames.Groups, request.Groups, true); + + writer.WriteEndObject(); + } + } +} diff --git a/SendWithUs.Client/Requests/ICustomerUpdateRequest.cs b/SendWithUs.Client/Requests/ICustomerUpdateRequest.cs new file mode 100644 index 0000000..ef75914 --- /dev/null +++ b/SendWithUs.Client/Requests/ICustomerUpdateRequest.cs @@ -0,0 +1,53 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System.Collections.Generic; + + /// + /// Describes the interface of objects used to make API requests to add/update customers. + /// + /// This interface roughly corresponds to the JSON object used with the /customers route + /// in the REST API, with some properties flattened or renamed. + public interface ICustomerUpdateRequest : IRequest + { + /// + /// Gets the email address of the customer. + /// + string Email { get; } + + /// + /// Gets the locale of the customer. + /// + string Locale { get; } + + /// + /// Gets the data to use for creating the customer. + /// + /// Corresponds to the "data" property in the SendWithUs API. + IEnumerable> Data { get; } + + /// + /// Gets the groups that this customer should belong to + /// + IEnumerable Groups { get; } + } +} diff --git a/SendWithUs.Client/Responses/CustomerUpdateResponse.cs b/SendWithUs.Client/Responses/CustomerUpdateResponse.cs new file mode 100644 index 0000000..6497bfe --- /dev/null +++ b/SendWithUs.Client/Responses/CustomerUpdateResponse.cs @@ -0,0 +1,56 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using Newtonsoft.Json.Linq; + + public class CustomerUpdateResponse : BaseObjectResponse, ICustomerUpdateResponse + { + internal static class PropertyNames + { + public const string Success = "success"; + public const string Status = "status"; + } + + #region ISendResponse Members + + public virtual bool Success { get; set; } + + public virtual string Status { get; set; } + + #endregion + + #region Base class overrides + + protected internal override void Populate(JObject json) + { + if (json == null) + { + return; + } + + this.Success = json.Value(PropertyNames.Success); + this.Status = json.Value(PropertyNames.Status); + } + + #endregion + } +} diff --git a/SendWithUs.Client/Responses/ICustomerUpdateResponse.cs b/SendWithUs.Client/Responses/ICustomerUpdateResponse.cs new file mode 100644 index 0000000..226e3c4 --- /dev/null +++ b/SendWithUs.Client/Responses/ICustomerUpdateResponse.cs @@ -0,0 +1,29 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + public interface ICustomerUpdateResponse : IResponse + { + bool Success { get; } + + string Status { get; } + } +} diff --git a/SendWithUs.Client/SendWithUs.Client.csproj b/SendWithUs.Client/SendWithUs.Client.csproj index 55039be..c4b42fb 100755 --- a/SendWithUs.Client/SendWithUs.Client.csproj +++ b/SendWithUs.Client/SendWithUs.Client.csproj @@ -47,6 +47,9 @@ + + + @@ -66,10 +69,12 @@ + + From ee1603c45b0cdc177eda86c5e8d6590cb10cd48e Mon Sep 17 00:00:00 2001 From: Kenny Kaplan Date: Thu, 8 Sep 2016 15:17:50 -0600 Subject: [PATCH 6/8] Add CustomerUpdateRequest tests --- .../EndToEnd/BatchAsyncTests.cs | 32 +++ .../EndToEnd/CustomerUpdateAsyncTests.cs | 65 +++++++ .../EndToEnd/Data/CustomerUpdateRequest.xml | 12 ++ .../EndToEnd/Data/CustomerUpdateRequest2.xml | 12 ++ SendWithUs.Client.Tests/EndToEnd/TestData.cs | 5 + .../SendWithUs.Client.Tests.csproj | 10 + .../CustomerUpdateRequestConverterTests.cs | 184 ++++++++++++++++++ .../Unit/CustomerUpdateRequestTests.cs | 103 ++++++++++ .../Unit/CustomerUpdateResponseTests.cs | 70 +++++++ SendWithUs.Client.sln | 6 +- .../Requests/CustomerUpdateRequest.cs | 2 +- 11 files changed, 497 insertions(+), 4 deletions(-) create mode 100644 SendWithUs.Client.Tests/EndToEnd/CustomerUpdateAsyncTests.cs create mode 100644 SendWithUs.Client.Tests/EndToEnd/Data/CustomerUpdateRequest.xml create mode 100644 SendWithUs.Client.Tests/EndToEnd/Data/CustomerUpdateRequest2.xml create mode 100644 SendWithUs.Client.Tests/Unit/CustomerUpdateRequestConverterTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/CustomerUpdateRequestTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/CustomerUpdateResponseTests.cs diff --git a/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs b/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs index 5505e4f..f69d259 100755 --- a/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs +++ b/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs @@ -18,6 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace SendWithUs.Client.Tests.EndToEnd { using System.Collections.Generic; @@ -90,5 +91,36 @@ public void BatchAsync_SendMultipleDifferentTypes_Succeeds() Assert.AreEqual("OK", sendResponse.Status, true); Assert.AreEqual(true, sendResponse.Success); } + + [TestMethod] + public void BatchAsync_SendMultipleCustomerWithData_Succeeds() + { + // Item 1 + var testData = new TestData("EndToEnd/Data/CustomerUpdateRequest.xml"); + var request1 = new CustomerUpdateRequest(testData.Email, testData.Data); + + // Item 2 + testData = new TestData("EndToEnd/Data/CustomerUpdateRequest2.xml"); + var request2 = new CustomerUpdateRequest(testData.Email, testData.Data); + + var client = new SendWithUsClient(testData.ApiKey); + + var batchResponse = client.BatchAsync(new List { request1, request2 }).Result; + var batchItems = batchResponse.Items.ToList(); + + Assert.AreEqual(HttpStatusCode.OK, batchResponse.StatusCode); + Assert.AreEqual(2, batchItems.Count()); + + var updateCustomerResponse1 = batchItems.First() as ICustomerUpdateResponse; + Assert.AreEqual(HttpStatusCode.OK, updateCustomerResponse1.StatusCode); + Assert.AreEqual("OK", updateCustomerResponse1.Status, true); + Assert.AreEqual(true, updateCustomerResponse1.Success); + batchItems.RemoveAt(0); + + var updateCustomerResponse2 = batchItems.First() as ICustomerUpdateResponse; + Assert.AreEqual(HttpStatusCode.OK, updateCustomerResponse2.StatusCode); + Assert.AreEqual("OK", updateCustomerResponse2.Status, true); + Assert.AreEqual(true, updateCustomerResponse2.Success); + } } } diff --git a/SendWithUs.Client.Tests/EndToEnd/CustomerUpdateAsyncTests.cs b/SendWithUs.Client.Tests/EndToEnd/CustomerUpdateAsyncTests.cs new file mode 100644 index 0000000..a327ecb --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/CustomerUpdateAsyncTests.cs @@ -0,0 +1,65 @@ +// Copyright © 2015 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.EndToEnd +{ + using System.Net; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using SendWithUs.Client; + + [TestClass] + public class CustomerUpdateAsyncTests + { + [TestMethod] + public void CustomerUpdateAsync_MinimalRequest_Succeeds() + { + // Arrange + var testData = new TestData("EndToEnd/Data/CustomerUpdateRequest.xml"); + var request = new CustomerUpdateRequest(testData.Email); + var client = new SendWithUsClient(testData.ApiKey); + + // Act + var response = client.SingleAsync(request).Result; + + // Assert + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + Assert.AreEqual("OK", response.Status, true); + Assert.AreEqual(true, response.Success); + } + + [TestMethod] + public void CustomerUpdateAsync_WithData_Succeeds() + { + // Arrange + var testData = new TestData("EndToEnd/Data/CustomerUpdateRequest.xml"); + var subject = "CustomerUpdateAsync_WithData " + TestHelper.GetUniqueId(); + var request = new CustomerUpdateRequest(testData.Email, testData.Data); + var client = new SendWithUsClient(testData.ApiKey); + + // Act + var response = client.SingleAsync(request).Result; + + // Assert + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + Assert.AreEqual("OK", response.Status, true); + Assert.AreEqual(true, response.Success); + } + } +} diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/CustomerUpdateRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/CustomerUpdateRequest.xml new file mode 100644 index 0000000..a92d76c --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/Data/CustomerUpdateRequest.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/CustomerUpdateRequest2.xml b/SendWithUs.Client.Tests/EndToEnd/Data/CustomerUpdateRequest2.xml new file mode 100644 index 0000000..a92d76c --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/Data/CustomerUpdateRequest2.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/SendWithUs.Client.Tests/EndToEnd/TestData.cs b/SendWithUs.Client.Tests/EndToEnd/TestData.cs index af813d6..fdeabd2 100755 --- a/SendWithUs.Client.Tests/EndToEnd/TestData.cs +++ b/SendWithUs.Client.Tests/EndToEnd/TestData.cs @@ -41,6 +41,11 @@ public string CampaignId get { return this.GetString("CampaignId"); } } + public string Email + { + get { return this.GetString("Email"); } + } + public string SenderAddress { get { return this.GetString("SenderAddress"); } diff --git a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj index db2961c..78ca5d6 100755 --- a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj +++ b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj @@ -80,6 +80,7 @@ + @@ -98,6 +99,9 @@ + + + @@ -139,6 +143,9 @@ + + Always + Always @@ -148,6 +155,9 @@ Always + + Always + diff --git a/SendWithUs.Client.Tests/Unit/CustomerUpdateRequestConverterTests.cs b/SendWithUs.Client.Tests/Unit/CustomerUpdateRequestConverterTests.cs new file mode 100644 index 0000000..02c8e68 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/CustomerUpdateRequestConverterTests.cs @@ -0,0 +1,184 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json; + using SendWithUs.Client; + using Names = CustomerUpdateRequestConverter.PropertyNames; + + [TestClass] + public class CustomerUpdateRequestConverterTests + { + public class NonCustomerUpdateRequest { } + + public interface ICustomerUpdateRequestSubtype : ICustomerUpdateRequest { } + + [TestMethod] + public void CanRead_Getter_ReturnsFalse() + { + // Arrange + var converter = new CustomerUpdateRequestConverter(); + + // Act + var canRead = converter.CanRead; + + // Assert + Assert.IsFalse(canRead); + } + + [TestMethod] + public void CanWrite_Getter_ReturnsTrue() + { + // Arrange + var converter = new CustomerUpdateRequestConverter(); + + // Act + var canWrite = converter.CanWrite; + + // Assert + Assert.IsTrue(canWrite); + } + + [TestMethod] + public void CanConvert_ICustomerUpdateRequestType_ReturnsTrue() + { + // Arrange + var type = typeof(ICustomerUpdateRequest); + var converter = new CustomerUpdateRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_ICustomerUpdateRequestSubtype_ReturnsTrue() + { + // Arrange + var type = typeof(ICustomerUpdateRequestSubtype); + var converter = new CustomerUpdateRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_NonICustomerUpdateRequestType_ReturnsFalse() + { + // Arrange + var type = typeof(NonCustomerUpdateRequest); + var converter = new CustomerUpdateRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsFalse(canConvert); + } + + [TestMethod] + public void ReadJson_Always_Throws() + { + // Arrange + var reader = new Mock().Object; + var serializer = new Mock().Object; + var request = new Mock().Object; + var converter = new CustomerUpdateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.ReadJson(reader, request.GetType(), request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(NotSupportedException)); + } + + [TestMethod] + public void WriteJson_NullWriter_Throws() + { + // Arrange + var serializer = new Mock(null).Object; + var request = new Mock().Object; + var converter = new CustomerUpdateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(null, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(NullReferenceException)); + } + + [TestMethod] + public void WriteJson_NullSerializer_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = null as SerializerProxy; + var request = new Mock().Object; + var converter = new CustomerUpdateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(NullReferenceException)); + } + + [TestMethod] + public void WriteJson_NonICustomerUpdateRequestValue_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = new Mock(null).Object; + var value = new NonCustomerUpdateRequest(); + var converter = new CustomerUpdateRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, value, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentException)); + } + + [TestMethod] + public void WriteJson_Normally_WritesObject() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new CustomerUpdateRequestConverter(); + + // Act + converter.WriteJson(writer.Object, request.Object, serializer.Object); + + // Assert + writer.Verify(w => w.WriteStartObject(), Times.AtLeastOnce); + writer.Verify(w => w.WriteEndObject(), Times.AtLeastOnce); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/CustomerUpdateRequestTests.cs b/SendWithUs.Client.Tests/Unit/CustomerUpdateRequestTests.cs new file mode 100644 index 0000000..a118d53 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/CustomerUpdateRequestTests.cs @@ -0,0 +1,103 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class CustomerUpdateRequestTests + { + [TestMethod] + public void IsValid_Getter_CallsValidate() + { + // Arrange + var request = new Mock() { CallBase = true }; + + // Act + var isValid = request.Object.IsValid; + + // Assert + request.Verify(r => r.Validate(), Times.Once); + } + + [TestMethod] + public void GetResponseType_Always_ReturnsCustomerUpdateResponseType() + { + // Arrange + var request = new CustomerUpdateRequest(); + + // Act + var responseType = request.GetResponseType(); + + // Assert + Assert.AreEqual(typeof(CustomerUpdateResponse), responseType); + } + + [TestMethod] + public void Validate_Always_ReturnsSelf() + { + // Arrange + var email = TestHelper.GetUniqueId(); + var request = new CustomerUpdateRequest(email); + + // Act + var self = request.Validate(); + + // Assert + Assert.AreSame(request, self); + } + + [TestMethod] + public void Validate_Normally_ReturnsThis() + { + // Arrange + var email = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.Email).Returns(email); + + // Act + var self = request.Object.Validate(); + + // Assert + Assert.AreSame(request.Object, self); + } + + [TestMethod] + public void ValidateBool_EmptyEmail_Throws() + { + // Arrange + var email = String.Empty; + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.Email).Returns(email); + + // Act + var exception = TestHelper.CaptureException(() => request.Object.Validate()); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ValidationException)); + var invalid = exception as ValidationException; + Assert.AreEqual(ValidationFailureMode.MissingCustomerAddress, invalid.FailureMode); + } + + } +} diff --git a/SendWithUs.Client.Tests/Unit/CustomerUpdateResponseTests.cs b/SendWithUs.Client.Tests/Unit/CustomerUpdateResponseTests.cs new file mode 100644 index 0000000..cee648d --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/CustomerUpdateResponseTests.cs @@ -0,0 +1,70 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json.Linq; + using Names = SendWithUs.Client.CustomerUpdateResponse.PropertyNames; + + [TestClass] + public class CustomerUpdateResponseTests + { + [TestMethod] + public void Populate_NullJson_DoesNotSetProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var json = null as JObject; + + // Act + response.Object.Populate(json); + + // Assert + response.VerifySet(r => r.Success = It.IsAny(), Times.Never); + response.VerifySet(r => r.Status = It.IsAny(), Times.Never); + } + + [TestMethod] + public void Populate_ValidJson_SetsProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var success = true; + var status = TestHelper.GetUniqueId(); + var json = new Mock(); + var details = new Mock(); + + json.Setup(j => j.Value(Names.Success)).Returns(success); + json.Setup(j => j.Value(Names.Status)).Returns(status); + + // Act + response.Object.Populate(json.Object); + + // Assert + response.VerifySet(r => r.Success = success, Times.Once); + response.VerifySet(r => r.Status = status, Times.Once); + } + } +} diff --git a/SendWithUs.Client.sln b/SendWithUs.Client.sln index cfa0c73..6bc355e 100755 --- a/SendWithUs.Client.sln +++ b/SendWithUs.Client.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.24720.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SendWithUs.Client", "SendWithUs.Client\SendWithUs.Client.csproj", "{012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}" EndProject @@ -26,8 +26,8 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Debug|Any CPU.ActiveCfg = Release|Any CPU - {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Debug|Any CPU.Build.0 = Release|Any CPU + {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Debug|Any CPU.Build.0 = Debug|Any CPU {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Release|Any CPU.ActiveCfg = Release|Any CPU {012B2A9E-8A75-4D6F-8051-EEFBE9F6BAD1}.Release|Any CPU.Build.0 = Release|Any CPU {C3059E9E-CE97-4E9B-B778-D78EFD1E448A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU diff --git a/SendWithUs.Client/Requests/CustomerUpdateRequest.cs b/SendWithUs.Client/Requests/CustomerUpdateRequest.cs index 20ab803..a42d3e2 100644 --- a/SendWithUs.Client/Requests/CustomerUpdateRequest.cs +++ b/SendWithUs.Client/Requests/CustomerUpdateRequest.cs @@ -74,7 +74,7 @@ public string GetHttpMethod() public Type GetResponseType() { - return typeof(SendResponse); + return typeof(CustomerUpdateResponse); } public virtual IRequest Validate() From 40fcba335d6600172ee62b61876eceb626e8c4c5 Mon Sep 17 00:00:00 2001 From: Kenny Kaplan Date: Thu, 8 Sep 2016 15:35:56 -0600 Subject: [PATCH 7/8] Add CustomerUpdate group tests --- .../EndToEnd/BatchAsyncTests.cs | 7 +++++-- .../EndToEnd/CustomerUpdateAsyncTests.cs | 19 +++++++++++++++++++ SendWithUs.Client.Tests/EndToEnd/TestData.cs | 5 +++++ SendWithUs.Client.Tests/TestHelper.cs | 6 ++++++ 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs b/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs index f69d259..3822a64 100755 --- a/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs +++ b/SendWithUs.Client.Tests/EndToEnd/BatchAsyncTests.cs @@ -93,19 +93,22 @@ public void BatchAsync_SendMultipleDifferentTypes_Succeeds() } [TestMethod] - public void BatchAsync_SendMultipleCustomerWithData_Succeeds() + public void BatchAsync_SendMultipleCustomerWithGroups_Succeeds() { // Item 1 var testData = new TestData("EndToEnd/Data/CustomerUpdateRequest.xml"); var request1 = new CustomerUpdateRequest(testData.Email, testData.Data); + request1.Groups = testData.Groups; // Item 2 testData = new TestData("EndToEnd/Data/CustomerUpdateRequest2.xml"); var request2 = new CustomerUpdateRequest(testData.Email, testData.Data); + request2.Groups = testData.Groups; var client = new SendWithUsClient(testData.ApiKey); - var batchResponse = client.BatchAsync(new List { request1, request2 }).Result; + var batchList = new List { request1, request2 }; + var batchResponse = client.BatchAsync(batchList).Result; var batchItems = batchResponse.Items.ToList(); Assert.AreEqual(HttpStatusCode.OK, batchResponse.StatusCode); diff --git a/SendWithUs.Client.Tests/EndToEnd/CustomerUpdateAsyncTests.cs b/SendWithUs.Client.Tests/EndToEnd/CustomerUpdateAsyncTests.cs index a327ecb..88e0813 100644 --- a/SendWithUs.Client.Tests/EndToEnd/CustomerUpdateAsyncTests.cs +++ b/SendWithUs.Client.Tests/EndToEnd/CustomerUpdateAsyncTests.cs @@ -61,5 +61,24 @@ public void CustomerUpdateAsync_WithData_Succeeds() Assert.AreEqual("OK", response.Status, true); Assert.AreEqual(true, response.Success); } + + [TestMethod] + public void CustomerUpdateAsync_WithGroups_Succeeds() + { + // Arrange + var testData = new TestData("EndToEnd/Data/CustomerUpdateRequest.xml"); + var subject = "CustomerUpdateAsync_WithData " + TestHelper.GetUniqueId(); + var request = new CustomerUpdateRequest(testData.Email); + request.Groups = testData.Groups; + var client = new SendWithUsClient(testData.ApiKey); + + // Act + var response = client.SingleAsync(request).Result; + + // Assert + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + Assert.AreEqual("OK", response.Status, true); + Assert.AreEqual(true, response.Success); + } } } diff --git a/SendWithUs.Client.Tests/EndToEnd/TestData.cs b/SendWithUs.Client.Tests/EndToEnd/TestData.cs index fdeabd2..969f220 100755 --- a/SendWithUs.Client.Tests/EndToEnd/TestData.cs +++ b/SendWithUs.Client.Tests/EndToEnd/TestData.cs @@ -90,6 +90,11 @@ public IDictionary Data } } + public IEnumerable Groups + { + get { return new List { "grp_PUTGROUPIDHERE" }; } + } + public IEnumerable Tags { get { return null; } diff --git a/SendWithUs.Client.Tests/TestHelper.cs b/SendWithUs.Client.Tests/TestHelper.cs index 5321214..54a4435 100755 --- a/SendWithUs.Client.Tests/TestHelper.cs +++ b/SendWithUs.Client.Tests/TestHelper.cs @@ -93,5 +93,11 @@ public static IDictionary GetRandomDictionary() var itemCount = GetRandomInteger(1, 10); return Generate(itemCount, i => GetUniqueId()).ToDictionary(k => k, k => GetUniqueId()); } + + public static IEnumerable GetRandomStringList() + { + var itemCount = GetRandomInteger(1, 10); + return Generate(itemCount, i => GetUniqueId()); + } } } From aace30111c9c1533fb778b6593bd802595e828ef Mon Sep 17 00:00:00 2001 From: Kenny Kaplan Date: Thu, 12 Jan 2017 15:26:37 -0700 Subject: [PATCH 8/8] Add Customer Delete request and response --- .../Component/ComponentTestsBase.cs | 19 ++ .../CustomerDeleteRequestConverterTests.cs | 49 +++++ .../EndToEnd/CustomerDeleteAsyncTests.cs | 48 +++++ .../EndToEnd/Data/CustomerDeleteRequest.xml | 5 + .../SendWithUs.Client.Tests.csproj | 8 + .../CustomerDeleteRequestConverterTests.cs | 184 ++++++++++++++++++ .../Unit/CustomerDeleteRequestTests.cs | 103 ++++++++++ .../Unit/CustomerDeleteResponseTests.cs | 70 +++++++ .../Requests/CustomerDeleteRequest.cs | 100 ++++++++++ .../CustomerDeleteRequestConverter.cs | 66 +++++++ .../Requests/ICustomerDeleteRequest.cs | 37 ++++ .../Responses/CustomerDeleteResponse.cs | 56 ++++++ .../Responses/ICustomerDeleteResponse.cs | 29 +++ SendWithUs.Client/SendWithUs.Client.csproj | 5 + 14 files changed, 779 insertions(+) create mode 100644 SendWithUs.Client.Tests/Component/CustomerDeleteRequestConverterTests.cs create mode 100644 SendWithUs.Client.Tests/EndToEnd/CustomerDeleteAsyncTests.cs create mode 100644 SendWithUs.Client.Tests/EndToEnd/Data/CustomerDeleteRequest.xml create mode 100644 SendWithUs.Client.Tests/Unit/CustomerDeleteRequestConverterTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/CustomerDeleteRequestTests.cs create mode 100644 SendWithUs.Client.Tests/Unit/CustomerDeleteResponseTests.cs create mode 100644 SendWithUs.Client/Requests/CustomerDeleteRequest.cs create mode 100644 SendWithUs.Client/Requests/CustomerDeleteRequestConverter.cs create mode 100644 SendWithUs.Client/Requests/ICustomerDeleteRequest.cs create mode 100644 SendWithUs.Client/Responses/CustomerDeleteResponse.cs create mode 100644 SendWithUs.Client/Responses/ICustomerDeleteResponse.cs diff --git a/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs b/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs index 8095174..758ae7c 100755 --- a/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs +++ b/SendWithUs.Client.Tests/Component/ComponentTestsBase.cs @@ -27,6 +27,7 @@ namespace SendWithUs.Client.Tests.Component using RenderNames = SendWithUs.Client.RenderRequestConverter.PropertyNames; using SendNames = SendWithUs.Client.SendRequestConverter.PropertyNames; using CustomerUpdateNames = SendWithUs.Client.CustomerUpdateRequestConverter.PropertyNames; + using CustomerDeleteNames = SendWithUs.Client.CustomerDeleteRequestConverter.PropertyNames; using System.Linq; public abstract class ComponentTestsBase { @@ -142,6 +143,24 @@ protected void ValidateCustomerUpdateRequest(CustomerUpdateRequest request, JObj Assert.IsTrue(emailFound); } + protected void ValidateCustomerDeleteRequest(CustomerDeleteRequest request, JObject jsonObject) + { + var emailFound = false; + + foreach (var pair in jsonObject) + { + switch (pair.Key) + { + case CustomerDeleteNames.Email: + Assert.AreEqual(request.Email, pair.Value.Value()); + emailFound = true; + break; + } + } + + Assert.IsTrue(emailFound); + } + protected void ValidateRequestData(JObject actualData, IDictionary expectedData) { Assert.AreEqual(expectedData.Count, actualData.Count); diff --git a/SendWithUs.Client.Tests/Component/CustomerDeleteRequestConverterTests.cs b/SendWithUs.Client.Tests/Component/CustomerDeleteRequestConverterTests.cs new file mode 100644 index 0000000..b331d33 --- /dev/null +++ b/SendWithUs.Client.Tests/Component/CustomerDeleteRequestConverterTests.cs @@ -0,0 +1,49 @@ +// Copyright © 2015 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Component +{ + using System.Collections.Generic; + using System.Linq; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using SendWithUs.Client; + + [TestClass] + public class CustomerDeleteRequestConverterTests : ComponentTestsBase + { + [TestMethod] + public void WriteJson_MinimalCustomerDeleteRequest_Succeeds() + { + var email = TestHelper.GetUniqueId(); + var request = new CustomerDeleteRequest(email); + var writer = BufferedJsonStringWriter.Create(); + var serializer = JsonSerializer.Create(); + var converter = new CustomerDeleteRequestConverter(); + + converter.WriteJson(writer, request, serializer); + var jsonObject = writer.GetBufferAs(); + + Assert.IsNotNull(jsonObject); + this.ValidateCustomerDeleteRequest(request, jsonObject); + } + } +} diff --git a/SendWithUs.Client.Tests/EndToEnd/CustomerDeleteAsyncTests.cs b/SendWithUs.Client.Tests/EndToEnd/CustomerDeleteAsyncTests.cs new file mode 100644 index 0000000..adc583c --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/CustomerDeleteAsyncTests.cs @@ -0,0 +1,48 @@ +// Copyright © 2015 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.EndToEnd +{ + using System.Net; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using SendWithUs.Client; + using System.Threading.Tasks; + + [TestClass] + public class CustomerDeleteAsyncTests + { + [TestMethod] + public async Task CustomerDeleteAsync_MinimalRequest_Succeeds() + { + // Arrange + var testData = new TestData("EndToEnd/Data/CustomerDeleteRequest.xml"); + var request = new CustomerDeleteRequest(testData.Email); + var client = new SendWithUsClient(testData.ApiKey); + + // Act + var response = await client.SingleAsync(request); + + // Assert + Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); + Assert.AreEqual("OK", response.Status, true); + Assert.AreEqual(true, response.Success); + } + } +} diff --git a/SendWithUs.Client.Tests/EndToEnd/Data/CustomerDeleteRequest.xml b/SendWithUs.Client.Tests/EndToEnd/Data/CustomerDeleteRequest.xml new file mode 100644 index 0000000..fb315d0 --- /dev/null +++ b/SendWithUs.Client.Tests/EndToEnd/Data/CustomerDeleteRequest.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj index 78ca5d6..1e25c0c 100755 --- a/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj +++ b/SendWithUs.Client.Tests/SendWithUs.Client.Tests.csproj @@ -78,8 +78,10 @@ + + @@ -99,8 +101,11 @@ + + + @@ -146,6 +151,9 @@ Always + + Always + Always diff --git a/SendWithUs.Client.Tests/Unit/CustomerDeleteRequestConverterTests.cs b/SendWithUs.Client.Tests/Unit/CustomerDeleteRequestConverterTests.cs new file mode 100644 index 0000000..f01b8a4 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/CustomerDeleteRequestConverterTests.cs @@ -0,0 +1,184 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json; + using SendWithUs.Client; + using Names = CustomerDeleteRequestConverter.PropertyNames; + + [TestClass] + public class CustomerDeleteRequestConverterTests + { + public class NonCustomerDeleteRequest { } + + public interface ICustomerDeleteRequestSubtype : ICustomerDeleteRequest { } + + [TestMethod] + public void CanRead_Getter_ReturnsFalse() + { + // Arrange + var converter = new CustomerDeleteRequestConverter(); + + // Act + var canRead = converter.CanRead; + + // Assert + Assert.IsFalse(canRead); + } + + [TestMethod] + public void CanWrite_Getter_ReturnsTrue() + { + // Arrange + var converter = new CustomerDeleteRequestConverter(); + + // Act + var canWrite = converter.CanWrite; + + // Assert + Assert.IsTrue(canWrite); + } + + [TestMethod] + public void CanConvert_ICustomerDeleteRequestType_ReturnsTrue() + { + // Arrange + var type = typeof(ICustomerDeleteRequest); + var converter = new CustomerDeleteRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_ICustomerDeleteRequestSubtype_ReturnsTrue() + { + // Arrange + var type = typeof(ICustomerDeleteRequestSubtype); + var converter = new CustomerDeleteRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsTrue(canConvert); + } + + [TestMethod] + public void CanConvert_NonICustomerDeleteRequestType_ReturnsFalse() + { + // Arrange + var type = typeof(NonCustomerDeleteRequest); + var converter = new CustomerDeleteRequestConverter(); + + // Act + var canConvert = converter.CanConvert(type); + + // Assert + Assert.IsFalse(canConvert); + } + + [TestMethod] + public void ReadJson_Always_Throws() + { + // Arrange + var reader = new Mock().Object; + var serializer = new Mock().Object; + var request = new Mock().Object; + var converter = new CustomerDeleteRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.ReadJson(reader, request.GetType(), request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(NotSupportedException)); + } + + [TestMethod] + public void WriteJson_NullWriter_Throws() + { + // Arrange + var serializer = new Mock(null).Object; + var request = new Mock().Object; + var converter = new CustomerDeleteRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(null, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(NullReferenceException)); + } + + [TestMethod] + public void WriteJson_NullSerializer_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = null as SerializerProxy; + var request = new Mock().Object; + var converter = new CustomerDeleteRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, request, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(NullReferenceException)); + } + + [TestMethod] + public void WriteJson_NonICustomerDeleteRequestValue_Throws() + { + // Arrange + var writer = new Mock().Object; + var serializer = new Mock(null).Object; + var value = new NonCustomerDeleteRequest(); + var converter = new CustomerDeleteRequestConverter(); + + // Act + var exception = TestHelper.CaptureException(() => converter.WriteJson(writer, value, serializer)); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ArgumentException)); + } + + [TestMethod] + public void WriteJson_Normally_WritesObject() + { + // Arrange + var writer = new Mock(); + var serializer = new Mock(null); + var request = new Mock(); + var converter = new CustomerDeleteRequestConverter(); + + // Act + converter.WriteJson(writer.Object, request.Object, serializer.Object); + + // Assert + writer.Verify(w => w.WriteStartObject(), Times.AtLeastOnce); + writer.Verify(w => w.WriteEndObject(), Times.AtLeastOnce); + } + } +} diff --git a/SendWithUs.Client.Tests/Unit/CustomerDeleteRequestTests.cs b/SendWithUs.Client.Tests/Unit/CustomerDeleteRequestTests.cs new file mode 100644 index 0000000..8a44475 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/CustomerDeleteRequestTests.cs @@ -0,0 +1,103 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + + [TestClass] + public class CustomerDeleteRequestTests + { + [TestMethod] + public void IsValid_Getter_CallsValidate() + { + // Arrange + var request = new Mock() { CallBase = true }; + + // Act + var isValid = request.Object.IsValid; + + // Assert + request.Verify(r => r.Validate(), Times.Once); + } + + [TestMethod] + public void GetResponseType_Always_ReturnsCustomerDeleteResponseType() + { + // Arrange + var request = new CustomerDeleteRequest(); + + // Act + var responseType = request.GetResponseType(); + + // Assert + Assert.AreEqual(typeof(CustomerDeleteResponse), responseType); + } + + [TestMethod] + public void Validate_Always_ReturnsSelf() + { + // Arrange + var email = TestHelper.GetUniqueId(); + var request = new CustomerDeleteRequest(email); + + // Act + var self = request.Validate(); + + // Assert + Assert.AreSame(request, self); + } + + [TestMethod] + public void Validate_Normally_ReturnsThis() + { + // Arrange + var email = TestHelper.GetUniqueId(); + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.Email).Returns(email); + + // Act + var self = request.Object.Validate(); + + // Assert + Assert.AreSame(request.Object, self); + } + + [TestMethod] + public void ValidateBool_EmptyEmail_Throws() + { + // Arrange + var email = String.Empty; + var request = new Mock() { CallBase = true }; + + request.SetupGet(r => r.Email).Returns(email); + + // Act + var exception = TestHelper.CaptureException(() => request.Object.Validate()); + + // Assert + Assert.IsInstanceOfType(exception, typeof(ValidationException)); + var invalid = exception as ValidationException; + Assert.AreEqual(ValidationFailureMode.MissingCustomerAddress, invalid.FailureMode); + } + + } +} diff --git a/SendWithUs.Client.Tests/Unit/CustomerDeleteResponseTests.cs b/SendWithUs.Client.Tests/Unit/CustomerDeleteResponseTests.cs new file mode 100644 index 0000000..1c938e4 --- /dev/null +++ b/SendWithUs.Client.Tests/Unit/CustomerDeleteResponseTests.cs @@ -0,0 +1,70 @@ +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client.Tests.Unit +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Newtonsoft.Json.Linq; + using Names = SendWithUs.Client.CustomerDeleteResponse.PropertyNames; + + [TestClass] + public class CustomerDeleteResponseTests + { + [TestMethod] + public void Populate_NullJson_DoesNotSetProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var json = null as JObject; + + // Act + response.Object.Populate(json); + + // Assert + response.VerifySet(r => r.Success = It.IsAny(), Times.Never); + response.VerifySet(r => r.Status = It.IsAny(), Times.Never); + } + + [TestMethod] + public void Populate_ValidJson_SetsProperties() + { + // Arrange + var response = new Mock() { CallBase = true }; + var success = true; + var status = TestHelper.GetUniqueId(); + var json = new Mock(); + var details = new Mock(); + + json.Setup(j => j.Value(Names.Success)).Returns(success); + json.Setup(j => j.Value(Names.Status)).Returns(status); + + // Act + response.Object.Populate(json.Object); + + // Assert + response.VerifySet(r => r.Success = success, Times.Once); + response.VerifySet(r => r.Status = status, Times.Once); + } + } +} diff --git a/SendWithUs.Client/Requests/CustomerDeleteRequest.cs b/SendWithUs.Client/Requests/CustomerDeleteRequest.cs new file mode 100644 index 0000000..8a8e72a --- /dev/null +++ b/SendWithUs.Client/Requests/CustomerDeleteRequest.cs @@ -0,0 +1,100 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// Represents the data necessary to make API requests to delete a customer. + /// + [JsonConverter(typeof(CustomerDeleteRequestConverter))] + public class CustomerDeleteRequest : ICustomerDeleteRequest + { + #region Constructors + + public CustomerDeleteRequest() + { } + + public CustomerDeleteRequest(string email) + { + EnsureArgument.NotNullOrEmpty(email, "email"); + + this.Email = email; + } + + #endregion + + #region ISendRequest members + + public virtual string Email { get; set; } + + #endregion + + #region IRequest members + + public string GetUriPath() + { + return string.Format("/api/v1/customers/{0}", this.Email); + } + + public string GetHttpMethod() + { + return "DELETE"; + } + + public Type GetResponseType() + { + return typeof(CustomerDeleteResponse); + } + + public virtual IRequest Validate() + { + // Customer email is required. + if (String.IsNullOrEmpty(this.Email)) + { + throw new ValidationException(ValidationFailureMode.MissingCustomerAddress); + } + + return this; + } + + public virtual bool IsValid + { + get + { + try + { + this.Validate(); + } + catch (ValidationException) + { + return false; + } + + return true; + } + } + + #endregion + } +} diff --git a/SendWithUs.Client/Requests/CustomerDeleteRequestConverter.cs b/SendWithUs.Client/Requests/CustomerDeleteRequestConverter.cs new file mode 100644 index 0000000..971621d --- /dev/null +++ b/SendWithUs.Client/Requests/CustomerDeleteRequestConverter.cs @@ -0,0 +1,66 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System; + using System.Collections.Generic; + using System.Reflection; + using Newtonsoft.Json; + + public class CustomerDeleteRequestConverter : BaseConverter + { + internal static class PropertyNames + { + public const string Email = "email"; + } + + public override bool CanRead + { + get { return false; } + } + + public override bool CanWrite + { + get { return true; } + } + + public override bool CanConvert(Type objectType) + { + return typeof(ICustomerDeleteRequest).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + throw new NotSupportedException(); + } + + protected internal override void WriteJson(JsonWriter writer, object value, SerializerProxy serializer) + { + var request = EnsureArgument.Of(value, "value"); + + writer.WriteStartObject(); + + this.WriteProperty(writer, serializer, PropertyNames.Email, request.Email, false); + + writer.WriteEndObject(); + } + } +} diff --git a/SendWithUs.Client/Requests/ICustomerDeleteRequest.cs b/SendWithUs.Client/Requests/ICustomerDeleteRequest.cs new file mode 100644 index 0000000..cffb689 --- /dev/null +++ b/SendWithUs.Client/Requests/ICustomerDeleteRequest.cs @@ -0,0 +1,37 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using System.Collections.Generic; + + /// + /// Describes the interface of objects used to make API requests to add/update customers. + /// + /// This interface roughly corresponds to the JSON object used with the /customers route + /// in the REST API, with some properties flattened or renamed. + public interface ICustomerDeleteRequest : IRequest + { + /// + /// Gets the email address of the customer. + /// + string Email { get; } + } +} diff --git a/SendWithUs.Client/Responses/CustomerDeleteResponse.cs b/SendWithUs.Client/Responses/CustomerDeleteResponse.cs new file mode 100644 index 0000000..2b560da --- /dev/null +++ b/SendWithUs.Client/Responses/CustomerDeleteResponse.cs @@ -0,0 +1,56 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + using Newtonsoft.Json.Linq; + + public class CustomerDeleteResponse : BaseObjectResponse, ICustomerDeleteResponse + { + internal static class PropertyNames + { + public const string Success = "success"; + public const string Status = "status"; + } + + #region ISendResponse Members + + public virtual bool Success { get; set; } + + public virtual string Status { get; set; } + + #endregion + + #region Base class overrides + + protected internal override void Populate(JObject json) + { + if (json == null) + { + return; + } + + this.Success = json.Value(PropertyNames.Success); + this.Status = json.Value(PropertyNames.Status); + } + + #endregion + } +} diff --git a/SendWithUs.Client/Responses/ICustomerDeleteResponse.cs b/SendWithUs.Client/Responses/ICustomerDeleteResponse.cs new file mode 100644 index 0000000..2dc23b3 --- /dev/null +++ b/SendWithUs.Client/Responses/ICustomerDeleteResponse.cs @@ -0,0 +1,29 @@ +// Copyright © 2014 Mimeo, Inc. + +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: + +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. + +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +namespace SendWithUs.Client +{ + public interface ICustomerDeleteResponse : IResponse + { + bool Success { get; } + + string Status { get; } + } +} diff --git a/SendWithUs.Client/SendWithUs.Client.csproj b/SendWithUs.Client/SendWithUs.Client.csproj index c4b42fb..9404956 100755 --- a/SendWithUs.Client/SendWithUs.Client.csproj +++ b/SendWithUs.Client/SendWithUs.Client.csproj @@ -47,8 +47,11 @@ + + + @@ -69,11 +72,13 @@ + +