usmu-s3 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a2bf26b514877f1596619bb43c3f6a702fd26be9
4
+ data.tar.gz: d2ad7cd9958cf71e5e68a123555829d08677db50
5
+ SHA512:
6
+ metadata.gz: a040b35e4fc077cd0b82677b2efe3cc0608be03842e0890bea510af89827ee245de5425e2334a427f50673ffb37298fb7b75910116c2b9fc30bf77f272b98cc5
7
+ data.tar.gz: b05383994090614f96c6befb4d90122d0ed92d5cbcd5362d55e9c9933307a5c649c940bcd0748719d34ab8d34fc409cd5fe1ec7a975508c02aed41d2f4bca097
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile*.lock
4
+ /_yardoc/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /vendor
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,6 @@
1
+ --color
2
+ -I spec
3
+ -r turnip/rspec
4
+ --require spec_helper
5
+ --format documentation
6
+ --no-profile
data/.travis.yml ADDED
@@ -0,0 +1,33 @@
1
+ language: ruby
2
+ script: rake ci
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0
6
+ - 2.1
7
+ - 2.2
8
+ - ruby-head
9
+ - mruby-head
10
+ - rbx-2.1
11
+ - rbx-2.2
12
+ - rbx-2.3
13
+ - rbx-2.4
14
+ matrix:
15
+ include:
16
+ - rvm: jruby
17
+ - rvm: jruby
18
+ env: JRUBY_OPTS='--2.0'
19
+ - rvm: jruby-head
20
+ - rvm: jruby-head
21
+ env: JRUBY_OPTS='--2.0'
22
+ allow_failures:
23
+ - rvm: 1.9.3
24
+ - rvm: jruby
25
+ - rvm: jruby-head
26
+ - rvm: mruby-head
27
+ - rvm: rbx-2.1
28
+ - rvm: rbx-2.2
29
+ - rvm: rbx-2.3
30
+ - rvm: rbx-2.4
31
+ addons:
32
+ code_climate:
33
+ repo_token: ebb97d3c606e22753911d08f39444a86f27a7da6a40d834f94d640375615fff8
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --private --protected --default-return void -m markdown -M redcarpet -- lib/**/*.rb - README.md CHANGELOG.md
data/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Usmu S3 Upload plugin changelog
2
+
3
+ ## 1.0.0
4
+
5
+ Matthew Scharley <matt.scharley@gmail.com>
6
+
7
+ * Fix readme (fea8602d016709c089b3c8b66b6487b07ff48d05)
8
+ * Update build system from Usmu core (65487dfac5a76c8fa9011a7c5286cf2ca2b59b4d)
9
+ * Add an S3Configuration which can read from ENV (2fa8a5d44e539f89dc044c8821ee10e45769d19c)
10
+ * Add gemnasium badge (0e7e2b74b143dd0ac54c38335aef7cf964783dfa)
11
+ * Add spec for S3Configuration (541b1624a524482b57f24b4213792176af480c41)
12
+ * Add Code Coverage (a6b7617b5be714fc1a8fefcaf23f72a6304cfc1d)
13
+ * Convert to Code Climate's coverage data (992c27a773de91034b054a2e3c6c80636c4ef147)
14
+ * Include the AWS SDK and update configuration to use their env vars (4d6a342050eab38f1a2dfbb7db7ac659bf1c5b5e)
15
+ * Add mutant (943c29c358341ae4cb498d6c7e0d3ac7e20cfe3d)
16
+ * Prepare for the deployment API (57c05d4c30b53e62598cdca89897b133b84acbaa)
17
+ * Update coverage for S3Configuration (26287e6089b1071f375adbb793524bbae9d563cb)
18
+ * Tests for completed sections of Usmu::S3 (2c6c9966a6274378efa606b4183c0c819aceb5dd)
19
+ * Add a RemoteFileInterface implementation (d92ee043bf1a1e093927b4930523c7bc4690c770)
20
+ * Add support for uploading to S3 (4f07cd33f7b79f1ecb7cc6b6a00431df99284d1a)
21
+ * Complete 100% mutant test coverage (a1fac102bf7caa7a00fed8a79e54c3a527234efd)
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,7 @@
1
+ # Contributing to usmu
2
+
3
+ 1. Fork it
4
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
5
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
6
+ 4. Push to the branch (`git push origin my-new-feature`)
7
+ 5. Create a new Pull Request
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in usmu.gemspec
4
+ gemspec name: 'usmu-s3'
5
+
6
+ gem 'codeclimate-test-reporter', group: :test, require: nil
7
+
8
+ if RUBY_VERSION.to_f >= 2 && RUBY_VERSION.to_f < 2.2 && RUBY_ENGINE == 'ruby'
9
+ gem 'mutant', '~> 0.7'
10
+ gem 'mutant-rspec', '~> 0.7'
11
+ end
data/Guardfile ADDED
@@ -0,0 +1,13 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec, cmd: 'rspec', spec_paths: ['spec'] do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/usmu/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
7
+ watch(%r{^spec/support}) { 'spec' }
8
+ watch('spec/spec_helper.rb') { 'spec' }
9
+
10
+ # Turnip features and steps
11
+ watch(%r{^spec/acceptance/(.+)\.feature$})
12
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
13
+ end
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Matthew Scharley and contributors
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # usmu-s3
2
+
3
+ [![Build Status](https://travis-ci.org/usmu/usmu-s3.svg?branch=master)](https://travis-ci.org/usmu/usmu-s3)
4
+ [![Dependency Status](https://gemnasium.com/usmu/usmu-s3.svg)](https://gemnasium.com/usmu/usmu-s3)
5
+ [![Code Climate](https://codeclimate.com/github/usmu/usmu-s3/badges/gpa.svg)](https://codeclimate.com/github/usmu/usmu-s3)
6
+
7
+ **Source:** [https://github.com/usmu/usmu-s3](https://github.com/usmu/usmu-s3)
8
+ **Author:** Matthew Scharley
9
+ **Contributors:** [See contributors on GitHub][gh-contrib]
10
+ **Bugs/Support:** [Github Issues][gh-issues]
11
+ **Copyright:** 2014
12
+ **License:** [MIT license][license]
13
+ **Status:** Active
14
+
15
+ ## Synopsis
16
+
17
+ Allows you to deploy your [Usmu][usmu] website to Amazon's S3 service.
18
+
19
+ TODO: Write synopsis here
20
+
21
+ ## Installation
22
+
23
+ $ gem install usmu-s3
24
+
25
+ ## Usage
26
+
27
+ TODO: Write usage instructions here
28
+
29
+ [gh-contrib]: https://github.com/usmu/usmu-s3/graphs/contributors
30
+ [gh-issues]: https://github.com/usmu/usmu-s3/issues
31
+ [license]: https://github.com/usmu/usmu-s3/blob/master/LICENSE.md
32
+ [usmu]: https://github.com/usmu/usmu
data/Rakefile ADDED
@@ -0,0 +1,92 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+
4
+ require 'rspec/core/rake_task'
5
+ require 'usmu/s3/version'
6
+
7
+ def current_gems
8
+ Dir["pkg/usmu-s3-#{Usmu::S3::VERSION}*.gem"]
9
+ end
10
+
11
+ RSpec::Core::RakeTask.new(:spec) do |t|
12
+ t.pattern = 'spec/**/*_spec.rb'
13
+ end
14
+
15
+ desc 'Run all test scripts'
16
+ task :test => [:clean, :spec, :mutant]
17
+
18
+ desc 'Run mutation tests'
19
+ task :mutant, [:target] => [:clean] do |t,args|
20
+ old = ENV.delete('CODECLIMATE_REPO_TOKEN')
21
+ if `which mutant 2>&1 > /dev/null; echo \$?`.to_i != 0
22
+ puts 'Mutant isn\'t supported on your platform. Please run these tests on MRI <= 2.1.5.'
23
+ else
24
+ sh('bundle', 'exec', 'mutant', '--include', 'lib', '--require', 'usmu/s3', '--use', 'rspec', args[:target] || 'Usmu::S3*')
25
+ end
26
+ ENV['CODECLIMATE_REPO_TOKEN'] = old unless old.nil?
27
+ end
28
+
29
+ desc 'Run CI test suite'
30
+ task :ci => [:clean, :spec]
31
+
32
+ desc 'Clean up after tests'
33
+ task :clean do
34
+ [
35
+ 'test/coverage',
36
+ current_gems,
37
+ ].flatten.each do |f|
38
+ rm_r f if File.exist? f
39
+ end
40
+ end
41
+
42
+ namespace :gem do
43
+ desc 'Build gems'
44
+ task :build => [:clean] do
45
+ mkdir 'pkg' unless File.exist? 'pkg'
46
+ Dir['*.gemspec'].each do |gemspec|
47
+ sh "gem build #{gemspec}"
48
+ end
49
+ Dir['*.gem'].each do |gem|
50
+ mv gem, "pkg/#{gem}"
51
+ end
52
+ end
53
+
54
+ desc 'Install gem'
55
+ task :install => ['gem:build'] do
56
+ sh "gem install pkg/usmu-s3-#{Usmu::S3::VERSION}.gem"
57
+ end
58
+
59
+ desc 'Deploy gems to rubygems'
60
+ task :deploy => ['gem:build'] do
61
+ current_gems.each do |gem|
62
+ sh "gem push #{gem}"
63
+ end
64
+ sh "git tag #{Usmu::S3::VERSION}" if File.exist? '.git'
65
+ end
66
+ end
67
+
68
+ # (mostly) borrowed from: https://gist.github.com/mcansky/802396
69
+ desc 'generate changelog with nice clean output'
70
+ task :changelog, :since_c, :until_c do |t,args|
71
+ since_c = args[:since_c] || `git tag | egrep '^[0-9]+\\.[0-9]+\\.[0-9]+\$' | sort -Vr | head -n 1`.chomp
72
+ until_c = args[:until_c]
73
+ cmd=`git log --pretty='format:%ci::::%an <%ae>::::%s::::%H' #{since_c}..#{until_c}`
74
+
75
+ entries = Hash.new
76
+ changelog_content = "\#\# #{Usmu::S3::VERSION}\n\n"
77
+
78
+ cmd.lines.each do |entry|
79
+ date, author, subject, hash = entry.chomp.split('::::')
80
+ entries[author] = Array.new unless entries[author]
81
+ day = date.split(' ').first
82
+ entries[author] << "#{subject} (#{hash})" unless subject =~ /Merge/
83
+ end
84
+
85
+ # generate clean output
86
+ entries.keys.each do |author|
87
+ changelog_content += author + "\n\n"
88
+ entries[author].reverse.each { |entry| changelog_content += "* #{entry}\n" }
89
+ end
90
+
91
+ puts changelog_content
92
+ end
@@ -0,0 +1,46 @@
1
+ require 'usmu/deployment/remote_file_interface'
2
+ require 'aws-sdk'
3
+
4
+ module Usmu
5
+ class S3
6
+ class RemoteFiles
7
+ include Usmu::Deployment::RemoteFileInterface
8
+
9
+ # @param [Usmu::S3::Configuration] configuration
10
+ # An S3 configuration to provide connection details to the remote S3 bucket.
11
+ def initialize(configuration)
12
+ @s3 = Aws::S3::Resource.new(credentials: configuration.credentials, region: configuration.region)
13
+ @bucket = @s3.bucket(configuration.bucket)
14
+ end
15
+
16
+ # @see Usmu::Deployment::RemoteFileInterface#files_list
17
+ def files_list
18
+ objects.map {|o| o.key }
19
+ end
20
+
21
+ # @see Usmu::Deployment::RemoteFileInterface#stat
22
+ def stat(filename)
23
+ obj = objects.select {|o| o.key.eql? filename }.first
24
+ return nil if obj.nil?
25
+
26
+ etag = unless obj.etag.index('-')
27
+ obj.etag.gsub(/^["]|["]$/, '')
28
+ end
29
+
30
+ {
31
+ md5: etag,
32
+ mtime: obj.last_modified,
33
+ }
34
+ end
35
+
36
+ private
37
+
38
+ attr_reader :s3
39
+ attr_reader :bucket
40
+
41
+ def objects
42
+ @objects ||= @bucket.objects.to_a
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,41 @@
1
+ require 'aws-sdk'
2
+
3
+ module Usmu
4
+ class S3
5
+ class S3Configuration
6
+ def initialize(hash)
7
+ @config = hash
8
+ end
9
+
10
+ def region
11
+ substitute_env(@config['region'] || '%env{AWS_REGION}')
12
+ end
13
+
14
+ def access_key
15
+ substitute_env(@config['access key'] || '%env{AWS_ACCESS_KEY_ID}')
16
+ end
17
+
18
+ def secret_key
19
+ substitute_env(@config['secret key'] || '%env{AWS_SECRET_ACCESS_KEY}')
20
+ end
21
+
22
+ def bucket
23
+ substitute_env @config['bucket'] || ''
24
+ end
25
+
26
+ def inspect
27
+ "\#<#{self.class} region=\"#{region}\" access_key=\"#{access_key}\" bucket=\"#{bucket}\">"
28
+ end
29
+
30
+ def credentials
31
+ @credentials ||= Aws::Credentials.new(access_key, secret_key)
32
+ end
33
+
34
+ private
35
+
36
+ def substitute_env(string)
37
+ string.gsub(%r[%env\{([^}]*)\}]) { ENV[$1] }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,50 @@
1
+
2
+ module Usmu
3
+ class S3
4
+ class Uploader
5
+ # @param [Usmu::Configuration] configuration
6
+ # @param [Usmu::S3::S3Configuration] s3_configuration
7
+ def initialize(configuration, s3_configuration)
8
+ @log = Logging.logger[self]
9
+ @configuration = configuration
10
+ s3 = Aws::S3::Resource.new(credentials: s3_configuration.credentials, region: s3_configuration.region)
11
+ @bucket = s3.bucket(s3_configuration.bucket)
12
+ end
13
+
14
+ def push(diff)
15
+ push_local(diff[:local])
16
+ push_local(diff[:updated])
17
+ delete_remote(diff[:remote])
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :log
23
+ attr_reader :configuration
24
+ attr_reader :bucket
25
+
26
+ def push_local(files)
27
+ for file in files
28
+ @log.success("Uploading #{file}")
29
+ File.open(File.join(@configuration.destination_path, file), 'r') do |io|
30
+ @bucket.put_object({
31
+ key: file,
32
+ body: io,
33
+ })
34
+ end
35
+ end
36
+ end
37
+
38
+ def delete_remote(files)
39
+ # We can 'only' delete 1000 items at a time with #delete_objects.
40
+ for i in (0...files.length).step(1000)
41
+ deleting = files.slice(i, 1000)
42
+ for f in deleting
43
+ @log.success("Deleting #{f}")
44
+ end
45
+ @bucket.delete_objects({delete: {objects: deleting.map { |f| {key: f} }}})
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,7 @@
1
+
2
+ module Usmu
3
+ class S3
4
+ # The current version string for the gem
5
+ VERSION = '1.0.0'
6
+ end
7
+ end
data/lib/usmu/s3.rb ADDED
@@ -0,0 +1,52 @@
1
+ %w{
2
+ aws-sdk
3
+ logging
4
+ usmu/deployment
5
+ usmu/s3/remote_files
6
+ usmu/s3/s3_configuration
7
+ usmu/s3/uploader
8
+ usmu/s3/version
9
+ }.each {|f| require f }
10
+
11
+ # Module from Usmu Core
12
+ module Usmu
13
+ # Usmu::S3 is the main plugin class for this plugin. It contains entry hooks as required to implement the S3
14
+ # deployment interface.
15
+ class S3
16
+ def initialize
17
+ @log = Logging.logger[self]
18
+ @log.debug("Initializing usmu-s3 v#{VERSION}")
19
+ end
20
+
21
+ # @see Usmu::Plugin::CoreHooks#commands
22
+ def commands(ui, c)
23
+ @log.debug('Adding commands from usmu-s3.')
24
+ @ui = ui
25
+
26
+ c.command(:'s3 deploy') do |command|
27
+ command.syntax = 'usmu s3 deploy'
28
+ command.description = 'Deploys your website to S3'
29
+ command.action &method(:command_deploy)
30
+ end
31
+ end
32
+
33
+ def command_deploy(args = [], options = {})
34
+ raise 'This command does not take arguments.' unless args.empty?
35
+ raise 'Invalid options, must be a Hash.' unless options.instance_of? Hash
36
+
37
+ configuration = @ui.configuration
38
+ s3_configuration = S3Configuration.new(configuration['plugin', 's3', default: {}])
39
+ @log.info('Gathering information...')
40
+ diff = Deployment::DirectoryDiff.new(configuration, RemoteFiles.new(s3_configuration))
41
+ @log.info('Uploading files.')
42
+ uploader = Uploader.new(configuration, s3_configuration)
43
+ uploader.push(diff.get_diffs)
44
+ @log.info('Website updated successfully.')
45
+ end
46
+
47
+ private
48
+
49
+ attr_reader :log
50
+ attr_accessor :ui
51
+ end
52
+ end
@@ -0,0 +1,31 @@
1
+
2
+ module Usmu
3
+ class CommanderMock
4
+ def initialize
5
+ @commands = {}
6
+ end
7
+
8
+ def get_command(name)
9
+ @commands[name]
10
+ end
11
+
12
+ def command(name, &block)
13
+ @current_command = name
14
+ @commands[name] = {}
15
+
16
+ block.yield(self)
17
+ end
18
+
19
+ def syntax=(value)
20
+ @commands[@current_command][:syntax] = value
21
+ end
22
+
23
+ def description=(value)
24
+ @commands[@current_command][:description] = value
25
+ end
26
+
27
+ def action(&block)
28
+ @commands[@current_command][:action] = block
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,35 @@
1
+
2
+ module Usmu
3
+ class S3ServiceMock
4
+ attr_accessor :objects
5
+
6
+ class ArrayWrapper
7
+ def initialize(objects)
8
+ @objects = objects
9
+ end
10
+
11
+ def to_a
12
+ @objects
13
+ end
14
+ end
15
+
16
+ def initialize(objects)
17
+ @objects = ArrayWrapper.new(objects)
18
+ end
19
+
20
+ def bucket(name)
21
+ @bucket = name
22
+ self
23
+ end
24
+
25
+ def get_bucket
26
+ @bucket
27
+ end
28
+
29
+ def put_object(hash)
30
+ end
31
+
32
+ def delete_objects(request)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,10 @@
1
+
2
+ module Usmu
3
+ class UploaderMock
4
+ attr_reader :diffs
5
+
6
+ def push(diffs)
7
+ @diffs = diffs
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,74 @@
1
+ require 'usmu/s3/s3_configuration'
2
+ require 'usmu/s3/remote_files'
3
+ require 'usmu/s3_service_mock'
4
+ require 'ostruct'
5
+
6
+ RSpec.describe Usmu::S3::RemoteFiles do
7
+ let(:now) { Time.now }
8
+ let(:configuration) {
9
+ Usmu::S3::S3Configuration.new(
10
+ {
11
+ 'access key' => 'access',
12
+ 'secret key' => 'secret',
13
+ 'region' => 'us-east-1',
14
+ 'bucket' => 'bucket',
15
+ }
16
+ )
17
+ }
18
+ let(:creds) { OpenStruct.new({ access_key: 'access', secret_key: 'secret' }) }
19
+ let(:s3) {
20
+ Usmu::S3ServiceMock.new(
21
+ [
22
+ OpenStruct.new({ key: 'index.html', etag: '"dffd613ea3d712d38c230c810be2e4a6"', last_modified: now }),
23
+ OpenStruct.new({ key: 'sitemap.xml', etag: '"dffd613ea3d712d38c230c810be2e4a6-5"', last_modified: now }),
24
+ ]
25
+ )
26
+ }
27
+ let(:remote) { Usmu::S3::RemoteFiles.new(configuration) }
28
+
29
+ before do
30
+ expect(configuration).to receive(:credentials).and_return(creds)
31
+ expect(Aws::S3::Resource).to receive(:new).with({credentials: creds, region: 'us-east-1'}).and_return(s3)
32
+ end
33
+
34
+ context '#initialize' do
35
+ it 'creates an S3 resource instance' do
36
+ remote
37
+ expect(remote.send :s3).to eq(s3)
38
+ end
39
+
40
+ it 'finds the relevant S3 bucket' do
41
+ remote
42
+ expect(remote.send :bucket).to eq(s3)
43
+ expect(s3.get_bucket).to eq(configuration.bucket)
44
+ end
45
+ end
46
+
47
+ context '#files_list' do
48
+ it 'returns a list of file names' do
49
+ expect(remote.files_list.sort).to eq(['index.html', 'sitemap.xml'])
50
+ end
51
+ end
52
+
53
+ context '#stat' do
54
+ it 'returns a hash of information' do
55
+ expect(remote.stat('index.html')).to eq({md5: 'dffd613ea3d712d38c230c810be2e4a6', mtime: now})
56
+ end
57
+
58
+ it 'doesn\'t return an :md5 element for multi-part uploads' do
59
+ expect(remote.stat('sitemap.xml')).to eq({md5: nil, mtime: now})
60
+ end
61
+
62
+ it 'returns nil if there is no information available' do
63
+ expect(remote.stat('jquery.js')).to eq(nil)
64
+ end
65
+ end
66
+
67
+ context '#objects' do
68
+ it 'returns a list of objects about files' do
69
+ objs = remote.send :objects
70
+ expect(objs.length).to eq(2)
71
+ expect(objs.map {|o| o.key }.sort).to eq(['index.html', 'sitemap.xml'])
72
+ end
73
+ end
74
+ end