glacier_on_rails 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rspec +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +21 -0
  6. data/Gemfile.lock +231 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +98 -0
  9. data/Rakefile +13 -0
  10. data/app/assets/images/glacier_on_rails/.gitkeep +0 -0
  11. data/app/assets/javascripts/glacier_on_rails/application.js +15 -0
  12. data/app/assets/stylesheets/glacier_on_rails/application.css +13 -0
  13. data/app/controllers/glacier_on_rails/application_controller.rb +2 -0
  14. data/app/controllers/glacier_on_rails/application_data_backups_controller.rb +43 -0
  15. data/app/controllers/glacier_on_rails/aws_archive_retrieval_jobs_controller.rb +7 -0
  16. data/app/controllers/glacier_on_rails/aws_sns_subscriptions_controller.rb +40 -0
  17. data/app/helpers/glacier_on_rails/application_helper.rb +4 -0
  18. data/app/models/application_data_backup.rb +84 -0
  19. data/app/models/application_database/base_adapter.rb +7 -0
  20. data/app/models/application_database/mysql_adapter.rb +11 -0
  21. data/app/models/application_database/postgres_adapter.rb +52 -0
  22. data/app/models/application_database.rb +29 -0
  23. data/app/models/application_file.rb +25 -0
  24. data/app/models/aws_backend/sns_subscription.rb +54 -0
  25. data/app/models/aws_backend.rb +113 -0
  26. data/app/models/aws_log.rb +7 -0
  27. data/app/models/glacier_archive.rb +115 -0
  28. data/app/models/glacier_db_archive.rb +27 -0
  29. data/app/models/glacier_file_archive.rb +45 -0
  30. data/app/views/glacier_on_rails/aws_archive_retrieval_jobs/_application_data_backup.haml +4 -0
  31. data/app/views/glacier_on_rails/aws_archive_retrieval_jobs/_available.haml +3 -0
  32. data/app/views/glacier_on_rails/aws_archive_retrieval_jobs/_index.haml +101 -0
  33. data/app/views/glacier_on_rails/aws_archive_retrieval_jobs/_local.haml +1 -0
  34. data/app/views/glacier_on_rails/aws_archive_retrieval_jobs/_pending.haml +1 -0
  35. data/app/views/glacier_on_rails/aws_archive_retrieval_jobs/_ready.haml +2 -0
  36. data/config/initializers/aws_log.rb +1 -0
  37. data/config/initializers/glacier_on_rails.rb +3 -0
  38. data/config/initializers/time_formats.rb +3 -0
  39. data/config/routes.rb +9 -0
  40. data/db/migrate/20170503133854_create_glacier_archives_table.rb +11 -0
  41. data/db/migrate/20170507161533_add_notification_column_to_glacier_archives.rb +5 -0
  42. data/db/migrate/20170509195716_add_archive_retrieval_job_id_to_glacier_archive.rb +5 -0
  43. data/db/migrate/20170602135721_create_application_data_backups.rb +7 -0
  44. data/db/migrate/20170602143524_add_application_data_backup_id_to_glacier_archives.rb +5 -0
  45. data/db/migrate/20170602145526_create_glacier_file_archive_join_table.rb +5 -0
  46. data/db/migrate/20170602150324_add_type_to_glacier_archives.rb +5 -0
  47. data/db/migrate/20170603141909_add_filename_to_glacier_archive.rb +5 -0
  48. data/glacier_on_rails.gemspec +29 -0
  49. data/lib/glacier_on_rails/config.rb +22 -0
  50. data/lib/glacier_on_rails/engine.rb +5 -0
  51. data/lib/glacier_on_rails/version.rb +3 -0
  52. data/lib/glacier_on_rails.rb +5 -0
  53. data/lib/tasks/aws.rake +6 -0
  54. data/script/rails +8 -0
  55. data/spec/dummy/README.rdoc +261 -0
  56. data/spec/dummy/Rakefile +7 -0
  57. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  58. data/spec/dummy/app/assets/javascripts/ractive.js +16621 -0
  59. data/spec/dummy/app/assets/javascripts/underscore.js +5 -0
  60. data/spec/dummy/app/assets/stylesheets/application.css +14 -0
  61. data/spec/dummy/app/controllers/admin_controller.rb +4 -0
  62. data/spec/dummy/app/controllers/application_controller.rb +6 -0
  63. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  64. data/spec/dummy/app/mailers/.gitkeep +0 -0
  65. data/spec/dummy/app/models/.gitkeep +0 -0
  66. data/spec/dummy/app/models/application_record.rb +3 -0
  67. data/spec/dummy/app/models/fake_model.rb +10 -0
  68. data/spec/dummy/app/views/admin/_flash_error.haml +40 -0
  69. data/spec/dummy/app/views/admin/index.haml +3 -0
  70. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  71. data/spec/dummy/config/application.rb +67 -0
  72. data/spec/dummy/config/boot.rb +10 -0
  73. data/spec/dummy/config/database.yml +6 -0
  74. data/spec/dummy/config/environment.rb +5 -0
  75. data/spec/dummy/config/environments/development.rb +40 -0
  76. data/spec/dummy/config/environments/production.rb +70 -0
  77. data/spec/dummy/config/environments/test.rb +40 -0
  78. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  79. data/spec/dummy/config/initializers/file_upload.rb +1 -0
  80. data/spec/dummy/config/initializers/glacier_on_rails.rb +5 -0
  81. data/spec/dummy/config/initializers/inflections.rb +15 -0
  82. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  83. data/spec/dummy/config/initializers/secret_token.rb +8 -0
  84. data/spec/dummy/config/initializers/session_store.rb +8 -0
  85. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  86. data/spec/dummy/config/locales/en.yml +5 -0
  87. data/spec/dummy/config/routes.rb +5 -0
  88. data/spec/dummy/config.ru +4 -0
  89. data/spec/dummy/db/migrate/20170531170208_create_fake_models.rb +8 -0
  90. data/spec/dummy/db/schema.rb +56 -0
  91. data/spec/dummy/lib/assets/.gitkeep +0 -0
  92. data/spec/dummy/lib/constants.rb +2 -0
  93. data/spec/dummy/log/.gitkeep +0 -0
  94. data/spec/dummy/public/404.html +26 -0
  95. data/spec/dummy/public/422.html +26 -0
  96. data/spec/dummy/public/500.html +25 -0
  97. data/spec/dummy/public/favicon.ico +0 -0
  98. data/spec/dummy/script/rails +6 -0
  99. data/spec/features/application_data_backup_spec.rb +166 -0
  100. data/spec/helpers/aws_helper.rb +99 -0
  101. data/spec/helpers/dummy_app_helper.rb +23 -0
  102. data/spec/helpers/http_mock_helpers.rb +137 -0
  103. data/spec/models/application_data_backup_spec.rb +226 -0
  104. data/spec/models/application_file_spec.rb +8 -0
  105. data/spec/models/glacier_db_archive_spec.rb +118 -0
  106. data/spec/models/glacier_file_archive_spec.rb +56 -0
  107. data/spec/models/postgres_adapter_spec.rb +46 -0
  108. data/spec/rails_helper.rb +59 -0
  109. data/spec/spec_helper.rb +110 -0
  110. data/spec/support/wait_for_ajax.rb +22 -0
  111. metadata +308 -0
