s3_agent_spec.rb 7.8KB

    require 'rails_helper' describe Agents::S3Agent do before(:each) do @valid_params = { 'mode' => 'read', 'access_key_id' => '32343242', 'access_key_secret' => '1231312', 'watch' => 'false', 'bucket' => 'testbucket', 'region' => 'us-east-1', 'filename' => 'test.txt', 'data' => '{{ data }}' } @checker = Agents::S3Agent.new(:name => "somename", :options => @valid_params) @checker.user = users(:jane) @checker.save! end describe "#validate_options" do it "requires the bucket to be set" do @checker.options['bucket'] = '' expect(@checker).not_to be_valid end it "requires watch to be present" do @checker.options['watch'] = '' expect(@checker).not_to be_valid end it "requires watch to be either 'true' or 'false'" do @checker.options['watch'] = 'true' expect(@checker).to be_valid @checker.options['watch'] = 'false' expect(@checker).to be_valid @checker.options['watch'] = 'test' expect(@checker).not_to be_valid end it "requires region to be present" do @checker.options['region'] = '' expect(@checker).not_to be_valid end it "requires mode to be set to 'read' or 'write'" do @checker.options['mode'] = 'write' expect(@checker).to be_valid @checker.options['mode'] = '' expect(@checker).not_to be_valid end it "requires 'filename' in 'write' mode" do @checker.options['mode'] = 'write' @checker.options['filename'] = '' expect(@checker).not_to be_valid end it "requires 'data' in 'write' mode" do @checker.options['mode'] = 'write' @checker.options['data'] = '' expect(@checker).not_to be_valid end end describe "#validating" do it "validates the key" do mock(@checker).client { raise Aws::S3::Errors::SignatureDoesNotMatch.new('', '') } expect(@checker.validate_access_key_id).to be_falsy end it "validates the secret" do mock(@checker).buckets { true } expect(@checker.validate_access_key_secret).to be_truthy end end it "completes the buckets" do mock(@checker).buckets { [OpenStruct.new(name: 'test'), OpenStruct.new(name: 'test2')]} expect(@checker.complete_bucket).to eq([{text: 'test', id: 'test'}, {text: 'test2', id: 'test2'}]) end context "#working" do it "is working with no recent errors" do @checker.last_check_at = Time.now expect(@checker).to be_working end end context "#check" do context "not watching" do it "emits an event for every file" do mock(@checker).get_bucket_contents { {"test"=>"231232", "test2"=>"4564545"} } expect { @checker.check }.to change(Event, :count).by(2) expect(Event.last.payload).to eq({"file_pointer" => {"file"=>"test2", "agent_id"=> @checker.id}}) end end context "watching" do before(:each) do @checker.options['watch'] = 'true' end it "does not emit any events on the first run" do contents = {"test"=>"231232", "test2"=>"4564545"} mock(@checker).get_bucket_contents { contents } expect { @checker.check }.not_to change(Event, :count) expect(@checker.memory).to eq('seen_contents' => contents) end context "detecting changes" do before(:each) do contents = {"test"=>"231232", "test2"=>"4564545"} mock(@checker).get_bucket_contents { contents } expect { @checker.check }.not_to change(Event, :count) @checker.last_check_at = Time.now end it "emits events for removed files" do contents = {"test"=>"231232"} mock(@checker).get_bucket_contents { contents } expect { @checker.check }.to change(Event, :count).by(1) expect(Event.last.payload).to eq({"file_pointer" => {"file" => "test2", "agent_id"=> @checker.id}, "event_type" => "removed"}) end it "emits events for modified files" do contents = {"test"=>"231232", "test2"=>"changed"} mock(@checker).get_bucket_contents { contents } expect { @checker.check }.to change(Event, :count).by(1) expect(Event.last.payload).to eq({"file_pointer" => {"file" => "test2", "agent_id"=> @checker.id}, "event_type" => "modified"}) end it "emits events for added files" do contents = {"test"=>"231232", "test2"=>"4564545", "test3" => "31231231"} mock(@checker).get_bucket_contents { contents } expect { @checker.check }.to change(Event, :count).by(1) expect(Event.last.payload).to eq({"file_pointer" => {"file" => "test3", "agent_id"=> @checker.id}, "event_type" => "added"}) end end context "error handling" do it "handles AccessDenied exceptions" do mock(@checker).get_bucket_contents { raise Aws::S3::Errors::AccessDenied.new('', '') } expect { @checker.check }.to change(AgentLog, :count).by(1) expect(AgentLog.last.message).to eq("Could not access 'testbucket' Aws::S3::Errors::AccessDenied ") end it "handles generic S3 exceptions" do mock(@checker).get_bucket_contents { raise Aws::S3::Errors::PermanentRedirect.new('', 'error') } expect { @checker.check }.to change(AgentLog, :count).by(1) expect(AgentLog.last.message).to eq("Aws::S3::Errors::PermanentRedirect: error") end end end end it "get_io returns a StringIO object" do stringio =StringIO.new mock_response = mock() mock(mock_response).body { stringio } mock_client = mock() mock(mock_client).get_object(bucket: 'testbucket', key: 'testfile') { mock_response } mock(@checker).client { mock_client } @checker.get_io('testfile') end context "#get_bucket_contents" do it "returns a hash with the contents of the bucket" do mock_response = mock() mock(mock_response).contents { [OpenStruct.new(key: 'test', etag: '231232'), OpenStruct.new(key: 'test2', etag: '4564545')] } mock_client = mock() mock(mock_client).list_objects(bucket: 'testbucket') { [mock_response] } mock(@checker).client { mock_client } expect(@checker.send(:get_bucket_contents)).to eq({"test"=>"231232", "test2"=>"4564545"}) end end context "#client" do it "initializes the S3 client correctly" do mock_credential = mock() mock(Aws::Credentials).new('32343242', '1231312') { mock_credential } mock(Aws::S3::Client).new(credentials: mock_credential, region: 'us-east-1') @checker.send(:client) end end context "#event_description" do it "should include event_type when watch is set to true" do @checker.options['watch'] = 'true' expect(@checker.event_description).to include('event_type') end it "should not include event_type when watch is set to false" do @checker.options['watch'] = 'false' expect(@checker.event_description).not_to include('event_type') end end context "#receive" do before(:each) do @checker.options['mode'] = 'write' @checker.options['filename'] = 'file.txt' @checker.options['data'] = '{{ data }}' end it "writes the data at data into a file" do client_mock = mock() mock(client_mock).put_object(bucket: @checker.options['bucket'], key: @checker.options['filename'], body: 'hello world!') mock(@checker).client { client_mock } event = Event.new(payload: {'data' => 'hello world!'}) @checker.receive([event]) end it "does nothing when mode is set to 'read'" do @checker.options['mode'] = 'read' event = Event.new(payload: {'data' => 'hello world!'}) @checker.receive([event]) end end end