require 'spec_helper' class WebHookProcessorTestHarness # Mock some controller behaviour # TODO: we should probably start using a real controller harness for testing def self.skip_before_action(*args) ; @skip_before_action_settings = args; end def self.skip_before_action_settings ; @skip_before_action_settings; end def self.before_action(*args) ; @before_action_settings = args ; end def self.before_action_settings ; @before_action_settings; end def head(*args) ; end attr_accessor :params, :request include Mandrill::Rails::WebHookProcessor end describe Mandrill::Rails::WebHookProcessor do let(:processor_class) { WebHookProcessorTestHarness } let(:processor_instance) { processor_class.new } before do # clear class instance settings processor_class.authenticate_with_mandrill_keys! nil processor_class.on_unhandled_mandrill_events! nil end describe "##skip_before_action settings" do subject { processor_class.skip_before_action_settings } it "includes verify_authenticity_token" do expect(subject).to eql([:verify_authenticity_token, { raise: false }]) end end describe "##before_action settings" do subject { processor_class.before_action_settings } it "includes authenticate_mandrill_request" do expect(subject).to eql([:authenticate_mandrill_request!, {:only=>[:create]}]) end end describe "#mandrill_webhook_keys" do subject { processor_class.mandrill_webhook_keys } context "when not set" do it "is empty" do expect(subject).to eql([]) end end context "when set with mandrill_webhook_keys=" do let(:expected_value) { [1,2,3] } before { processor_class.mandrill_webhook_keys = expected_value } it { should eql(expected_value) } end context "when authenticate_with_mandrill_keys! set" do context "with an array" do it "has the correct settings" do processor_class.authenticate_with_mandrill_keys! [4,5,6] expect(subject).to eql([4,5,6]) end end context "with a list" do it "has the correct settings" do processor_class.authenticate_with_mandrill_keys! "a", "b", "c" expect(subject).to eql(["a", "b", "c"]) end end context "with a single value" do it "has the correct settings" do processor_class.authenticate_with_mandrill_keys! "key_a" expect(subject).to eql(["key_a"]) end end context "with nil" do it "has cleared settings" do processor_class.authenticate_with_mandrill_keys! "key_a" processor_class.authenticate_with_mandrill_keys! nil expect(subject).to eql([]) end end end end subject { processor_instance } describe "#show" do it "should return head(:ok)" do expect(processor_instance).to receive(:head).with(:ok) processor_instance.show end end describe "#create" do let(:params) { {} } before do processor_instance.params = params end it "returns head(:ok) on success" do expect(processor_instance).to receive(:head).with(:ok) expect_any_instance_of(Mandrill::WebHook::Processor).to receive(:run!) expect_any_instance_of(Mandrill::WebHook::Processor).to receive(:on_unhandled_mandrill_events=).with(:log) processor_instance.create end context "when unhandled events set to raise exceptions" do it "delegates the setting to the processor" do processor_instance.class.unhandled_events_raise_exceptions! expect(processor_instance).to receive(:head).with(:ok) expect_any_instance_of(Mandrill::WebHook::Processor).to receive(:run!) expect_any_instance_of(Mandrill::WebHook::Processor).to receive(:on_unhandled_mandrill_events=).with(:raise_exception) processor_instance.create end end context "when unhandled events set to be ignored" do it "delegates the setting to the processor" do processor_instance.class.ignore_unhandled_events! expect(processor_instance).to receive(:head).with(:ok) expect_any_instance_of(Mandrill::WebHook::Processor).to receive(:run!) expect_any_instance_of(Mandrill::WebHook::Processor).to receive(:on_unhandled_mandrill_events=).with(:ignore) processor_instance.create end end end describe "#authenticate_mandrill_request! (protected)" do let(:example_payload) { webhook_example_event('click_with_signature') } let(:expected_signature) { example_payload['headers']['X-Mandrill-Signature'] } let(:original_url) { example_payload['original_url'] } let(:valid_webhook_key) { example_payload['private_key'] } let(:raw_params) { example_payload['raw_params'] } let(:params) { {} } let(:headers) { { 'HTTP_X_MANDRILL_SIGNATURE' => expected_signature} } let(:request) { double() } before do allow(request).to receive(:original_url).and_return(original_url) allow(request).to receive(:request_parameters).and_return(raw_params) allow(request).to receive(:headers).and_return(headers) processor_instance.request = request processor_instance.params = params end subject { processor_instance.send(:authenticate_mandrill_request!) } context "when authentication not enabled" do it "passes" do expect(subject).to eql(true) end end context "when authentication enabled" do before do processor_class.authenticate_with_mandrill_keys! mandrill_webhook_keys end context "with valid key" do let(:mandrill_webhook_keys) { valid_webhook_key } it "passes" do expect(subject).to eql(true) end end context "with mix of valid and invalid keys" do let(:mandrill_webhook_keys) { ['bogative',valid_webhook_key] } it "passes" do expect(subject).to eql(true) end end context "with invalid key" do let(:mandrill_webhook_keys) { 'bogative' } it "calls head(:forbidden) and return false" do expect(processor_instance).to receive(:head).with(:forbidden, :text => "Mandrill signature did not match.") expect(subject).to eql(false) end end end end end