@@ -0,0 +1,226 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ApplicationDataBackup#create" do
4
+ include HttpMockHelpers
5
+ include DummyAppDb
6
+ before do
7
+ @backup = ApplicationDataBackup.create
8
+ end
9
+
10
+ it "should have a single GlacierDbArchive association" do
11
+ expect(@backup.glacier_db_archive).to be_a GlacierDbArchive
12
+ end
13
+
14
+ it "should have a GlacierFileArchive for each file attachment" do
15
+ expect(@backup.glacier_file_archives.length).to eq 3 # DummyAppDb creates 3 files
16
+ end
17
+
18
+ it "should create exactly one ApplicationDataBackup instance" do
19
+ expect(ApplicationDataBackup.count).to eq 1
20
+ end
21
+
22
+ it "should create exactly one GlacierDbArchive" do
23
+ expect(GlacierDbArchive.count).to eq 1
24
+ end
25
+ end
26
+
27
+ describe "ApplicationDataBackup#initiate_retrieval" do
28
+ include HttpMockHelpers
29
+ include DummyAppDb
30
+ include AwsHelper
31
+ context "all aws responses are normal" do
32
+ before do
33
+ create_application_data_backup_with_available_components
34
+ FileUtils.rm(FakeModel::FilePath.join(FakeModel.first.file_id))
35
+ @application_data_backup.initiate_retrieval
36
+ end
37
+
38
+ it "should initiate retrieval for database and file archives" do
39
+ expect(@application_data_backup.glacier_db_archive.retrieval_status).to eq 'pending'
40
+ expect(@application_data_backup.glacier_file_archives[0].retrieval_status).to eq 'pending' # b/c its file was removed
41
+ expect(@application_data_backup.glacier_file_archives[1].retrieval_status).to eq 'exists'
42
+ expect(@application_data_backup.glacier_file_archives[2].retrieval_status).to eq 'exists'
43
+ expect(@application_data_backup.retrieval_status).to eq 'pending'
44
+ expect(initiate_retrieve_job).to have_been_requested.times(2) # one pending file and the db
45
+ end
46
+ end
47
+
48
+ context "one of the responses has an error" do
49
+ before do
50
+ stub_errored_response_for_initiate_retrieval
51
+ create_application_data_backup_with_available_components
52
+ FileUtils.rm(Dir.glob(FakeModel::FilePath.join('*')))
53
+ @application_data_backup.initiate_retrieval
54
+ end
55
+
56
+ it "does not change to pending status if one of the components returns error for the initiate" do
57
+ expect(@application_data_backup.glacier_db_archive.retrieval_status).to eq 'pending' # success response
58
+ expect(@application_data_backup.glacier_file_archives[0].retrieval_status).to eq 'pending' # success response
59
+ expect(@application_data_backup.glacier_file_archives[1].retrieval_status).to eq 'pending' # success response
60
+ expect(@application_data_backup.glacier_file_archives[2].retrieval_status).to eq 'available' # fail response
61
+ expect(@application_data_backup.glacier_file_archives[2].errors.full_messages.first).to eq 'Failed to initiate archive retrieval with: Aws::Glacier::Errors::BadRequest: '
62
+ expect(@application_data_backup.errors.full_messages.first).to eq 'Failed to initiate archive retrieval with: Aws::Glacier::Errors::BadRequest: '
63
+ expect(@application_data_backup.retrieval_status).to eq 'available'
64
+ expect(aws_log).to match /Failed to initiate archive retrieval with: Aws::Glacier::Errors::BadRequest:/
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "ApplicationDataBackup#fetch" do
70
+ include HttpMockHelpers
71
+ include DummyAppDb
72
+ include AwsHelper
73
+ context "when retrieval job ids are current" do
74
+ before do
75
+ create_application_data_backup_with_ready_components
76
+ FakeModel.destroy_all
77
+ @application_data_backup.fetch_archive
78
+ end
79
+
80
+ it "should report aggregate status" do
81
+ expect(fetch_db_archive_retrieval_job_output).to have_been_requested.once
82
+ expect(fetch_file_archive_retrieval_job_output).to have_been_requested.times(3)
83
+ expect(@application_data_backup.retrieval_status).to eq "local"
84
+ expect(File.exists?(@application_data_backup.glacier_db_archive.backup_file)).to eq true
85
+ expect(File.exists?(@application_data_backup.glacier_file_archives[0].backup_file)).to eq true
86
+ expect(File.exists?(@application_data_backup.glacier_file_archives[1].backup_file)).to eq true
87
+ expect(File.exists?(@application_data_backup.glacier_file_archives[2].backup_file)).to eq true
88
+ end
89
+ end
90
+
91
+ context "when some retrieval job id has expired" do
92
+ before do
93
+ create_application_data_backup_with_ready_components
94
+ FakeModel.destroy_all
95
+ GlacierFileArchive.where(:filename => '1234abc').first.update_attributes(:archive_retrieval_job_id => 'expiredJobId')
96
+ fetch_expired_archive #setup response for expired job
97
+ @application_data_backup = ApplicationDataBackup.first
98
+ @application_data_backup.fetch_archive
99
+ end
100
+
101
+ it "does not change to local status if one of the component fetches fails with errors" do
102
+ expect(fetch_db_archive_retrieval_job_output).to have_been_requested.once
103
+ expect(fetch_file_archive_retrieval_job_output).to have_been_requested.times(2)
104
+ expect(fetch_expired_archive).to have_been_requested.once
105
+ expect(@application_data_backup.retrieval_status).to eq "available"
106
+ expect(File.exists?(@application_data_backup.glacier_db_archive.backup_file)).to eq true
107
+ expect(File.exists?(@application_data_backup.glacier_file_archives.find{|a| a.filename=="1234abc"}.backup_file)).to eq false
108
+ expect(File.exists?(@application_data_backup.glacier_file_archives.find{|a| a.filename=="4567def"}.backup_file)).to eq true
109
+ expect(File.exists?(@application_data_backup.glacier_file_archives.find{|a| a.filename=="8899bin"}.backup_file)).to eq true
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "ApplicationDataBackup#restore" do
115
+ include DummyAppDb
116
+ include HttpMockHelpers
117
+ include AwsHelper
118
+ before do
119
+ create_application_data_backup_with_local_components
120
+ @application_data_backup = ApplicationDataBackup.first
121
+ @application_data_backup.glacier_db_archive.reload # not sure why!
122
+ FakeModel.destroy_all
123
+ 8.times do |i|
124
+ FakeModel.create(:file_id => "abracadabra#{i}")
125
+ end
126
+ create_application_data_backup_with_local_components
127
+ @application_data_backup.restore
128
+ end
129
+
130
+ it "should restore database and each fetched file archive" do
131
+ expect(FakeModel.count).to eq 3
132
+ expect(Dir.glob(GlacierOnRails::Config.attached_files_directory.join('*')).length).to eq 3
133
+ expect(@application_data_backup.retrieval_status).to eq "available"
134
+ end
135
+
136
+ it "should move into the orphan_files_directory any files added since the application_data_backup being restored" do
137
+ expect(Dir.glob(GlacierOnRails::Config.orphan_files_directory.join('*')).length).to eq 8
138
+ end
139
+
140
+ it "should delete the fetched backup files" do
141
+ expect(Dir.glob( GlacierArchive::BackupFileDir.join('*')).length).to eq 9 # it leaves in place the files that were not restored
142
+ end
143
+
144
+ it "should retain and not overwrite application_data_backups table" do
145
+ expect(ApplicationDataBackup.count).to eq 2
146
+ end
147
+
148
+ it "should retain and not overwrite glacier_archives table" do
149
+ expect(GlacierDbArchive.count).to eq 2
150
+ expect(GlacierFileArchive.count).to eq 11
151
+ end
152
+ end
153
+
154
+ describe '#pick_lowest' do
155
+ before do
156
+ @app_db = ApplicationDataBackup.new
157
+ end
158
+
159
+ it "should pick the lowest status according as the earliest in the archive lifecycle" do
160
+ # just try some random combinations!
161
+ expect(@app_db.send(:pick_lowest, ["ready", "available", "local"])).to eq "available"
162
+ expect(@app_db.send(:pick_lowest, ["local", "ready", "available"])).to eq "available"
163
+ expect(@app_db.send(:pick_lowest, ["exists", "exists", "local"])).to eq "local"
164
+ expect(@app_db.send(:pick_lowest, ["pending", "exists", "ready"])).to eq "pending"
165
+ expect(@app_db.send(:pick_lowest, ["pending", "available", "ready"])).to eq "available"
166
+ end
167
+ end
168
+
169
+ describe '#retrieval_status' do
170
+ context "components have identical retrieval_status" do
171
+ before do
172
+ @application_data_backup = ApplicationDataBackup.new
173
+ allow_any_instance_of(GlacierFileArchive).to receive(:retrieval_status).and_return('pending')
174
+ allow_any_instance_of(GlacierDbArchive).to receive(:retrieval_status).and_return('pending')
175
+ allow(@application_data_backup).to receive(:glacier_file_archives).and_return([GlacierFileArchive.new(:filename => 'abc123')])
176
+ allow(@application_data_backup).to receive(:glacier_db_archive).and_return(GlacierDbArchive.new(:filename => GlacierDbArchive.filename_from_time))
177
+ end
178
+
179
+ it "should return pending for application_data_backup#retrieval_status" do
180
+ expect(@application_data_backup.retrieval_status).to eq 'pending'
181
+ end
182
+ end
183
+
184
+ context "components have disparate retrieval_status" do
185
+ before do
186
+ @application_data_backup = ApplicationDataBackup.new
187
+ allow_any_instance_of(GlacierFileArchive).to receive(:retrieval_status).and_return('pending')
188
+ allow_any_instance_of(GlacierDbArchive).to receive(:retrieval_status).and_return('ready')
189
+ allow(@application_data_backup).to receive(:glacier_file_archives).and_return([GlacierFileArchive.new(:filename => 'abc123')])
190
+ allow(@application_data_backup).to receive(:glacier_db_archive).and_return(GlacierDbArchive.new(:filename => GlacierDbArchive.filename_from_time))
191
+ end
192
+
193
+ it "should return pending for application_data_backup#retrieval_status" do
194
+ expect(@application_data_backup.retrieval_status).to eq 'pending'
195
+ end
196
+ end
197
+ end
198
+
199
+ describe '#destroy' do
200
+ include HttpMockHelpers
201
+ include DummyAppDb
202
+ include AwsHelper
203
+
204
+ context "glacier_file_archives do not belong to any other application_data_backups" do
205
+ before do
206
+ create_application_data_backup_with_ready_components
207
+ end
208
+
209
+ it "should destroy all associated archives" do
210
+ expect{@application_data_backup.destroy}.to change{ GlacierDbArchive.count }.from(1).to(0).
211
+ and change{ GlacierFileArchive.count }.from(3).to(0)
212
+ end
213
+ end
214
+
215
+ context "glacier_file_archives also belong to other application_data_backups" do
216
+ before do
217
+ create_application_data_backup_with_ready_components
218
+ create_application_data_backup_with_ready_components
219
+ end
220
+
221
+ it "should not destroy associated archives that also belong to another application_data_backup" do
222
+ expect{@application_data_backup.destroy}.to change{ GlacierDbArchive.count }.from(2).to(1)
223
+ expect( GlacierFileArchive.count ).to eq 3
224
+ end
225
+ end
226
+ end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+
3
+ describe '.list' do
4
+ include DummyAppDb
5
+ it "should list filenames" do
6
+ expect(ApplicationFile.list).to match_array ['1234abc', '4567def', '8899bin']
7
+ end
8
+ end
@@ -0,0 +1,118 @@
1
+ require 'spec_helper'
2
+ # helpers are all required in spec helper
3
+
4
+
5
+ describe 'GlacierDbArchive.create' do
6
+ include HttpMockHelpers
7
+ include AwsHelper
8
+
9
+ before do
10
+ @archive = GlacierDbArchive.create
11
+ end
12
+
13
+ it 'should create instance of GlacierDbArchive in the database' do
14
+ expect(upload_archive_post).to have_been_requested.once
15
+
16
+ expect(@archive.archive_id).not_to be_nil
17
+ expect(@archive.checksum).not_to be_nil
18
+ expect(@archive.location).not_to be_nil
19
+ expect(@archive.retrieval_status).to eq 'available'
20
+ end
21
+ end
22
+
23
+ describe 'GlacierDbArchive.create with error' do
24
+ include HttpMockHelpers
25
+ include AwsHelper
26
+
27
+ before do
28
+ upload_archive_post_with_error_response
29
+ @archive = GlacierDbArchive.create
30
+ end
31
+
32
+ it 'should not create instance of GlacierDbArchive in the database' do
33
+ expect(upload_archive_post_with_error_response).to have_been_requested.once
34
+ expect(aws_log).to match /Failed to create archive with: Aws::Glacier::Errors::InvalidParameterValueException: Invalid Content-Length: 0/
35
+
36
+ expect(@archive.id).to be_nil
37
+ expect(@archive.errors.full_messages[0]).to eq "Failed to create archive with: Aws::Glacier::Errors::InvalidParameterValueException: Invalid Content-Length: 0"
38
+ end
39
+ end
40
+
41
+ describe GlacierOnRails::AwsSnsSubscriptionsController, :type => :controller do
42
+ include HttpMockHelpers
43
+ include AwsHelper
44
+
45
+ routes { GlacierOnRails::Engine.routes }
46
+
47
+ before do
48
+ @archive = GlacierDbArchive.create
49
+ end
50
+
51
+ it "should send archive retrieval job initiation request" do
52
+ expect(@archive.reload.retrieval_status).to eq 'available'
53
+ @archive.initiate_retrieve_job
54
+ expect(initiate_retrieve_job).to have_been_requested.once
55
+ expect(@archive.retrieval_status).to eq 'pending'
56
+ end
57
+
58
+ it "should change status to ready when notification is received" do
59
+ @archive.initiate_retrieve_job
60
+ expect(@archive.retrieval_status).to eq 'pending'
61
+ receive_notification
62
+ expect(@archive.reload.retrieval_status).to eq 'ready'
63
+ end
64
+
65
+ end
66
+
67
+ describe GlacierOnRails::ApplicationDataBackupsController, :type => :controller do
68
+ include HttpMockHelpers
69
+ include AwsHelper
70
+ routes { GlacierOnRails::Engine.routes }
71
+
72
+ context "when archive retrieval job is fresh" do
73
+ before do
74
+ @archive = GlacierDbArchive.create(:notification => "got a notification", :archive_retrieval_job_id => "validJobId")
75
+ end
76
+
77
+ it "should retrieve the archive" do
78
+ expect(@archive.fetch_archive).to eq true
79
+ expect(@archive.notification).to be_nil
80
+ expect(@archive.archive_retrieval_job_id).to be_nil
81
+ expect(@archive.retrieval_status).to eq 'local'
82
+ end
83
+ end
84
+
85
+ context "when archive retrieval job has expired" do
86
+ before do
87
+ fetch_expired_archive # set up the webmock stub
88
+ @archive = GlacierDbArchive.create(:notification => "got a notification", :archive_retrieval_job_id => "expiredJobId")
89
+ end
90
+
91
+ it "should return to available status" do
92
+ expect(@archive.fetch_archive).to eq false
93
+ expect(fetch_expired_archive).to have_been_requested.once
94
+ expect(aws_log).to match /Fetch archive failed with: Aws::Glacier::Errors::ResourceNotFoundException: The job ID was not found/
95
+ expect(@archive.notification).to be_nil
96
+ expect(@archive.archive_retrieval_job_id).to be_nil
97
+ expect(@archive.retrieval_status).to eq 'available'
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ describe "GlacierDbArchive#restore" do
104
+ include HttpMockHelpers
105
+ include AwsHelper
106
+
107
+ before do
108
+ @archive = GlacierDbArchive.create(:notification => "got a notification", :archive_retrieval_job_id => "validJobId")
109
+ create_compressed_archive(@archive)
110
+ change_database
111
+ @archive.restore
112
+ end
113
+
114
+ it "should restore the database" do
115
+ expect(ActiveRecord::Base.connection.execute("select * from test").first["foo"]).to eq 'bar'
116
+ end
117
+
118
+ end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'GlacierFileArchive.all!' do
4
+ include HttpMockHelpers
5
+ include AwsHelper
6
+ include DummyAppDb
7
+ before do
8
+ GlacierFileArchive.all!
9
+ end
10
+
11
+ it "should create an archive for each file attachment" do
12
+ # just verifying FakeModel here!
13
+ expect(File.exists?(FakeModel::FilePath.join('1234abc'))).to eq true
14
+ expect(File.exists?(FakeModel::FilePath.join('4567def'))).to eq true
15
+ expect(File.exists?(FakeModel::FilePath.join('8899bin'))).to eq true
16
+ expect(GlacierFileArchive.pluck(:filename)).to match_array ['1234abc', '4567def', '8899bin']
17
+ end
18
+
19
+ it "should add new files" do
20
+ FakeModel.create(:file_id => '6666zyx')
21
+ expect(GlacierFileArchive.pluck(:filename)).to match_array ['1234abc', '4567def', '8899bin']
22
+ GlacierFileArchive.all!
23
+ expect(GlacierFileArchive.pluck(:filename)).to match_array ['1234abc', '4567def', '8899bin', '6666zyx']
24
+ end
25
+
26
+ end
27
+
28
+ describe '#initiate_retrieve_job' do
29
+ include HttpMockHelpers
30
+ context "when file does not exist in the filesystem" do
31
+ before do
32
+ FakeModel.create(:file_id => '6666zyx')
33
+ @archive = GlacierFileArchive.create(:filename => '6666zyx')
34
+ FileUtils.rm(FakeModel::FilePath.join('6666zyx'))
35
+ @archive.initiate_retrieve_job
36
+ end
37
+
38
+ it "should send a job initiation request and change status to pending" do
39
+ expect(initiate_retrieve_job).to have_been_requested.once
40
+ expect(@archive.retrieval_status).to eq 'pending'
41
+ end
42
+ end
43
+
44
+ context "when file exists in the filesystem" do
45
+ before do
46
+ FakeModel.create(:file_id => '6666zyx')
47
+ @archive = GlacierFileArchive.create(:filename => '6666zyx')
48
+ @archive.initiate_retrieve_job
49
+ end
50
+
51
+ it "should not send a job initiation request and should change status to exists" do
52
+ expect(initiate_retrieve_job).not_to have_been_requested
53
+ expect(@archive.retrieval_status).to eq 'exists'
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+ # helpers are all required in spec helper
3
+
4
+ describe "PostgresAdapter#create_object_restoral_list_omitting_exclusions" do
5
+ include HttpMockHelpers
6
+ include AwsHelper
7
+
8
+ before do
9
+ @archive = GlacierDbArchive.create(:notification => "got a notification", :archive_retrieval_job_id => "validJobId")
10
+ create_compressed_archive(@archive)
11
+ change_database
12
+ db_config = ActiveRecord::Base.configurations["test"]
13
+ postgres_adapter = ApplicationDatabase::PostgresAdapter.new(db_config)
14
+ postgres_adapter.send(:generate_object_restoral_list, @archive.backup_file)
15
+ end
16
+
17
+ it "should create intermediate file with list of objects to be restored" do
18
+ expect(File.exists?(ApplicationDatabase::PostgresAdapter::RestoreList)).to eq true
19
+ ApplicationDatabase::PostgresAdapter::RestoreExclusions.each do |table|
20
+ expect(File.read(ApplicationDatabase::PostgresAdapter::RestoreList)).not_to match /#{table}/
21
+ end
22
+ end
23
+
24
+ end
25
+
26
+ describe "PostgresAdapter#restore_from_list" do
27
+ include HttpMockHelpers
28
+ include AwsHelper
29
+
30
+ before do
31
+ @archive = GlacierDbArchive.create(:notification => "got a notification", :archive_retrieval_job_id => "validJobId")
32
+ GlacierDbArchive.create(:notification => "got a notification", :archive_retrieval_job_id => "validJobId")
33
+ create_compressed_archive(@archive)
34
+ change_database
35
+ db_config = ActiveRecord::Base.configurations["test"]
36
+ postgres_adapter = ApplicationDatabase::PostgresAdapter.new(db_config)
37
+ postgres_adapter.send(:generate_object_restoral_list, @archive.backup_file)
38
+ postgres_adapter.send(:restore_from_list, @archive.backup_file)
39
+ end
40
+
41
+ it "should create intermediate file with list of objects to be restored" do
42
+ expect(ActiveRecord::Base.connection.execute("select * from test").first["foo"]).to eq 'bar'
43
+ expect(GlacierDbArchive.count).to eq 2
44
+ end
45
+
46
+ end
@@ -0,0 +1,59 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ ENV['RAILS_ENV'] ||= 'test'
3
+ require 'byebug'
4
+
5
+ require File.expand_path('spec/dummy/config/environment')
6
+ require 'rspec/rails'
7
+ $:.unshift File.expand_path '../helpers', __FILE__
8
+ # Add additional requires below this line. Rails is not loaded until this point!
9
+
10
+ # Requires supporting ruby files with custom matchers and macros, etc, in
11
+ # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
12
+ # run as spec files by default. This means that files in spec/support that end
13
+ # in _spec.rb will both be required and run as specs, causing the specs to be
14
+ # run twice. It is recommended that you do not name files matching this glob to
15
+ # end with _spec.rb. You can configure this pattern with the --pattern
16
+ # option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
17
+ #
18
+ # The following line is provided for convenience purposes. It has the downside
19
+ # of increasing the boot-up time by auto-requiring all files in the support
20
+ # directory. Alternatively, in the individual `*_spec.rb` files, manually
21
+ # require only the support files necessary.
22
+ #
23
+ # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
24
+
25
+ # Checks for pending migrations before tests are run.
26
+ # If you are not using ActiveRecord, you can remove this line.
27
+ ActiveRecord::Migration.maintain_test_schema!
28
+
29
+ RSpec.configure do |config|
30
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
31
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
32
+
33
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
34
+ # examples within a transaction, remove the following line or assign false
35
+ # instead of true.
36
+ #
37
+ # for reasons I don't fully understand, transactional fixtures cause test failures
38
+ # when using the capybara selenium driver, so disable them here
39
+ # and use database cleaner instead!
40
+ #config.use_transactional_fixtures = true
41
+ config.use_transactional_fixtures = false
42
+
43
+ # RSpec Rails can automatically mix in different behaviours to your tests
44
+ # based on their file location, for example enabling you to call `get` and
45
+ # `post` in specs under `spec/controllers`.
46
+ #
47
+ # You can disable this behaviour by removing the line below, and instead
48
+ # explicitly tag your specs with their type, e.g.:
49
+ #
50
+ # RSpec.describe UsersController, :type => :controller do
51
+ # # ...
52
+ # end
53
+ #
54
+ # The different available types are documented in the features, such as in
55
+ # https://relishapp.com/rspec/rspec-rails/docs
56
+ config.infer_spec_type_from_file_location!
57
+
58
+ end
59
+
@@ -0,0 +1,110 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
3
+ require 'rspec/rails'
4
+ require 'byebug'
5
+ require 'webmock/rspec'
6
+ require 'capybara/poltergeist'
7
+ require 'selenium-webdriver'
8
+ include WebMock::API
9
+ require 'database_cleaner'
10
+
11
+ ENGINE_RAILS_ROOT= GlacierOnRails::Engine.root
12
+ # this is intended to be the Capistrano shared files directory.
13
+ # in development we store them in tmp
14
+ # in production it's typically at ../shared
15
+ GlacierOnRails::Engine::TempDirectory = Rails.root.join('tmp')
16
+
17
+ # Requires supporting ruby files with custom matchers and macros, etc,
18
+ # in spec/support/ and its subdirectories.
19
+ Dir[File.join(ENGINE_RAILS_ROOT, "spec/support/*.rb")].each {|f| require f }
20
+ Dir[File.join(ENGINE_RAILS_ROOT, "spec/helpers/*.rb")].each {|f| require f }
21
+
22
+ Capybara.register_driver :chrome do |app|
23
+ #caps = Selenium::WebDriver::Remote::Capabilities.chrome(
24
+ #"chromeOptions" => {
25
+ #"args" => [ "--window-size=1400,800"],
26
+ #"prefs" => {"download.default_directory" => DownloadHelpers::PATH }
27
+ #}
28
+ #)
29
+ #Capybara::Selenium::Driver.new(app, :browser => :chrome, :desired_capabilities => caps)
30
+ Capybara::Selenium::Driver.new(app, :browser => :chrome)
31
+ end
32
+
33
+
34
+ Capybara.register_driver :poltergeist do |app|
35
+ # use this configuration to show the messages between poltergeist and phantomjs
36
+ #Capybara::Poltergeist::Driver.new(app, :debug => true)
37
+ # use this configuration to enable the page.driver.debug interface
38
+ # see https://github.com/teampoltergeist/poltergeist
39
+ #Capybara::Poltergeist::Driver.new(app, :inspector => true, :timeout => 300)
40
+ Capybara::Poltergeist::Driver.new(:window_size => [1600,900])
41
+ end
42
+
43
+ if ENV["client"] =~ /(sel|ff)/i
44
+ puts "Browser: Firefox via Selenium"
45
+ Capybara.javascript_driver = :selenium
46
+ elsif ENV["client"] =~ /chr/i
47
+ puts "Browser: Chrome"
48
+
49
+ Capybara.javascript_driver = :chrome
50
+ elsif ENV["client"] =~ /ie/i
51
+ puts "Browser: IE"
52
+ CONFIGURATION FOR REMOTE TESTING OF IE
53
+ require 'capybara/rspec'
54
+
55
+
56
+ Capybara.server_port = 3010
57
+ ip = `ifconfig | grep 'inet ' | grep -v 127.0.0.1 | cut -d ' ' -f2`.strip
58
+ puts "this machine ip is #{ip}"
59
+
60
+ Capybara.app_host = "http://#{ip}:#{Capybara.server_port}"
61
+ Capybara.current_driver = :remote
62
+ Capybara.javascript_driver = :remote
63
+ Capybara.run_server = false
64
+ Capybara.remote = true
65
+
66
+ else
67
+ puts "Browser: Phantomjs via Poltergeist"
68
+
69
+ Capybara.javascript_driver = :poltergeist
70
+ end
71
+
72
+
73
+ WebMock.disable_net_connect!(allow_localhost: true)
74
+
75
+ RSpec.configure do |config|
76
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
77
+ # examples within a transaction, remove the following line or assign false
78
+ # instead of true.
79
+ # NOTE:this creates db locking problems with pg_dump, psql etc when run from within tests
80
+ #config.use_transactional_fixtures = true
81
+
82
+ # If true, the base class of anonymous controllers will be inferred
83
+ # automatically. This will be the default behavior in future versions of
84
+ # rspec-rails.
85
+ config.infer_base_class_for_anonymous_controllers = false
86
+
87
+ # Run specs in random order to surface order dependencies. If you find an
88
+ # order dependency and want to debug it, you can fix the order by providing
89
+ # the seed, which is printed after each run.
90
+ # --seed 1234
91
+ #config.order = "random"
92
+
93
+ config.mock_with :rspec do |mocks|
94
+ mocks.syntax = :expect
95
+ mocks.verify_partial_doubles = true
96
+ end
97
+
98
+ config.before(:each) do |example|
99
+ DatabaseCleaner.strategy = :truncation
100
+ DatabaseCleaner.start
101
+ end
102
+ config.after(:each) do
103
+ DatabaseCleaner.clean
104
+ FileUtils.rm Dir.glob FakeModel::FilePath.join('*')
105
+ FileUtils.rm Dir.glob GlacierArchive::BackupFileDir.join('*')
106
+ FileUtils.rm Dir.glob GlacierOnRails::Config.orphan_files_directory.join('*')
107
+ `:> #{AwsLog::LogFile}`
108
+ end
109
+
110
+ end
@@ -0,0 +1,22 @@
1
+ # thank you Thoughtbot!
2
+ # https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara
3
+ module WaitForAjax
4
+ def wait_for_ajax
5
+ earlier_version = Capybara::VERSION == "2.5.0.dev" || Capybara::VERSION.to_f <= 2.4
6
+ wait_time = earlier_version ? "default_wait_time" : "default_max_wait_time"
7
+ Timeout.timeout(Capybara.send(wait_time)) do
8
+ loop until finished_all_ajax_requests?
9
+ end
10
+ end
11
+
12
+ def finished_all_ajax_requests?
13
+ # see http://stackoverflow.com/a/3148506/451893
14
+ # this MAY change to jQuery.ajax.active in a later release
15
+ page.evaluate_script('jQuery.active').zero?
16
+ end
17
+
18
+ end
19
+
20
+ RSpec.configure do |config|
21
+ config.include WaitForAjax, type: :feature
22
+ end