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