s3_rotate 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,145 @@
1
+ # standard
2
+ require 'date'
3
+
4
+ # 3rd part
5
+ require 'fog-aws'
6
+
7
+ # s3_rotate
8
+ require File.expand_path("../../../../lib/s3_rotate/core/backup_uploader", __FILE__)
9
+ require File.expand_path("../../../../lib/s3_rotate/utils/file_utils", __FILE__)
10
+
11
+ describe S3Rotate::BackupUploader do
12
+
13
+ before :each do
14
+ @client = S3Rotate::S3Client.new('key', 'secret', 'bucket', 'region')
15
+ @uploader = S3Rotate::BackupUploader.new(@client)
16
+ end
17
+
18
+ describe '#initialize' do
19
+
20
+ it 'sets the client' do
21
+ expect(@uploader.s3_client).not_to eq nil
22
+ end
23
+
24
+ end
25
+
26
+ describe '#upload' do
27
+
28
+ it 'uploads all the new files until reaching an already uploaded file' do
29
+ # mock
30
+ @client.connection.directories.get('bucket').files.create(key: '/backup_name/daily/2020-01-02.tgz', body: 'some data')
31
+ @client.connection.directories.get('bucket').files.create(key: '/backup_name/daily/2020-01-03.tgz', body: 'some data')
32
+ @client.connection.directories.get('bucket').files.create(key: '/backup_name/daily/2020-01-04.tgz', body: 'some data')
33
+ @client.connection.directories.get('bucket').files.create(key: '/backup_name/weekly/2020-01-05.tgz', body: 'some data')
34
+ @client.connection.directories.get('bucket').files.create(key: '/backup_name/monthly/2020-01-06.tgz', body: 'some data')
35
+ @client.connection.directories.get('bucket').files.create(key: '/other_backup_name/daily/2020-01-07.tgz', body: 'some data')
36
+
37
+ allow(S3Rotate::FileUtils).to receive(:date_from_filename).and_call_original
38
+ allow(S3Rotate::FileUtils).to receive(:extension_from_filename).and_call_original
39
+ allow(S3Rotate::FileUtils).to receive(:files_in_directory).with('/path/to/dir').and_return([
40
+ 'some-backup-2020-01-01.tgz',
41
+ 'some-backup-2020-01-02.tgz',
42
+ 'some-backup-2020-01-03.tgz',
43
+ 'some-backup-2020-01-04.tgz',
44
+ 'some-backup-2020-01-05.tgz',
45
+ 'some-backup-2020-01-06.tgz',
46
+ 'some-backup-2020-01-07.tgz'
47
+ ])
48
+ allow(@client).to receive(:upload_local_backup_to_s3).and_return nil
49
+ allow(File).to receive(:open).and_return "raw_data"
50
+
51
+ # perform test
52
+ @uploader.upload('backup_name', '/path/to/dir')
53
+
54
+ # verify result
55
+ expect(@client).to have_received(:upload_local_backup_to_s3).exactly(3)
56
+ expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 7), 'daily', '.tgz', 'raw_data')
57
+ expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 6), 'daily', '.tgz', 'raw_data')
58
+ expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 5), 'daily', '.tgz', 'raw_data')
59
+
60
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).exactly(4)
61
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-07.tgz', /\d{4}-\d{2}-\d{2}/)
62
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-06.tgz', /\d{4}-\d{2}-\d{2}/)
63
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-05.tgz', /\d{4}-\d{2}-\d{2}/)
64
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-04.tgz', /\d{4}-\d{2}-\d{2}/)
65
+
66
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).exactly(4)
67
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-07.tgz')
68
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-06.tgz')
69
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-05.tgz')
70
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-04.tgz')
71
+ end
72
+
73
+ it 'uploads files without extensions' do
74
+ # mock
75
+ allow(S3Rotate::FileUtils).to receive(:date_from_filename).and_call_original
76
+ allow(S3Rotate::FileUtils).to receive(:extension_from_filename).and_return nil
77
+ allow(S3Rotate::FileUtils).to receive(:files_in_directory).with('/path/to/dir').and_return([
78
+ 'some-backup-2020-01-01.tgz',
79
+ 'some-backup-2020-01-02.tgz',
80
+ 'some-backup-2020-01-03.tgz',
81
+ ])
82
+ allow(@client).to receive(:upload_local_backup_to_s3).and_return nil
83
+ allow(File).to receive(:open).and_return "raw_data"
84
+
85
+ # perform test
86
+ @uploader.upload('backup_name', '/path/to/dir')
87
+
88
+ # verify result
89
+ expect(@client).to have_received(:upload_local_backup_to_s3).exactly(3)
90
+ expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 3), 'daily', nil, 'raw_data')
91
+ expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 2), 'daily', nil, 'raw_data')
92
+ expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 1), 'daily', nil, 'raw_data')
93
+
94
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).exactly(3)
95
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-03.tgz', /\d{4}-\d{2}-\d{2}/)
96
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-02.tgz', /\d{4}-\d{2}-\d{2}/)
97
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-01.tgz', /\d{4}-\d{2}-\d{2}/)
98
+
99
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).exactly(3)
100
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-03.tgz')
101
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-02.tgz')
102
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-01.tgz')
103
+ end
104
+
105
+ it 'does not upload files with broken date' do
106
+ # mock
107
+ original_date_from_filename = S3Rotate::FileUtils.method(:date_from_filename)
108
+ allow(S3Rotate::FileUtils).to receive(:date_from_filename) do |filename, date_regex|
109
+ if filename == 'some-backup-2020-01-02.tgz'
110
+ nil
111
+ else
112
+ original_date_from_filename.call(filename, date_regex)
113
+ end
114
+ end
115
+ allow(S3Rotate::FileUtils).to receive(:extension_from_filename).and_call_original
116
+ allow(S3Rotate::FileUtils).to receive(:files_in_directory).with('/path/to/dir').and_return([
117
+ 'some-backup-2020-01-01.tgz',
118
+ 'some-backup-2020-01-02.tgz',
119
+ 'some-backup-2020-01-03.tgz',
120
+ ])
121
+ allow(@client).to receive(:upload_local_backup_to_s3).and_return nil
122
+ allow(File).to receive(:open).and_return "raw_data"
123
+
124
+ # perform test
125
+ @uploader.upload('backup_name', '/path/to/dir')
126
+
127
+ # verify result
128
+ expect(@client).to have_received(:upload_local_backup_to_s3).exactly(2)
129
+ expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 3), 'daily', '.tgz', 'raw_data')
130
+ expect(@client).to have_received(:upload_local_backup_to_s3).with('backup_name', Date.new(2020, 1, 1), 'daily', '.tgz', 'raw_data')
131
+
132
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).exactly(3)
133
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-03.tgz', /\d{4}-\d{2}-\d{2}/)
134
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-02.tgz', /\d{4}-\d{2}-\d{2}/)
135
+ expect(S3Rotate::FileUtils).to have_received(:date_from_filename).with('some-backup-2020-01-01.tgz', /\d{4}-\d{2}-\d{2}/)
136
+
137
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).exactly(3)
138
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-03.tgz')
139
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-02.tgz')
140
+ expect(S3Rotate::FileUtils).to have_received(:extension_from_filename).with('some-backup-2020-01-01.tgz')
141
+ end
142
+
143
+ end
144
+
145
+ end
@@ -0,0 +1,61 @@
1
+ # standard
2
+ require 'date'
3
+
4
+ # s3_rotate
5
+ require File.expand_path("../../../../lib/s3_rotate/utils/file_utils", __FILE__)
6
+
7
+ describe S3Rotate::FileUtils do
8
+
9
+ describe '#date_from_filename' do
10
+
11
+ it 'parses Date.parse formats' do
12
+ expect(S3Rotate::FileUtils::date_from_filename("/path/to/file-2020-12-13-backup.tar.gz")).to eq Date.new(2020, 12, 13)
13
+ end
14
+
15
+ it 'parses timestamp formats' do
16
+ expect(S3Rotate::FileUtils::date_from_filename("/path/to/file-1580098737-backup.tar.gz", /file-(\d+)-backup.tar.gz/)).to eq Date.new(2020, 1, 27)
17
+ end
18
+
19
+ it 'raises if the regex matched nothing' do
20
+ expect{ S3Rotate::FileUtils::date_from_filename("/path/to/file-1580098737-backup.tar.gz") }.to raise_error(RuntimeError, "Invalid date_regex or filename format")
21
+ end
22
+
23
+ it 'raises if the regex matched nothing' do
24
+ expect{ S3Rotate::FileUtils::date_from_filename("/path/to/file-1580098737-backup.tar.gz", /file-\d+-backup.tar.gz/) }.to raise_error(RuntimeError, "Date format not supported")
25
+ end
26
+
27
+ end
28
+
29
+ describe '#extension_from_filename' do
30
+
31
+ it 'handles no extension' do
32
+ expect(S3Rotate::FileUtils::extension_from_filename("backup")).to eq nil
33
+ end
34
+
35
+ it 'handles short extension' do
36
+ expect(S3Rotate::FileUtils::extension_from_filename("backup.tgz")).to eq '.tgz'
37
+ end
38
+
39
+ it 'handles long extension' do
40
+ expect(S3Rotate::FileUtils::extension_from_filename("backup.tar.gz.1")).to eq '.tar.gz.1'
41
+ end
42
+
43
+ it 'handles absolute paths' do
44
+ expect(S3Rotate::FileUtils::extension_from_filename("/path/to.file/backup.tar.gz.1")).to eq '.tar.gz.1'
45
+ end
46
+
47
+ end
48
+
49
+ describe 'files_in_directory' do
50
+
51
+ it 'returns the directory files ordered ASC' do
52
+ expect(S3Rotate::FileUtils::files_in_directory("#{__dir__}/mock")).to eq [ "backup-2020-01-02.test", "backup-2020-01-03.test", "backup-2020-02-01.test", "backup-2021-01-01.test" ]
53
+ end
54
+
55
+ it 'raises for invalid directories' do
56
+ expect{ S3Rotate::FileUtils::files_in_directory("/invalid/path") }.to raise_error(RuntimeError, "Invalid directory /invalid/path")
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,15 @@
1
+ RSpec.configure do |c|
2
+
3
+ c.before :each do
4
+ Fog.mock!
5
+
6
+ fog = Fog::Storage.new(aws_access_key_id: 'key', aws_secret_access_key: 'secret', provider: 'AWS', region: 'region')
7
+ fog.directories.create(key: 'bucket')
8
+ end
9
+
10
+ c.after :each do
11
+ Fog::Mock.reset
12
+ Fog.unmock!
13
+ end
14
+
15
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: s3_rotate
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Simon Ninon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-01-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: AWS S3 upload with rotation mechanism
14
+ email: simon.ninon@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".gitignore"
20
+ - ".rspec"
21
+ - Gemfile
22
+ - Gemfile.lock
23
+ - LICENSE
24
+ - README.md
25
+ - examples/example.rb
26
+ - lib/s3_rotate.rb
27
+ - lib/s3_rotate/aws/s3_client.rb
28
+ - lib/s3_rotate/core/backup_manager.rb
29
+ - lib/s3_rotate/core/backup_rotator.rb
30
+ - lib/s3_rotate/core/backup_uploader.rb
31
+ - lib/s3_rotate/utils/file_utils.rb
32
+ - s3_rotate.gemspec
33
+ - spec/s3_rotate/aws/s3_client_spec.rb
34
+ - spec/s3_rotate/core/backup_manager_spec.rb
35
+ - spec/s3_rotate/core/backup_rotator_spec.rb
36
+ - spec/s3_rotate/core/backup_uploader_spec.rb
37
+ - spec/s3_rotate/utils/file_utils_spec.rb
38
+ - spec/s3_rotate/utils/mock/backup-2020-01-02.test
39
+ - spec/s3_rotate/utils/mock/backup-2020-01-03.test
40
+ - spec/s3_rotate/utils/mock/backup-2020-02-01.test
41
+ - spec/s3_rotate/utils/mock/backup-2021-01-01.test
42
+ - spec/spec_helper.rb
43
+ homepage: https://github.com/Whova/s3_rotate
44
+ licenses:
45
+ - MIT
46
+ metadata: {}
47
+ post_install_message:
48
+ rdoc_options: []
49
+ require_paths:
50
+ - lib
51
+ required_ruby_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubygems_version: 3.0.1
63
+ signing_key:
64
+ specification_version: 4
65
+ summary: AWS S3 upload with rotation mechanism
66
+ test_files:
67
+ - spec/s3_rotate/aws/s3_client_spec.rb
68
+ - spec/s3_rotate/core/backup_manager_spec.rb
69
+ - spec/s3_rotate/core/backup_rotator_spec.rb
70
+ - spec/s3_rotate/core/backup_uploader_spec.rb
71
+ - spec/s3_rotate/utils/file_utils_spec.rb
72
+ - spec/s3_rotate/utils/mock/backup-2020-01-02.test
73
+ - spec/s3_rotate/utils/mock/backup-2020-01-03.test
74
+ - spec/s3_rotate/utils/mock/backup-2020-02-01.test
75
+ - spec/s3_rotate/utils/mock/backup-2021-01-01.test
76
+ - spec/spec_helper.rb