s3_agent_spec.rb 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. require 'rails_helper'
  2. describe Agents::S3Agent do
  3. before(:each) do
  4. @valid_params = {
  5. 'mode' => 'read',
  6. 'access_key_id' => '32343242',
  7. 'access_key_secret' => '1231312',
  8. 'watch' => 'false',
  9. 'bucket' => 'testbucket',
  10. 'region' => 'us-east-1',
  11. 'filename' => 'test.txt',
  12. 'data' => '{{ data }}'
  13. }
  14. @checker = Agents::S3Agent.new(:name => "somename", :options => @valid_params)
  15. @checker.user = users(:jane)
  16. @checker.save!
  17. end
  18. describe "#validate_options" do
  19. it "requires the bucket to be set" do
  20. @checker.options['bucket'] = ''
  21. expect(@checker).not_to be_valid
  22. end
  23. it "requires watch to be present" do
  24. @checker.options['watch'] = ''
  25. expect(@checker).not_to be_valid
  26. end
  27. it "requires watch to be either 'true' or 'false'" do
  28. @checker.options['watch'] = 'true'
  29. expect(@checker).to be_valid
  30. @checker.options['watch'] = 'false'
  31. expect(@checker).to be_valid
  32. @checker.options['watch'] = 'test'
  33. expect(@checker).not_to be_valid
  34. end
  35. it "requires region to be present" do
  36. @checker.options['region'] = ''
  37. expect(@checker).not_to be_valid
  38. end
  39. it "requires mode to be set to 'read' or 'write'" do
  40. @checker.options['mode'] = 'write'
  41. expect(@checker).to be_valid
  42. @checker.options['mode'] = ''
  43. expect(@checker).not_to be_valid
  44. end
  45. it "requires 'filename' in 'write' mode" do
  46. @checker.options['mode'] = 'write'
  47. @checker.options['filename'] = ''
  48. expect(@checker).not_to be_valid
  49. end
  50. it "requires 'data' in 'write' mode" do
  51. @checker.options['mode'] = 'write'
  52. @checker.options['data'] = ''
  53. expect(@checker).not_to be_valid
  54. end
  55. end
  56. describe "#validating" do
  57. it "validates the key" do
  58. expect(@checker).to receive(:client) {
  59. Aws::S3::Client.new(stub_responses: { list_buckets: ['SignatureDoesNotMatch'] })
  60. }
  61. expect(@checker.validate_access_key_id).to be_falsy
  62. end
  63. it "validates the secret" do
  64. expect(@checker).to receive(:buckets) { true }
  65. expect(@checker.validate_access_key_secret).to be_truthy
  66. end
  67. end
  68. it "completes the buckets" do
  69. expect(@checker).to receive(:buckets) { [OpenStruct.new(name: 'test'), OpenStruct.new(name: 'test2')]}
  70. expect(@checker.complete_bucket).to eq([{text: 'test', id: 'test'}, {text: 'test2', id: 'test2'}])
  71. end
  72. context "#working" do
  73. it "is working with no recent errors" do
  74. @checker.last_check_at = Time.now
  75. expect(@checker).to be_working
  76. end
  77. end
  78. context "#check" do
  79. context "not watching" do
  80. it "emits an event for every file" do
  81. expect(@checker).to receive(:get_bucket_contents) { {"test"=>"231232", "test2"=>"4564545"} }
  82. expect { @checker.check }.to change(Event, :count).by(2)
  83. expect(Event.last.payload).to eq({"file_pointer" => {"file"=>"test2", "agent_id"=> @checker.id}})
  84. end
  85. end
  86. context "watching" do
  87. before(:each) do
  88. @checker.options['watch'] = 'true'
  89. end
  90. it "does not emit any events on the first run" do
  91. contents = {"test"=>"231232", "test2"=>"4564545"}
  92. expect(@checker).to receive(:get_bucket_contents) { contents }
  93. expect { @checker.check }.not_to change(Event, :count)
  94. expect(@checker.memory).to eq('seen_contents' => contents)
  95. end
  96. context "detecting changes" do
  97. before(:each) do
  98. contents = {"test"=>"231232", "test2"=>"4564545"}
  99. expect(@checker).to receive(:get_bucket_contents) { contents }
  100. expect { @checker.check }.not_to change(Event, :count)
  101. @checker.last_check_at = Time.now
  102. end
  103. it "emits events for removed files" do
  104. contents = {"test"=>"231232"}
  105. expect(@checker).to receive(:get_bucket_contents) { contents }
  106. expect { @checker.check }.to change(Event, :count).by(1)
  107. expect(Event.last.payload).to eq({"file_pointer" => {"file" => "test2", "agent_id"=> @checker.id}, "event_type" => "removed"})
  108. end
  109. it "emits events for modified files" do
  110. contents = {"test"=>"231232", "test2"=>"changed"}
  111. expect(@checker).to receive(:get_bucket_contents) { contents }
  112. expect { @checker.check }.to change(Event, :count).by(1)
  113. expect(Event.last.payload).to eq({"file_pointer" => {"file" => "test2", "agent_id"=> @checker.id}, "event_type" => "modified"})
  114. end
  115. it "emits events for added files" do
  116. contents = {"test"=>"231232", "test2"=>"4564545", "test3" => "31231231"}
  117. expect(@checker).to receive(:get_bucket_contents) { contents }
  118. expect { @checker.check }.to change(Event, :count).by(1)
  119. expect(Event.last.payload).to eq({"file_pointer" => {"file" => "test3", "agent_id"=> @checker.id}, "event_type" => "added"})
  120. end
  121. end
  122. context "error handling" do
  123. it "handles AccessDenied exceptions" do
  124. expect(@checker).to receive(:client) {
  125. Aws::S3::Client.new(stub_responses: { list_objects: ['AccessDenied'] })
  126. }
  127. expect { @checker.check }.to change(AgentLog, :count).by(1)
  128. expect(AgentLog.last.message).to match(/Could not access 'testbucket' Aws::S3::Errors::AccessDenied/)
  129. end
  130. it "handles generic S3 exceptions" do
  131. expect(@checker).to receive(:client) {
  132. Aws::S3::Client.new(stub_responses: { list_objects: ['PermanentRedirect'] })
  133. }
  134. expect { @checker.check }.to change(AgentLog, :count).by(1)
  135. expect(AgentLog.last.message).to eq("Aws::S3::Errors::PermanentRedirect: stubbed-response-error-message")
  136. end
  137. end
  138. end
  139. end
  140. it "get_io returns a StringIO object" do
  141. stringio =StringIO.new
  142. mock_response = double()
  143. expect(mock_response).to receive(:body) { stringio }
  144. mock_client = double()
  145. expect(mock_client).to receive(:get_object).with(bucket: 'testbucket', key: 'testfile') { mock_response }
  146. expect(@checker).to receive(:client) { mock_client }
  147. @checker.get_io('testfile')
  148. end
  149. context "#get_bucket_contents" do
  150. it "returns a hash with the contents of the bucket" do
  151. mock_response = double()
  152. expect(mock_response).to receive(:contents) { [OpenStruct.new(key: 'test', etag: '231232'), OpenStruct.new(key: 'test2', etag: '4564545')] }
  153. mock_client = double()
  154. expect(mock_client).to receive(:list_objects).with(bucket: 'testbucket') { [mock_response] }
  155. expect(@checker).to receive(:client) { mock_client }
  156. expect(@checker.send(:get_bucket_contents)).to eq({"test"=>"231232", "test2"=>"4564545"})
  157. end
  158. end
  159. context "#client" do
  160. it "initializes the S3 client correctly" do
  161. mock_credential = double()
  162. expect(Aws::Credentials).to receive(:new).with('32343242', '1231312') { mock_credential }
  163. expect(Aws::S3::Client).to receive(:new).with(credentials: mock_credential,
  164. region: 'us-east-1')
  165. @checker.send(:client)
  166. end
  167. end
  168. context "#event_description" do
  169. it "should include event_type when watch is set to true" do
  170. @checker.options['watch'] = 'true'
  171. expect(@checker.event_description).to include('event_type')
  172. end
  173. it "should not include event_type when watch is set to false" do
  174. @checker.options['watch'] = 'false'
  175. expect(@checker.event_description).not_to include('event_type')
  176. end
  177. end
  178. context "#receive" do
  179. before(:each) do
  180. @checker.options['mode'] = 'write'
  181. @checker.options['filename'] = 'file.txt'
  182. @checker.options['data'] = '{{ data }}'
  183. end
  184. it "writes the data at data into a file" do
  185. client_mock = double()
  186. expect(client_mock).to receive(:put_object).with(bucket: @checker.options['bucket'], key: @checker.options['filename'], body: 'hello world!')
  187. expect(@checker).to receive(:client) { client_mock }
  188. event = Event.new(payload: {'data' => 'hello world!'})
  189. @checker.receive([event])
  190. end
  191. it "does nothing when mode is set to 'read'" do
  192. @checker.options['mode'] = 'read'
  193. event = Event.new(payload: {'data' => 'hello world!'})
  194. @checker.receive([event])
  195. end
  196. end
  197. end