spec/outputs/sns_spec.rb in logstash-output-sns-1.0.0 vs spec/outputs/sns_spec.rb in logstash-output-sns-2.0.0

- old
+ new

@@ -1,18 +1,142 @@ # encoding: utf-8 require "logstash/devutils/rspec/spec_helper" require 'logstash/outputs/sns' require 'logstash/event' +require "logstash/plugin_mixins/aws_config" +require "aws-sdk" # TODO: Why is this not automatically brought in by the aws_config plugin? + describe LogStash::Outputs::Sns do - describe '#format_message' do - it 'should allow to output to sns with empty tags' do - event = LogStash::Event.new({ "message" => "42 is the answer" }) - expect(LogStash::Outputs::Sns.format_message(event)).to match(/Tags:\s\n/m) + let(:arn) { "arn:aws:sns:us-east-1:999999999:logstash-test-sns-topic" } + let(:sns_subject) { "The Plain in Spain" } + let(:sns_message) { "That's where the rain falls, plainly." } + let(:mock_client) { double("Aws::SNS::Client") } + let(:instance) { + allow(Aws::SNS::Client).to receive(:new).and_return(mock_client) + inst = LogStash::Outputs::Sns.new + allow(inst).to receive(:publish_boot_message_arn).and_return(nil) + inst.register + inst + } + + describe "receiving an event" do + let(:expected_subject) { double("expected_subject")} + subject { + inst = instance + allow(inst).to receive(:send_sns_message).with(any_args) + allow(inst).to receive(:event_subject). + with(any_args). + and_return(expected_subject) + inst.receive(event) + inst + } + + shared_examples("publishing correctly") do + it "should send a message to the correct ARN if the event has 'arn' set" do + expect(subject).to have_received(:send_sns_message).with(arn, anything, anything) + end + + it "should send the message" do + expect(subject).to have_received(:send_sns_message).with(anything, anything, expected_message) + end + + it "should send the subject" do + expect(subject).to have_received(:send_sns_message).with(anything, expected_subject, anything) + end end - it 'should allow to output to sns with a list of tags' do - event = LogStash::Event.new({"tags" => ["elasticsearch", "logstash", "kibana"] }) - expect(LogStash::Outputs::Sns.format_message(event)).to match(/\nTags:\selasticsearch,\slogstash,\skibana\n/m) + describe "with an explicit message" do + let(:expected_subject) { sns_subject } + let(:expected_message) { sns_message } + let(:event) { LogStash::Event.new("sns" => arn, "sns_subject" => sns_subject, + "sns_message" => sns_message) } + include_examples("publishing correctly") + end + + describe "without an explicit message" do + # Testing codecs sucks. It'd be nice if codecs had to implement some sort of encode_sync method + let(:expected_message) { + c = subject.codec.clone + result = nil; + c.on_event {|event, encoded| result = encoded } + c.encode(event) + result + } + let(:event) { LogStash::Event.new("sns" => arn, "sns_subject" => sns_subject) } + + include_examples("publishing correctly") + end + end + + describe "determining the subject" do + it "should return 'sns_subject' when set" do + event = LogStash::Event.new("sns_subject" => "foo") + expect(subject.send(:event_subject, event)).to eql("foo") + end + + it "should return the sns subject as JSON if not a string" do + event = LogStash::Event.new("sns_subject" => ["foo", "bar"]) + expect(subject.send(:event_subject, event)).to eql(LogStash::Json.dump(["foo", "bar"])) + end + + it "should return the host if 'sns_subject' not set" do + event = LogStash::Event.new("host" => "foo") + expect(subject.send(:event_subject, event)).to eql("foo") + end + + it "should return 'NO SUBJECT' when subject cannot be determined" do + event = LogStash::Event.new("foo" => "bar") + expect(subject.send(:event_subject, event)).to eql(LogStash::Outputs::Sns::NO_SUBJECT) + end + end + + describe "sending an SNS notification" do + let(:good_publish_args) { + { + :topic_arn => arn, + :subject => sns_subject, + :message => sns_message + } + } + let(:long_message) { "A" * (LogStash::Outputs::Sns::MAX_MESSAGE_SIZE_IN_BYTES + 1) } + let(:long_subject) { "S" * (LogStash::Outputs::Sns::MAX_SUBJECT_SIZE_IN_CHARACTERS + 1) } + subject { instance } + + it "should raise an ArgumentError if no arn is provided" do + expect { + subject.send(:send_sns_message, nil, sns_subject, sns_message) + }.to raise_error(ArgumentError) + end + + it "should send a well formed message through to SNS" do + expect(mock_client).to receive(:publish).with(good_publish_args) + subject.send(:send_sns_message, arn, sns_subject, sns_message) + end + + it "should attempt to publish a boot message" do + expect(subject).to have_received(:publish_boot_message_arn).once + x = case "foo" + when "bar" + "hello" + end + end + + it "should truncate long messages before sending" do + max_size = LogStash::Outputs::Sns::MAX_MESSAGE_SIZE_IN_BYTES + expect(mock_client).to receive(:publish) {|args| + expect(args[:message].bytesize).to eql(max_size) + } + + subject.send(:send_sns_message, arn, sns_subject, long_message) + end + + it "should truncate long subjects before sending" do + max_size = LogStash::Outputs::Sns::MAX_SUBJECT_SIZE_IN_CHARACTERS + expect(mock_client).to receive(:publish) {|args| + expect(args[:subject].bytesize).to eql(max_size) + } + + subject.send(:send_sns_message, arn, long_subject, sns_message) end end end