usmu-s3 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,106 @@
1
+ require 'usmu/s3/s3_configuration'
2
+ require 'ostruct'
3
+
4
+ RSpec.describe Usmu::S3::S3Configuration do
5
+ let (:empty_configuration) { Usmu::S3::S3Configuration.new({}) }
6
+ let (:configuration) {
7
+ Usmu::S3::S3Configuration.new(
8
+ {
9
+ 'region' => '%env{TEST_REGION}',
10
+ 'access key' => 'replace %env{TEST_ACCESS_KEY}',
11
+ 'secret key' => 'replace %env{TEST_SECRET_KEY}',
12
+ 'bucket' => 'replace %env{TEST_BUCKET}',
13
+ }
14
+ )
15
+ }
16
+
17
+ before do
18
+ allow(ENV).to receive(:'[]').with('AWS_REGION').and_return('us-east-1')
19
+ allow(ENV).to receive(:'[]').with('AWS_ACCESS_KEY_ID').and_return('access_key_test')
20
+ allow(ENV).to receive(:'[]').with('AWS_SECRET_ACCESS_KEY').and_return('secret_key_test')
21
+ allow(ENV).to receive(:'[]').with('TEST_REGION').and_return('ap-southeast-2')
22
+ allow(ENV).to receive(:'[]').with('TEST_ACCESS_KEY').and_return('access_key_test')
23
+ allow(ENV).to receive(:'[]').with('TEST_SECRET_KEY').and_return('secret_key_test')
24
+ allow(ENV).to receive(:'[]').with('TEST_BUCKET').and_return('example.com')
25
+ end
26
+
27
+ context '#inspect' do
28
+ it 'does show class name' do
29
+ expect(configuration.inspect.start_with? '#<Usmu::S3::S3Configuration ').to eq(true)
30
+ end
31
+
32
+ it 'does show region' do
33
+ expect(configuration.inspect.match(/ region="ap-southeast-2"/)).to_not eq(nil)
34
+ end
35
+
36
+ it 'does show access_key' do
37
+ expect(configuration.inspect.match(/ access_key="replace access_key_test"/)).to_not eq(nil)
38
+ end
39
+
40
+ it "doesn't show secret_key" do
41
+ expect(configuration.inspect.match(/ secret_key="/)).to eq(nil)
42
+ end
43
+
44
+ it 'does show bucket' do
45
+ expect(configuration.inspect.match(/ bucket="replace example.com"/)).to_not eq(nil)
46
+ end
47
+ end
48
+
49
+ context '#region' do
50
+ it 'uses AWS SDK environment variables for defaults' do
51
+ expect(empty_configuration.region).to eq('us-east-1')
52
+ end
53
+
54
+ it 'replaces environment variables' do
55
+ expect(configuration.region).to eq('ap-southeast-2')
56
+ end
57
+ end
58
+
59
+ context '#access_key' do
60
+ it 'uses AWS SDK environment variables for defaults' do
61
+ expect(empty_configuration.access_key).to eq('access_key_test')
62
+ end
63
+
64
+ it 'replaces environment variables' do
65
+ expect(configuration.access_key).to eq('replace access_key_test')
66
+ end
67
+ end
68
+
69
+ context '#secret_key' do
70
+ it 'uses AWS SDK environment variables for defaults' do
71
+ expect(empty_configuration.secret_key).to eq('secret_key_test')
72
+ end
73
+
74
+ it 'replaces environment variables' do
75
+ expect(configuration.secret_key).to eq('replace secret_key_test')
76
+ end
77
+ end
78
+
79
+ context '#bucket' do
80
+ it 'has a default value of an empty string' do
81
+ expect(empty_configuration.bucket).to eq('')
82
+ end
83
+
84
+ it 'replaces environment variables' do
85
+ expect(configuration.bucket).to eq('replace example.com')
86
+ end
87
+ end
88
+
89
+ context '#substitute_env' do
90
+ it 'replaces environment variables' do
91
+ expect(empty_configuration.send :substitute_env, '%env{AWS_REGION}').to eq('us-east-1')
92
+ end
93
+
94
+ it 'replaces multiple environment variables' do
95
+ expect(empty_configuration.send :substitute_env, '%env{AWS_REGION},%env{TEST_REGION}').to eq('us-east-1,ap-southeast-2')
96
+ end
97
+ end
98
+
99
+ context '#credentials' do
100
+ it 'returns a new Aws::Credentials from it\'s settings' do
101
+ creds = OpenStruct.new {}
102
+ allow(Aws::Credentials).to receive(:new).with('access_key_test', 'secret_key_test').and_return(creds)
103
+ expect(empty_configuration.credentials).to eq(creds)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,92 @@
1
+ require 'usmu/configuration'
2
+ require 'usmu/s3/s3_configuration'
3
+ require 'usmu/s3/uploader'
4
+ require 'usmu/s3_service_mock'
5
+ require 'ostruct'
6
+
7
+ RSpec.describe Usmu::S3::Uploader do
8
+ let (:configuration) { Usmu::Configuration.from_hash({}) }
9
+ let (:s3_configuration) {
10
+ Usmu::S3::S3Configuration.new(
11
+ {
12
+ 'access key' => 'access',
13
+ 'secret key' => 'secret',
14
+ 'region' => 'us-east-1',
15
+ 'bucket' => 'bucket',
16
+ }
17
+ )
18
+ }
19
+ let (:creds) { OpenStruct.new({ access_key: 'access', secret_key: 'secret' }) }
20
+ let (:s3) { Usmu::S3ServiceMock.new([]) }
21
+ let (:uploader) { Usmu::S3::Uploader.new(configuration, s3_configuration) }
22
+
23
+ before do
24
+ expect(s3_configuration).to receive(:credentials).and_return(creds)
25
+ expect(Aws::S3::Resource).to receive(:new).with({credentials: creds, region: 'us-east-1'}).and_return(s3)
26
+ end
27
+
28
+ context '#initialize' do
29
+ it 'sets up instance variables' do
30
+ expect(uploader.send :configuration).to eq(configuration)
31
+ expect(uploader.send :bucket).to eq(s3)
32
+ expect(s3.get_bucket).to eq('bucket')
33
+ expect(uploader.send(:log).is_a? Logging::Logger).to eq(true)
34
+ expect(uploader.send(:log).name).to eq(described_class.name)
35
+ end
36
+ end
37
+
38
+ context '#push' do
39
+ it 'pushes new and updated files and deletes old files' do
40
+ expect(uploader).to receive(:push_local).with(['local.html'])
41
+ expect(uploader).to receive(:push_local).with(['updated.html'])
42
+ expect(uploader).to receive(:delete_remote).with(['remote.html'])
43
+
44
+ uploader.push({
45
+ local: ['local.html'],
46
+ updated: ['updated.html'],
47
+ remote: ['remote.html'],
48
+ })
49
+ end
50
+ end
51
+
52
+ context '#push_local' do
53
+ let (:io) { OpenStruct.new {} }
54
+
55
+ before do
56
+ allow(File).to receive(:open).with('site/local.html', 'r').and_yield(io)
57
+ end
58
+
59
+ it 'sends a request to S3 to push named files' do
60
+ expect(s3).to receive(:put_object).with({key: 'local.html', body: io})
61
+ uploader.send :push_local, ['local.html']
62
+ end
63
+
64
+ it 'logs files as they are pushed' do
65
+ uploader.send :push_local, ['local.html']
66
+ expect(@log_output.readline).to eq("SUCCESS Usmu::S3::Uploader : Uploading local.html\n")
67
+ end
68
+ end
69
+
70
+ context '#delete_remote' do
71
+ it 'sends a request to S3 to delete named files' do
72
+ expect(s3).to receive(:delete_objects).with({delete: {objects: [{key: 'remote.html'}]}})
73
+ uploader.send :delete_remote, ['remote.html']
74
+ end
75
+
76
+ it 'sends requests in batches of 1000' do
77
+ expect(s3).to receive(:delete_objects).with({delete: {objects: (0...1000).map {|f| {key: "#{f}.html"}}}})
78
+ expect(s3).to receive(:delete_objects).with({delete: {objects: (1000..1100).map {|f| {key: "#{f}.html"}}}})
79
+ uploader.send(:delete_remote, (0..1100).map {|f| "#{f}.html"})
80
+ end
81
+
82
+ it 'only sends one request if we have exactly one batch of files' do
83
+ expect(s3).to receive(:delete_objects).with({delete: {objects: (0...1000).map {|f| {key: "#{f}.html"}}}})
84
+ uploader.send(:delete_remote, (0...1000).map {|f| "#{f}.html"})
85
+ end
86
+
87
+ it 'logs files as they are deleted' do
88
+ uploader.send :delete_remote, ['remote.html']
89
+ expect(@log_output.readline).to eq("SUCCESS Usmu::S3::Uploader : Deleting remote.html\n")
90
+ end
91
+ end
92
+ end
data/spec/s3_spec.rb ADDED
@@ -0,0 +1,110 @@
1
+ require 'usmu/s3'
2
+ require 'usmu/configuration'
3
+ require 'usmu/uploader_mock'
4
+ require 'usmu/commander_mock'
5
+ require 'ostruct'
6
+
7
+ RSpec.describe Usmu::S3 do
8
+ let(:plugin) { Usmu::S3.new }
9
+ let(:commander) { Usmu::CommanderMock.new }
10
+
11
+ context '#initialize' do
12
+ it 'configures logging' do
13
+ expect(plugin.send(:log).is_a? Logging::Logger).to eq(true)
14
+ expect(plugin.send(:log).name).to eq(described_class.name)
15
+ end
16
+
17
+ it 'logs initialization' do
18
+ plugin
19
+ expect(@log_output.readline).to eq(" DEBUG Usmu::S3 : Initializing usmu-s3 v#{Usmu::S3::VERSION}\n")
20
+ end
21
+ end
22
+
23
+ context '#commands' do
24
+ let(:ui) { OpenStruct.new }
25
+
26
+ it 'logs when commands are accessed' do
27
+ plugin.commands(ui, commander)
28
+ # Discard the line from initialization
29
+ @log_output.readline
30
+ expect(@log_output.readline).to eq(" DEBUG Usmu::S3 : Adding commands from usmu-s3.\n")
31
+ end
32
+
33
+ it 'preserves the UI for later usage' do
34
+ plugin.commands(ui, commander)
35
+ expect(plugin.send :ui).to eq(ui)
36
+ end
37
+
38
+ it 'creates an "s3 deploy" command' do
39
+ plugin.commands(ui, commander)
40
+ expect(commander.get_command(:'s3 deploy')[:syntax]).to eq('usmu s3 deploy')
41
+ expect(commander.get_command(:'s3 deploy')[:description]).to eq('Deploys your website to S3')
42
+ expect(commander.get_command(:'s3 deploy')[:action].arity).to eq(-1)
43
+ end
44
+ end
45
+
46
+ context '#command_deploy' do
47
+ let(:empty_configuration) { Usmu::Configuration.from_hash({}) }
48
+ let(:configuration) {
49
+ Usmu::Configuration.from_hash(
50
+ {
51
+ 'plugin' => {
52
+ 's3' => {
53
+ 'bucket' => 'test',
54
+ },
55
+ },
56
+ }
57
+ )
58
+ }
59
+ let(:s3_configuration) { OpenStruct.new }
60
+ let(:ui) { OpenStruct.new configuration: configuration }
61
+ let(:empty_ui) { OpenStruct.new configuration: empty_configuration }
62
+ let(:differ) { OpenStruct.new get_diffs: diffs }
63
+ let(:diffs) { OpenStruct.new }
64
+ let(:uploader) { Usmu::UploaderMock.new }
65
+ let(:remote_files) { OpenStruct.new }
66
+
67
+ it 'raises an error when arguments are specified' do
68
+ expect { plugin.command_deploy(['foo']) }.to raise_error('This command does not take arguments.')
69
+ end
70
+
71
+ it 'raises an error when invalid options are specified' do
72
+ expect { plugin.command_deploy([], []) }.to raise_error('Invalid options, must be a Hash.')
73
+ end
74
+
75
+ it 'gets a DirectoryDiff and passes that to an Uploader' do
76
+ plugin.send :ui=, ui
77
+ expect(Usmu::S3::RemoteFiles).to receive(:new).with(s3_configuration).and_return(remote_files)
78
+ expect(Usmu::Deployment::DirectoryDiff).to receive(:new).with(configuration, remote_files).and_return(differ)
79
+ expect(Usmu::S3::Uploader).to receive(:new).with(configuration, s3_configuration).and_return(uploader)
80
+ expect(Usmu::S3::S3Configuration).to receive(:new).with({'bucket' => 'test'}).and_return(s3_configuration)
81
+ plugin.command_deploy
82
+ expect(uploader.diffs).to eq(diffs)
83
+ end
84
+
85
+ it 'it uses default values if not configured' do
86
+ plugin.send :ui=, empty_ui
87
+ expect(Usmu::S3::RemoteFiles).to receive(:new).with(s3_configuration).and_return(remote_files)
88
+ expect(Usmu::Deployment::DirectoryDiff).to receive(:new).with(empty_configuration, remote_files).and_return(differ)
89
+ expect(Usmu::S3::Uploader).to receive(:new).with(empty_configuration, s3_configuration).and_return(uploader)
90
+ expect(Usmu::S3::S3Configuration).to receive(:new).with({}).and_return(s3_configuration)
91
+ plugin.command_deploy
92
+ end
93
+
94
+ it 'logs progress' do
95
+ plugin.send :ui=, ui
96
+ expect(Usmu::S3::RemoteFiles).to receive(:new).with(s3_configuration).and_return(remote_files)
97
+ expect(Usmu::Deployment::DirectoryDiff).to receive(:new).with(configuration, remote_files).and_return(differ)
98
+ expect(Usmu::S3::Uploader).to receive(:new).with(configuration, s3_configuration).and_return(uploader)
99
+ expect(Usmu::S3::S3Configuration).to receive(:new).with({'bucket' => 'test'}).and_return(s3_configuration)
100
+ plugin.command_deploy
101
+
102
+ # Discard the line from initialization
103
+ @log_output.readline
104
+
105
+ expect(@log_output.readline).to eq(" INFO Usmu::S3 : Gathering information...\n")
106
+ expect(@log_output.readline).to eq(" INFO Usmu::S3 : Uploading files.\n")
107
+ expect(@log_output.readline).to eq(" INFO Usmu::S3 : Website updated successfully.\n")
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,112 @@
1
+ begin
2
+ require 'codeclimate-test-reporter'
3
+ CodeClimate::TestReporter.start
4
+ rescue LoadError
5
+ end
6
+
7
+ require 'logging'
8
+ require 'rspec/logging_helper'
9
+ require 'timeout'
10
+
11
+ Logging.init :debug, :info, :success, :warn, :error, :fatal
12
+
13
+ # This file was generated by the `rspec --init` command. Conventionally, all
14
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
15
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
16
+ # file to always be loaded, without a need to explicitly require it in any files.
17
+ #
18
+ # Given that it is always loaded, you are encouraged to keep this file as
19
+ # light-weight as possible. Requiring heavyweight dependencies from this file
20
+ # will add to the boot time of your test suite on EVERY test run, even for an
21
+ # individual file that may not need all of that loaded. Instead, consider making
22
+ # a separate helper file that requires the additional dependencies and performs
23
+ # the additional setup, and require it from the spec files that actually need it.
24
+ #
25
+ # The `.rspec` file also contains a few flags that are not defaults but that
26
+ # users commonly want.
27
+ #
28
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
29
+ RSpec.configure do |config|
30
+ # rspec-expectations config goes here. You can use an alternate
31
+ # assertion/expectation library such as wrong or the stdlib/minitest
32
+ # assertions if you prefer.
33
+ config.expect_with :rspec do |expectations|
34
+ # This option will default to `true` in RSpec 4. It makes the `description`
35
+ # and `failure_message` of custom matchers include text for helper methods
36
+ # defined using `chain`, e.g.:
37
+ # be_bigger_than(2).and_smaller_than(4).description
38
+ # # => "be bigger than 2 and smaller than 4"
39
+ # ...rather than:
40
+ # # => "be bigger than 2"
41
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
42
+ end
43
+
44
+ # rspec-mocks config goes here. You can use an alternate test double
45
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
46
+ config.mock_with :rspec do |mocks|
47
+ # Prevents you from mocking or stubbing a method that does not exist on
48
+ # a real object. This is generally recommended, and will default to
49
+ # `true` in RSpec 4.
50
+ mocks.verify_partial_doubles = true
51
+ end
52
+
53
+ # These two settings work together to allow you to limit a spec run
54
+ # to individual examples or groups you care about by tagging them with
55
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
56
+ # get run.
57
+ config.filter_run :focus
58
+ config.run_all_when_everything_filtered = true
59
+
60
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
61
+ # For more details, see:
62
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
63
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
64
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
65
+ config.disable_monkey_patching!
66
+
67
+ # This setting enables warnings. It's recommended, but in some cases may
68
+ # be too noisy due to issues in dependencies.
69
+ config.warnings = false
70
+
71
+ # Many RSpec users commonly either run the entire suite or an individual
72
+ # file, and it's useful to allow more verbose output when running an
73
+ # individual spec file.
74
+ if config.files_to_run.one?
75
+ # Use the documentation formatter for detailed output,
76
+ # unless a formatter has already been configured
77
+ # (e.g. via a command-line flag).
78
+ config.default_formatter = 'doc'
79
+ end
80
+
81
+ # Print the 10 slowest examples and example groups at the
82
+ # end of the spec run, to help surface which specs are running
83
+ # particularly slow.
84
+ config.profile_examples = 10
85
+
86
+ # Run specs in random order to surface order dependencies. If you find an
87
+ # order dependency and want to debug it, you can fix the order by providing
88
+ # the seed, which is printed after each run.
89
+ # --seed 1234
90
+ config.order = :random
91
+
92
+ # Seed global randomization in this process using the `--seed` CLI option.
93
+ # Setting this allows you to use `--seed` to deterministically reproduce
94
+ # test failures related to randomization by passing the same `--seed` value
95
+ # as the one that triggered the failure.
96
+ Kernel.srand config.seed
97
+
98
+ # Set a timeout on individual tests
99
+ config.around(:each) do |example|
100
+ Timeout.timeout(5, &example)
101
+ end
102
+
103
+ # Configure RSpec to capture log messages for tests.
104
+ include RSpec::LoggingHelper
105
+ config.capture_log_messages
106
+ end
107
+
108
+ # Load turnip step definitions
109
+ Dir['spec/**/*_steps.rb'].each {|f| require f[10..f.length] }
110
+
111
+ # Allow loading of mocks
112
+ $LOAD_PATH.unshift(File.realpath('./spec/mock')) if File.exist? 'spec/mock'
data/usmu-s3.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'usmu/s3/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'usmu-s3'
8
+ spec.version = Usmu::S3::VERSION
9
+ spec.authors = ['Matthew Scharley']
10
+ spec.email = ['matt.scharley@gmail.com']
11
+ spec.summary = %q{S3 publishing plugin for Usmu.}
12
+ spec.homepage = 'https://github.com/usmu/usmu-s3'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0")
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^spec/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.required_ruby_version = Gem::Requirement.new('>= 1.9.3')
21
+
22
+ spec.add_dependency 'usmu', '~> 0.3', '>= 0.3.4'
23
+ spec.add_dependency 'logging', '~> 1.8'
24
+ spec.add_dependency 'aws-sdk', '~> 2.0.pre', '>= 2.0.17'
25
+ #spec.add_dependency 'ruby-filemagic', '~> 0.6'
26
+
27
+ spec.add_development_dependency 'bundler', '~> 1.6'
28
+ spec.add_development_dependency 'rake', '~> 10.0'
29
+ spec.add_development_dependency 'rspec', '~> 3.1'
30
+ spec.add_development_dependency 'yard', '~> 0.8'
31
+ spec.add_development_dependency 'guard', '~> 2.8'
32
+ spec.add_development_dependency 'guard-rspec', '~> 4.3'
33
+ spec.add_development_dependency 'libnotify', '~> 0.9'
34
+ spec.add_development_dependency 'turnip', '~> 1.2'
35
+ spec.add_development_dependency 'timeout', '~> 0.0'
36
+ end