From fb19f2b11cc68c31c3a9c0407a9bc7635306bbb8 Mon Sep 17 00:00:00 2001
From: Shashike Jayatunge <35935196+donrestarone@users.noreply.github.com>
Date: Thu, 14 Jul 2022 21:14:10 -0400
Subject: [PATCH] test mailchimp plugin (#893) (#914) (#928)
Co-authored-by: Pralish Kayastha <50227291+Pralish@users.noreply.github.com>
---
test/fixtures/api_namespaces.yml | 27 +++++
test/fixtures/api_resources.yml | 9 ++
test/fixtures/external_api_clients.yml | 78 +++++++++++++-
test/plugins/mailchimp_plugin_test.rb | 139 +++++++++++++++++++++++++
4 files changed, 252 insertions(+), 1 deletion(-)
create mode 100644 test/plugins/mailchimp_plugin_test.rb
diff --git a/test/fixtures/api_namespaces.yml b/test/fixtures/api_namespaces.yml
index f5c4b7c4c..f94424649 100755
--- a/test/fixtures/api_namespaces.yml
+++ b/test/fixtures/api_namespaces.yml
@@ -81,4 +81,31 @@ namespace_with_all_types:
"null": null
}
requires_authentication: false
+ namespace_type: create-read-update-delete
+
+mailchimp:
+ name: mailchimp_namespace
+ slug: mailchimp_namespace
+ version: 1
+ properties: {
+ 'first_name': 'Violet',
+ 'last_name': 'Rails',
+ 'email': 'violet@rails.com',
+ 'contact': '',
+ 'synced_to_mailchimp': false
+ }
+ requires_authentication: false
+ namespace_type: create-read-update-delete
+
+mailchimp_logger:
+ name: mailchimp/logger
+ slug: mailchimp_logger
+ version: 1
+ properties: {
+ 'status': '',
+ 'response': {},
+ 'timstamp': '',
+ 'api_resource': ''
+ }
+ requires_authentication: false
namespace_type: create-read-update-delete
\ No newline at end of file
diff --git a/test/fixtures/api_resources.yml b/test/fixtures/api_resources.yml
index 1bca4c93e..87d904cee 100755
--- a/test/fixtures/api_resources.yml
+++ b/test/fixtures/api_resources.yml
@@ -33,3 +33,12 @@ plugin_subdomain_message_event:
"body": "
Hello
"
}
}
+mailchimp:
+ api_namespace: mailchimp
+ properties: {
+ 'first_name': 'Violet',
+ 'last_name': 'Rails',
+ 'email': 'violet@rails.com',
+ 'contact': '555-777',
+ 'synced_to_mailchimp': false
+ }
diff --git a/test/fixtures/external_api_clients.yml b/test/fixtures/external_api_clients.yml
index 7877d1510..46a260008 100644
--- a/test/fixtures/external_api_clients.yml
+++ b/test/fixtures/external_api_clients.yml
@@ -238,4 +238,80 @@ vacuum_job:
end
end
# at the end of the file we have to implicitly return the class
- VacuumJob
\ No newline at end of file
+ VacuumJob
+
+mailchimp_plugin:
+ api_namespace: mailchimp
+ slug: mailchimp-plugin
+ label: MailChimp
+ enabled: true
+ metadata: {
+ 'API_KEY': 'testkey',
+ 'SERVER_PREFIX': 'us9',
+ 'LIST_ID': 'valid_list_id',
+ }
+ model_definition: |
+ class SyncToMailchimp
+ def initialize(parameters)
+ @external_api_client = parameters[:external_api_client]
+ @api_key = @external_api_client.metadata["API_KEY"]
+ @unsynced_api_resources = @external_api_client.api_namespace.api_resources.where("properties @> ?", {synced_to_mailchimp: false}.to_json)
+ @mailchimp_uri = "https://#{@external_api_client.metadata['SERVER_PREFIX']}.api.mailchimp.com/3.0/lists/#{@external_api_client.metadata['LIST_ID']}/members?skip_merge_validation=true"
+ @custom_merge_fields_map = @external_api_client.metadata['CUSTOM_MERGE_FIELDS_MAP'] || {}
+ @attr_to_exclude = (@external_api_client.metadata['ATTR_TO_EXCLUDE'] || []) + @custom_merge_fields_map.keys + ['synced_to_mailchimp']
+ @logger_namespace = ApiNamespace.find_by(slug: @external_api_client.metadata["LOGGER_NAMESPACE"]) if @external_api_client.metadata["LOGGER_NAMESPACE"]
+ end
+
+ def start
+ @unsynced_api_resources.each do |api_resource|
+ begin
+ merge_fields = api_resource.properties.except(*@attr_to_exclude).transform_keys(&:upcase).transform_values(&:to_s)
+
+ @custom_merge_fields_map.each do |key, value|
+ merge_fields[value.upcase] = api_resource.properties[key].to_s if value
+ end
+
+ response = HTTParty.post(@mailchimp_uri,
+ body: {
+ email_address: api_resource.properties["email"],
+ status: "subscribed",
+ merge_fields: merge_fields,
+ tags: @external_api_client.metadata['TAGS'] || []
+ }.to_json,
+
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': "Basic #{@api_key}"
+ }
+ )
+
+ if response.success?
+ api_resource.properties["synced_to_mailchimp"] = true
+ api_resource.save
+ end
+
+ @logger_namespace.api_resources.create!(
+ properties: {
+ api_resource: api_resource.id,
+ status: response.success? ? "success" : "error",
+ response: JSON.parse(response.body),
+ timestamp: Time.zone.now
+ }
+ ) if @logger_namespace
+
+ rescue StandardError => e
+ @logger_namespace.api_resources.create!(
+ properties: {
+ api_resource: api_resource.id,
+ status: "error",
+ response: { detail: e.message},
+ timestamp: Time.zone.now
+ }
+ ) if @logger_namespace
+ end
+ end
+ end
+ end
+
+ # at the end of the file we have to implicitly return the class
+ SyncToMailchimp
\ No newline at end of file
diff --git a/test/plugins/mailchimp_plugin_test.rb b/test/plugins/mailchimp_plugin_test.rb
new file mode 100644
index 000000000..013320475
--- /dev/null
+++ b/test/plugins/mailchimp_plugin_test.rb
@@ -0,0 +1,139 @@
+require "test_helper"
+
+class MailchimpPluginTest < ActiveSupport::TestCase
+ setup do
+ @mailchimp_plugin = external_api_clients(:mailchimp_plugin)
+ @api_namespace = api_namespaces(:mailchimp)
+ @api_resource = api_resources(:mailchimp)
+ @logger_namespace = api_namespaces(:mailchimp_logger)
+ @mailchimp_api_uri = "https://#{@mailchimp_plugin.metadata['SERVER_PREFIX']}.api.mailchimp.com/3.0/lists/#{@mailchimp_plugin.metadata['LIST_ID']}/members?skip_merge_validation=true"
+ @request_headers = { 'Authorization': "Basic #{@mailchimp_plugin.metadata['API_KEY']}", 'Content-Type': 'application/json' }
+ Sidekiq::Testing.fake!
+ end
+
+ test "should send api request to mailchimp" do
+ metadata = @mailchimp_plugin.metadata
+
+ request_body = {
+ "email_address": @api_resource.properties['email'],
+ "status": "subscribed",
+ # synced_to_mailchimp property should be excluded by deafult
+ # merge fields keys should be uppercase properties keys
+ # tags should be an empty array if TAGS metadata is not defined
+ "merge_fields": {"EMAIL": @api_resource.properties['email'], "FIRST_NAME": @api_resource.properties['first_name'], "LAST_NAME": @api_resource.properties['last_name'], "CONTACT": @api_resource.properties['contact']},
+ "tags": []
+ }
+
+ response_body = {
+ "id" => "123adc",
+ "email" => "violet@rails.com"
+ }
+
+ mailchimp_request = stub_request(:post, @mailchimp_api_uri)
+ .with(body: request_body, headers: @request_headers)
+ .to_return(status: 200, body: response_body.to_json)
+
+ assert_changes -> { @api_resource.reload.properties['synced_to_mailchimp'] }, from: false, to: true do
+ # should not create log if LOGGER_NAMESPACE metadata is not defined
+ assert_no_difference "@logger_namespace.api_resources.count" do
+ perform_enqueued_jobs do
+ @mailchimp_plugin.run
+ Sidekiq::Worker.drain_all
+ end
+ end
+ end
+
+ assert_requested mailchimp_request
+ end
+
+ test "should send api request to mailchimp for all unsynced api resources" do
+ ApiResource.create(api_namespace_id: @api_namespace.id, properties: {'first_name': 'first_name', 'email': 'some_email@some_domain.com', 'synced_to_mailchimp': false})
+ ApiResource.create(api_namespace_id: @api_namespace.id, properties: {'first_name': 'some_name', 'email': 'second@some_domain.com', 'synced_to_mailchimp': true})
+
+ mailchimp_request = stub_request(:post, @mailchimp_api_uri).to_return(status: 200, body: {id: 'some_id'}.to_json)
+ expected_count = @api_namespace.api_resources.where("properties @> ?", {synced_to_mailchimp: false}.to_json).count
+
+ perform_enqueued_jobs do
+ @mailchimp_plugin.run
+ Sidekiq::Worker.drain_all
+ end
+
+ assert_requested mailchimp_request, times: expected_count
+ end
+
+ test "optional metadata" do
+ metadata = @mailchimp_plugin.metadata
+
+ # optional metadata
+ metadata['LOGGER_NAMESPACE'] = 'mailchimp_logger'
+ metadata['ATTR_TO_EXCLUDE'] = ['first_name']
+ metadata['TAGS'] = ['some_tag']
+ metadata['CUSTOM_MERGE_FIELDS_MAP'] = {'contact': 'PHONE'}
+
+ @mailchimp_plugin.update(metadata: metadata)
+
+ request_body = {
+ "email_address": @api_resource.properties['email'],
+ "status": "subscribed",
+ # synced_to_mailchimp property should be excluded by deafult
+ # excluded attributes [ATTR_TO_EXCLUDE] should not be present in the merge fields
+ # custom_merge_fields should replace default merge field name if CUSTOM_MERGE_FIELDS_MAP is defined eg. CONTACT is replaced by PHONE
+ "merge_fields": {"EMAIL": @api_resource.properties['email'], "LAST_NAME": @api_resource.properties['last_name'], "PHONE": @api_resource.properties['contact']},
+ "tags": ['some_tag']
+ }
+
+ response_body = {
+ "id" => "123adc",
+ "email" => "violet@rails.com"
+ }
+
+ mailchimp_request = stub_request(:post, @mailchimp_api_uri).with(body: request_body, headers: @request_headers).to_return(status: 200, body: response_body.to_json)
+
+ assert_changes -> { @api_resource.reload.properties['synced_to_mailchimp'] }, from: false, to: true do
+ # should create log if LOGGER_NAMESPACE metadata is defined
+ assert_difference "@logger_namespace.api_resources.count", +1 do
+ perform_enqueued_jobs do
+ @mailchimp_plugin.run
+ Sidekiq::Worker.drain_all
+ end
+ end
+ end
+
+ log = @logger_namespace.api_resources.last.properties
+
+ assert_equal log['status'], 'success'
+ assert_equal log['api_resource'], @api_resource.id
+ assert_equal log['response'], response_body
+
+ assert_requested mailchimp_request
+ end
+
+ test "error response: should create log with error status" do
+ metadata = @mailchimp_plugin.metadata
+ metadata['LOGGER_NAMESPACE'] = 'mailchimp_logger'
+
+ @mailchimp_plugin.update(metadata: metadata)
+
+ response_body = { "message" => "error message" }
+
+ mailchimp_request = stub_request(:post, @mailchimp_api_uri).to_return(status: 400, body: response_body.to_json)
+
+ assert_no_changes @api_resource.reload.properties['synced_to_mailchimp'] do
+ # should create log if LOGGER_NAMESPACE metadata is defined
+ assert_difference "@logger_namespace.api_resources.count", +1 do
+ perform_enqueued_jobs do
+ @mailchimp_plugin.run
+ Sidekiq::Worker.drain_all
+ end
+ end
+ end
+
+ log = @logger_namespace.api_resources.last.properties
+
+ assert_equal log['status'], 'error'
+ assert_equal log['api_resource'], @api_resource.id
+ assert_equal log['response'], response_body
+
+ assert_requested mailchimp_request
+ end
+end
\ No newline at end of file