nightcrawler_swift 0.1.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: 4caba3693564eaec6cc72f71e1e58d34a6bf15e5
4
+ data.tar.gz: 80d45c80c658dea8d2d2607cdfbec786e30a15d7
5
+ SHA512:
6
+ metadata.gz: 7c51c55c7b98578ed99c81525da725137ffd6884d3586ca1418a596c8d04c301dabbb4f1f0b041fadbed0ccaa2b5b2554063d93bb5750eddf8bce853d7c62b31
7
+ data.tar.gz: a8f9fd8695abb24101d06c0e08993daebdbcbbab8635eaa64d86f015534359c8cb3bd575c4eb9b254538fcf524f088ff5c4b2e5dddabc5bda729d40b9e29404b
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format documentation
3
+ --require spec_helper
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ nightcrawler_swift
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.1.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nightcrawler-swift.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ nightcrawler_swift (0.1.0)
5
+ rest-client (>= 1.7.0)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ byebug (3.2.0)
11
+ columnize (~> 0.8)
12
+ debugger-linecache (~> 1.2)
13
+ columnize (0.8.9)
14
+ debugger-linecache (1.2.0)
15
+ diff-lcs (1.2.5)
16
+ mime-types (2.3)
17
+ netrc (0.7.7)
18
+ rake (10.3.2)
19
+ rest-client (1.7.2)
20
+ mime-types (>= 1.16, < 3.0)
21
+ netrc (~> 0.7)
22
+ rspec (3.0.0)
23
+ rspec-core (~> 3.0.0)
24
+ rspec-expectations (~> 3.0.0)
25
+ rspec-mocks (~> 3.0.0)
26
+ rspec-core (3.0.4)
27
+ rspec-support (~> 3.0.0)
28
+ rspec-expectations (3.0.4)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.0.0)
31
+ rspec-mocks (3.0.4)
32
+ rspec-support (~> 3.0.0)
33
+ rspec-support (3.0.4)
34
+
35
+ PLATFORMS
36
+ ruby
37
+
38
+ DEPENDENCIES
39
+ bundler (~> 1.6)
40
+ byebug
41
+ nightcrawler_swift!
42
+ rake
43
+ rspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 tulios
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,111 @@
1
+ # Nightcrawler Swift
2
+
3
+ Like the X-Men nightcrawler it teleports your assets to a OpenStack Swift bucket/container
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'nightcrawler_swift'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install nightcrawler_swift
18
+
19
+ ## Usage
20
+
21
+ ### With Rails
22
+ #### 1) You will need to configure your swift credentials
23
+
24
+ ```ruby
25
+ NightcrawlerSwift.configure({
26
+ bucket: "rogue",
27
+ tenant_name: "nightcrawler"
28
+ username: "my_username1",
29
+ password: "my_password1",
30
+ auth_url: "https://auth.url.com:123/v2.0/tokens"
31
+ })
32
+ ```
33
+
34
+ You could create an initializer with this code.
35
+
36
+ #### 2) Load rake tasks into your Rakefile
37
+
38
+ ```ruby
39
+ require 'nightcrawler_swift'
40
+ load 'nightcrawler_swift/tasks/asset_sync.rake'
41
+ ```
42
+
43
+ #### 3) Profit!
44
+
45
+ ```sh
46
+ rake nightcrawler_swift:rails:asset_sync
47
+ ```
48
+
49
+ It will invoke ```rake assets:precompile``` and will copy your public directory to swift bucket/container.
50
+
51
+ ### Programatically
52
+
53
+ #### 1) Configure
54
+
55
+ Repeat the first step of Rails guide
56
+
57
+ #### 2) Call method sync with the desired directory
58
+
59
+ ```ruby
60
+ NightcrawlerSwift.sync File.expand_path("./my-dir")
61
+ ```
62
+
63
+ ## Commands
64
+
65
+ NightcrawlerSwift packs some useful commands. All commands requires that the gem has already been configured and the connection established.
66
+
67
+ To Establish the connection, call:
68
+
69
+ ```ruby
70
+ NightcrawlerSwift.connection.connect!
71
+ ```
72
+
73
+ To check if the connection is still valid, call:
74
+
75
+ ```ruby
76
+ NightcrawlerSwift.connection.connected?
77
+ ```
78
+
79
+ To reconnect just call ```NightcrawlerSwift.connection.connect!``` again.
80
+
81
+ ### Upload
82
+
83
+ ```ruby
84
+ upload = NightcrawlerSwift::Upload.new
85
+ upload.execute "my_file_path.txt", File.open("../my_file_fullpath.txt", "r")
86
+ # true / false
87
+ ```
88
+
89
+ ### List
90
+
91
+ ```ruby
92
+ list = NightcrawlerSwift::List.new
93
+ list.execute
94
+ # [{"hash": "...", "name": "my_file_path.txt"}, {}, {}, ...]
95
+ ```
96
+
97
+ ### Delete
98
+
99
+ ```ruby
100
+ delete = NightcrawlerSwift::Delete.new
101
+ delete.execute "my_file_path.txt"
102
+ # true / false
103
+ ```
104
+
105
+ ## Contributing
106
+
107
+ 1. Fork it ( https://github.com/tulios/nightcrawler_swift/fork )
108
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
109
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
110
+ 4. Push to the branch (`git push origin my-new-feature`)
111
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,33 @@
1
+ require "date"
2
+ require "logger"
3
+ require "ostruct"
4
+ require "rest_client"
5
+ require "nightcrawler_swift/version"
6
+ require "nightcrawler_swift/exceptions"
7
+ require "nightcrawler_swift/command"
8
+ require "nightcrawler_swift/connection"
9
+ require "nightcrawler_swift/upload"
10
+ require "nightcrawler_swift/list"
11
+ require "nightcrawler_swift/delete"
12
+ require "nightcrawler_swift/sync"
13
+
14
+ module NightcrawlerSwift
15
+ class << self
16
+
17
+ attr_accessor :logger
18
+ attr_reader :connection
19
+
20
+ def logger
21
+ @logger || Logger.new(STDOUT)
22
+ end
23
+
24
+ def configure opts = {}
25
+ @connection = Connection.new opts
26
+ end
27
+
28
+ def sync dir_path
29
+ Sync.new(@connection.connect!).execute(dir_path)
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,43 @@
1
+ module NightcrawlerSwift
2
+ class Command
3
+
4
+ def connection
5
+ NightcrawlerSwift.connection
6
+ end
7
+
8
+ def execute
9
+ raise NotImplemented.new
10
+ end
11
+
12
+ protected
13
+
14
+ def get url, params = {}
15
+ prepare_params params
16
+ resource = resource_for url
17
+ resource.get(params[:headers])
18
+ end
19
+
20
+ def put url, params = {}
21
+ prepare_params params
22
+ resource = resource_for url
23
+ resource.put(params[:body], params[:headers])
24
+ end
25
+
26
+ def delete url, params
27
+ prepare_params params
28
+ resource = resource_for url
29
+ resource.delete(params[:headers])
30
+ end
31
+
32
+ private
33
+
34
+ def resource_for url
35
+ RestClient::Resource.new url, verify_ssl: false
36
+ end
37
+
38
+ def prepare_params params
39
+ params[:headers] ||= {}
40
+ params[:headers]["X-Storage-Token"] = connection.token_id
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ module NightcrawlerSwift
2
+ class Connection
3
+ attr_accessor :opts, :auth_response, :token_id, :expires_at, :admin_url, :upload_url
4
+
5
+ # Hash with: bucket, tenant_name, username, password, auth_url
6
+ #
7
+ def initialize opts = {}
8
+ @opts = OpenStruct.new opts
9
+ end
10
+
11
+ def connect!
12
+ response = RestClient.post(
13
+ opts.auth_url,
14
+ {
15
+ auth: {
16
+ tenantName: opts.tenant_name,
17
+ passwordCredentials: {username: opts.username, password: opts.password}
18
+ }
19
+ }.to_json,
20
+
21
+ content_type: :json,
22
+ accept: :json,
23
+ )
24
+
25
+ @auth_response = OpenStruct.new(JSON.parse(response.body))
26
+ @token_id = @auth_response.access["token"]["id"]
27
+ @expires_at = @auth_response.access["token"]["expires"]
28
+ @expires_at = DateTime.parse(@expires_at).to_time
29
+
30
+ @admin_url = @auth_response.access["serviceCatalog"].first["endpoints"].first["adminURL"]
31
+ @upload_url = "#{@admin_url}/#{opts.bucket}"
32
+
33
+ NightcrawlerSwift.logger.info "Connected, token_id: #{@token_id}"
34
+ self
35
+
36
+ rescue StandardError => e
37
+ raise Exceptions::ConnectionError.new(e)
38
+ end
39
+
40
+ def connected?
41
+ !self.token_id.nil? and self.expires_at > Time.now
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,16 @@
1
+ module NightcrawlerSwift
2
+ class Delete < Command
3
+
4
+ def execute path
5
+ response = delete "#{connection.upload_url}/#{path}", headers: {accept: :json }
6
+ JSON.parse(response.body)
7
+
8
+ rescue RestClient::ResourceNotFound => e
9
+ raise Exceptions::NotFoundError.new(e)
10
+
11
+ rescue StandardError => e
12
+ raise Exceptions::ConnectionError.new(e)
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module NightcrawlerSwift
2
+ module Exceptions
3
+
4
+ class BaseError < StandardError
5
+ attr_accessor :original_exception
6
+
7
+ def initialize exception
8
+ super(exception.message)
9
+ @original_exception = exception
10
+ end
11
+ end
12
+
13
+ class ConnectionError < BaseError; end
14
+ class NotFoundError < BaseError; end
15
+
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module NightcrawlerSwift
2
+ class List < Command
3
+
4
+ def execute
5
+ response = get connection.upload_url, headers: {accept: :json}
6
+ JSON.parse(response.body)
7
+
8
+ rescue RestClient::ResourceNotFound => e
9
+ raise Exceptions::NotFoundError.new(e)
10
+
11
+ rescue StandardError => e
12
+ raise Exceptions::ConnectionError.new(e)
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ module NightcrawlerSwift
2
+ class Sync < Command
3
+
4
+ def initialize
5
+ @upload = Upload.new
6
+ @logger = NightcrawlerSwift.logger
7
+ end
8
+
9
+ def execute dir_path
10
+ @logger.info "dir_path: #{dir_path}"
11
+ Dir["#{dir_path}/**/**"].each do |fullpath|
12
+ path = fullpath.gsub("#{dir_path}/", "")
13
+
14
+ unless File.directory?(fullpath)
15
+ @logger.info path
16
+ @upload.execute path, File.open(fullpath, "r")
17
+ end
18
+ end
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ require "nightcrawler_swift"
2
+
3
+ namespace :nightcrawler_swift do
4
+ namespace :rails do
5
+
6
+ desc "Synchronizes the assets"
7
+ task asset_sync: ["assets:precompile", "environment"] do
8
+ raise unless defined?(Rails)
9
+ NightcrawlerSwift.sync File.join(Rails.root, "public")
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module NightcrawlerSwift
2
+ class Upload < Command
3
+
4
+ def execute path, file
5
+ response = put "#{connection.upload_url}/#{path}", body: file.read
6
+ [200, 201].include?(response.code)
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module NightcrawlerSwift
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nightcrawler_swift/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "nightcrawler_swift"
8
+ spec.version = NightcrawlerSwift::VERSION
9
+ spec.authors = ["tulios", "roberto"]
10
+ spec.email = ["ornelas.tulio@gmail.com", "roberto.tech@gmail.com"]
11
+ spec.summary = %q{Like the X-Men nightcrawler it teleports your assets to a OpenStack Swift bucket/container}
12
+ spec.description = spec.summary
13
+ spec.homepage = "https://github.com/tulios/nightcrawler_swift"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "rest-client", ">= 1.7.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "byebug"
27
+ end
@@ -0,0 +1 @@
1
+ 1
@@ -0,0 +1 @@
1
+ 2
@@ -0,0 +1 @@
1
+ 4
@@ -0,0 +1,62 @@
1
+ {
2
+ "access" : {
3
+ "serviceCatalog" : [
4
+ {
5
+ "name" : "swift",
6
+ "endpoints_links" : [],
7
+ "type" : "object-store",
8
+ "endpoints" : [
9
+ {
10
+ "publicURL" : "http://public.url.com",
11
+ "internalURL" : "http://internal.url.com",
12
+ "adminURL" : "http://api.url.com",
13
+ "region" : "RegionOne",
14
+ "id" : "1"
15
+ }
16
+ ]
17
+ },
18
+ {
19
+ "name" : "keystone",
20
+ "endpoints_links" : [],
21
+ "type" : "identity",
22
+ "endpoints" : [
23
+ {
24
+ "publicURL" : "http://auth.url.com:123/v2.0",
25
+ "internalURL" : "https://auth.url.com:123/v2.0",
26
+ "adminURL" : "https://auth.url.com:321/v2.0",
27
+ "region" : "RegionOne",
28
+ "id" : "2"
29
+ }
30
+ ]
31
+ }
32
+ ],
33
+ "user" : {
34
+ "roles" : [
35
+ {
36
+ "name" : "swiftoperator"
37
+ }
38
+ ],
39
+ "roles_links" : [],
40
+ "name" : "User Name 1",
41
+ "id" : "3",
42
+ "username" : "username1"
43
+ },
44
+ "metadata" : {
45
+ "roles" : [
46
+ "4"
47
+ ],
48
+ "is_admin" : 0
49
+ },
50
+ "token" : {
51
+ "tenant" : {
52
+ "name" : "tenant_username1",
53
+ "id" : "5",
54
+ "description" : "some desc",
55
+ "enabled" : true
56
+ },
57
+ "issued_at" : "2014-08-25T17:53:26.667691",
58
+ "id" : "5",
59
+ "expires" : "2014-08-25T18:53:26Z"
60
+ }
61
+ }
62
+ }
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe NightcrawlerSwift::Command do
4
+
5
+ subject do
6
+ NightcrawlerSwift::Command.new
7
+ end
8
+
9
+ before do
10
+ allow(NightcrawlerSwift).to receive(:connection).and_return(connection)
11
+ allow(RestClient::Resource).to receive(:new).and_return(restclient)
12
+ end
13
+
14
+ let(:connection) { double(:connection, token_id: token) }
15
+ let(:restclient) { double(:restclient, put: response, get: response, delete: response) }
16
+ let(:response) { double(:response) }
17
+
18
+ let :url do
19
+ "http://url.com"
20
+ end
21
+
22
+ let :token do
23
+ "token"
24
+ end
25
+
26
+ describe "#get" do
27
+ let :get do
28
+ subject.send :get, url, headers: {content_type: :json}
29
+ end
30
+
31
+ it "uses url to initialize RestClient" do
32
+ get
33
+ expect(RestClient::Resource).to have_received(:new).with(url, verify_ssl: false)
34
+ end
35
+
36
+ it "sends headers with token" do
37
+ get
38
+ expect(restclient).to have_received(:get).with(content_type: :json, "X-Storage-Token" => token)
39
+ end
40
+
41
+ it "returns RestClient response" do
42
+ expect(get).to eql(response)
43
+ end
44
+ end
45
+
46
+ describe "#delete" do
47
+ let :delete do
48
+ subject.send :delete, url, headers: {content_type: :json}
49
+ end
50
+
51
+ it "uses url to initialize RestClient" do
52
+ delete
53
+ expect(RestClient::Resource).to have_received(:new).with(url, verify_ssl: false)
54
+ end
55
+
56
+ it "sends headers with token" do
57
+ delete
58
+ expect(restclient).to have_received(:delete).with(content_type: :json, "X-Storage-Token" => token)
59
+ end
60
+
61
+ it "returns RestClient response" do
62
+ expect(delete).to eql(response)
63
+ end
64
+ end
65
+
66
+ describe "#put" do
67
+ let :put do
68
+ subject.send(:put, url, body: 'content', headers: {a: 1})
69
+ end
70
+
71
+ it "returns RestClient response" do
72
+ expect(put).to eql(response)
73
+ end
74
+
75
+ it "sends body" do
76
+ put
77
+ expect(restclient).to have_received(:put).with('content', anything)
78
+ end
79
+
80
+ it "sends headers with token" do
81
+ put
82
+ expect(restclient).to have_received(:put).with(anything, {a: 1, "X-Storage-Token" => token})
83
+ end
84
+
85
+ it "uses url to initialize RestClient" do
86
+ put
87
+ expect(RestClient::Resource).to have_received(:new).with(url, verify_ssl: false)
88
+ end
89
+ end
90
+
91
+ end
@@ -0,0 +1,124 @@
1
+ require "spec_helper"
2
+
3
+ describe NightcrawlerSwift::Connection do
4
+
5
+ let :opts do
6
+ {
7
+ bucket: "my-bucket-name",
8
+ tenant_name: "tenant_username1",
9
+ username: "username1",
10
+ password: "some-pass",
11
+ auth_url: "https://auth.url.com:123/v2.0/tokens"
12
+ }
13
+ end
14
+
15
+ let :unauthorized_error do
16
+ response = OpenStruct.new(body: "error", code: 401)
17
+ RestClient::Unauthorized.new response, response.code
18
+ end
19
+
20
+ subject do
21
+ NightcrawlerSwift::Connection.new opts
22
+ end
23
+
24
+ before do
25
+ NightcrawlerSwift.logger = Logger.new(StringIO.new)
26
+ end
27
+
28
+ describe "initialization" do
29
+ it "creates the opts struct with the given values" do
30
+ expect(subject.opts).to_not be_nil
31
+ opts.keys.each do |key|
32
+ expect(subject.opts.send(key)).to eql(opts[key])
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "#connect!" do
38
+ let :auth_json do
39
+ {
40
+ auth: {
41
+ tenantName: opts[:tenant_name],
42
+ passwordCredentials: {username: opts[:username], password: opts[:password]}
43
+ }
44
+ }.to_json
45
+ end
46
+
47
+ let :auth_success_response do
48
+ path = File.join(File.dirname(__FILE__), "../..", "fixtures/auth_success.json")
49
+ OpenStruct.new(body: File.read(File.expand_path(path)))
50
+ end
51
+
52
+ let :auth_success_json do
53
+ JSON.parse(auth_success_response.body)
54
+ end
55
+
56
+ describe "when it connects" do
57
+ before do
58
+ allow(RestClient).to receive(:post).
59
+ with(opts[:auth_url], auth_json, content_type: :json, accept: :json).
60
+ and_return(auth_success_response)
61
+ end
62
+
63
+ it "stores the auth response" do
64
+ subject.connect!
65
+ expect(subject.auth_response).to_not be_nil
66
+
67
+
68
+ auth_success_json.keys.each do |key|
69
+ expect(subject.auth_response.send(key)).to eql(auth_success_json[key])
70
+ end
71
+ end
72
+
73
+ it "stores the token id" do
74
+ subject.connect!
75
+ expect(subject.token_id).to eql(auth_success_json["access"]["token"]["id"])
76
+ end
77
+
78
+ it "stores the expires_at" do
79
+ subject.connect!
80
+ expires_at = DateTime.parse(auth_success_json["access"]["token"]["expires"]).to_time
81
+ expect(subject.expires_at).to eql(expires_at)
82
+ end
83
+
84
+ it "stores the admin_url" do
85
+ subject.connect!
86
+ expect(subject.admin_url).to eql(auth_success_json["access"]["serviceCatalog"].first["endpoints"].first["adminURL"])
87
+ end
88
+
89
+ it "stores the upload_url" do
90
+ subject.connect!
91
+ expect(subject.upload_url).to eql("#{subject.admin_url}/#{opts[:bucket]}")
92
+ end
93
+
94
+ it "returns self" do
95
+ expect(subject.connect!).to eql(subject)
96
+ end
97
+ end
98
+
99
+ describe "when some error happens" do
100
+ before do
101
+ allow(RestClient).to receive(:post).
102
+ with(opts[:auth_url], auth_json, content_type: :json, accept: :json).
103
+ and_raise(unauthorized_error)
104
+ end
105
+
106
+ it "raises NightcrawlerSwift::Exceptions::ConnectionError" do
107
+ expect { subject.connect! }.to raise_error(NightcrawlerSwift::Exceptions::ConnectionError)
108
+ end
109
+ end
110
+ end
111
+
112
+ describe "#connected?" do
113
+ it "checks if token_id exists and is still valid" do
114
+ expect(subject.token_id).to be_nil
115
+ expect(subject.connected?).to be false
116
+
117
+ expires_at = DateTime.now.to_time + 11
118
+ allow(subject).to receive(:expires_at).and_return(expires_at)
119
+ allow(subject).to receive(:token_id).and_return("token")
120
+ expect(subject.connected?).to be true
121
+ end
122
+ end
123
+
124
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe NightcrawlerSwift::Delete do
4
+
5
+ subject do
6
+ NightcrawlerSwift::Delete.new
7
+ end
8
+
9
+ describe "#execute" do
10
+ let :connection do
11
+ double :connection, upload_url: "server-url"
12
+ end
13
+
14
+ let :execute do
15
+ subject.execute "file_path"
16
+ end
17
+
18
+ before do
19
+ allow(NightcrawlerSwift).to receive(:connection).and_return(connection)
20
+ allow(subject).to receive(:delete).and_return(response)
21
+ end
22
+
23
+ context "success" do
24
+ let :response do
25
+ double(:response, code: 200, body: {a: 1}.to_json)
26
+ end
27
+
28
+ it "deletes using upload url" do
29
+ execute
30
+ expect(subject).to have_received(:delete).with("server-url/file_path", headers: {accept: :json})
31
+ end
32
+
33
+ it "returns the parsed json" do
34
+ expect(execute).to eql "a" => 1
35
+ end
36
+ end
37
+
38
+ context "when the file does not exist" do
39
+ let :response do
40
+ double(:response, code: 404)
41
+ end
42
+
43
+ before do
44
+ allow(subject).to receive(:delete).and_raise(RestClient::ResourceNotFound.new(response))
45
+ end
46
+
47
+ it "raises NightcrawlerSwift::Exceptions::NotFoundError" do
48
+ expect { execute }.to raise_error NightcrawlerSwift::Exceptions::NotFoundError
49
+ end
50
+ end
51
+
52
+ context "when another error happens" do
53
+ let :response do
54
+ double(:response, code: 500)
55
+ end
56
+
57
+ before do
58
+ allow(subject).to receive(:delete).and_raise(RuntimeError.new(response))
59
+ end
60
+
61
+ it "raises NightcrawlerSwift::Exceptions::ConnectionError" do
62
+ expect { execute }.to raise_error NightcrawlerSwift::Exceptions::ConnectionError
63
+ end
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,71 @@
1
+ require "spec_helper"
2
+
3
+ describe NightcrawlerSwift::List do
4
+
5
+ subject do
6
+ NightcrawlerSwift::List.new
7
+ end
8
+
9
+ describe "#execute" do
10
+ let :connection do
11
+ double :connection, upload_url: "server-url"
12
+ end
13
+
14
+ before do
15
+ allow(NightcrawlerSwift).to receive(:connection).and_return(connection)
16
+ end
17
+
18
+ context "success" do
19
+ let :json_response do
20
+ [{"name" => "file"}]
21
+ end
22
+
23
+ let :response do
24
+ double(:response, code: 200, body: json_response.to_json)
25
+ end
26
+
27
+ before do
28
+ allow(subject).to receive(:get).and_return(response)
29
+ end
30
+
31
+ it "gets upload url" do
32
+ subject.execute
33
+ expect(subject).to have_received(:get).with(connection.upload_url, headers: {accept: :json})
34
+ end
35
+
36
+ it "returns the parsed json" do
37
+ result = subject.execute
38
+ expect(result).to eql json_response
39
+ end
40
+ end
41
+
42
+ context "when the bucket does not exist" do
43
+ let :response do
44
+ double(:response, code: 400)
45
+ end
46
+
47
+ before do
48
+ allow(subject).to receive(:get).and_raise(RestClient::ResourceNotFound.new(response))
49
+ end
50
+
51
+ it "raises NightcrawlerSwift::Exceptions::NotFoundError" do
52
+ expect { subject.execute }.to raise_error NightcrawlerSwift::Exceptions::NotFoundError
53
+ end
54
+ end
55
+
56
+ context "when another error happens" do
57
+ let :response do
58
+ double(:response, code: 500)
59
+ end
60
+
61
+ before do
62
+ allow(subject).to receive(:get).and_raise(RuntimeError.new(response))
63
+ end
64
+
65
+ it "raises NightcrawlerSwift::Exceptions::ConnectionError" do
66
+ expect { subject.execute }.to raise_error NightcrawlerSwift::Exceptions::ConnectionError
67
+ end
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+
3
+ describe NightcrawlerSwift::Sync do
4
+
5
+ subject do
6
+ NightcrawlerSwift::Sync.new
7
+ end
8
+
9
+ before do
10
+ NightcrawlerSwift.logger = Logger.new(StringIO.new)
11
+ end
12
+
13
+ describe "#execute" do
14
+
15
+ let :upload do
16
+ NightcrawlerSwift::Upload.new
17
+ end
18
+
19
+ it "executes upload command for each file of a directory" do
20
+ dir = File.expand_path(File.join(File.dirname(__FILE__), "../../fixtures/assets"))
21
+
22
+ subject.instance_variable_set(:@upload, upload)
23
+ expect(File).to receive(:open).with(File.join(dir, "ex1.txt"), "r").and_call_original
24
+ expect(File).to receive(:open).with(File.join(dir, "ex2.txt"), "r").and_call_original
25
+ expect(File).to receive(:open).with(File.join(dir, "ex3/ex4.txt"), "r").and_call_original
26
+
27
+ expect(upload).to receive(:execute).with("ex1.txt", instance_of(File))
28
+ expect(upload).to receive(:execute).with("ex2.txt", instance_of(File))
29
+ expect(upload).to receive(:execute).with("ex3/ex4.txt", instance_of(File))
30
+
31
+ subject.execute dir
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe NightcrawlerSwift::Upload do
4
+
5
+ subject do
6
+ NightcrawlerSwift::Upload.new
7
+ end
8
+
9
+ describe "#execute" do
10
+ let(:path) { "file_name" }
11
+ let(:file) { double(:file, read: "content") }
12
+
13
+ let :connection do
14
+ double :connection, upload_url: "server-url"
15
+ end
16
+
17
+ let :response do
18
+ double(:response, code: 201)
19
+ end
20
+
21
+ before do
22
+ allow(NightcrawlerSwift).to receive(:connection).and_return(connection)
23
+ allow(subject).to receive(:put).and_return(response)
24
+ end
25
+
26
+ let :execute do
27
+ subject.execute path, file
28
+ end
29
+
30
+ it "reads file content" do
31
+ execute
32
+ expect(file).to have_received(:read)
33
+ end
34
+
35
+ it "sends file content as body" do
36
+ execute
37
+ expect(subject).to have_received(:put).with(anything, body: "content")
38
+ end
39
+
40
+ it "sends to upload url with given path" do
41
+ execute
42
+ expect(subject).to have_received(:put).with("server-url/file_name", anything)
43
+ end
44
+
45
+ context "when response code is 200" do
46
+ let(:response) { double(:response, code: 200) }
47
+ it { expect(execute).to be true }
48
+ end
49
+
50
+ context "when response code is 201" do
51
+ it { expect(execute).to be true }
52
+ end
53
+
54
+ context "when response code is different than 200 or 201" do
55
+ let(:response) { double(:response, code: 500) }
56
+ it { expect(execute).to be false }
57
+ end
58
+ end
59
+
60
+ end
File without changes
@@ -0,0 +1,79 @@
1
+ require "byebug"
2
+ require "nightcrawler_swift"
3
+
4
+ # This file was generated by the `rspec --init` command. Conventionally, all
5
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
6
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
7
+ # file to always be loaded, without a need to explicitly require it in any files.
8
+ #
9
+ # Given that it is always loaded, you are encouraged to keep this file as
10
+ # light-weight as possible. Requiring heavyweight dependencies from this file
11
+ # will add to the boot time of your test suite on EVERY test run, even for an
12
+ # individual file that may not need all of that loaded. Instead, make a
13
+ # separate helper file that requires this one and then use it only in the specs
14
+ # that actually need it.
15
+ #
16
+ # The `.rspec` file also contains a few flags that are not defaults but that
17
+ # users commonly want.
18
+ #
19
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
20
+ RSpec.configure do |config|
21
+ # The settings below are suggested to provide a good initial experience
22
+ # with RSpec, but feel free to customize to your heart's content.
23
+ # These two settings work together to allow you to limit a spec run
24
+ # to individual examples or groups you care about by tagging them with
25
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
26
+ # get run.
27
+ config.filter_run :focus
28
+ config.run_all_when_everything_filtered = true
29
+
30
+ # Many RSpec users commonly either run the entire suite or an individual
31
+ # file, and it's useful to allow more verbose output when running an
32
+ # individual spec file.
33
+ if config.files_to_run.one?
34
+ # Use the documentation formatter for detailed output,
35
+ # unless a formatter has already been configured
36
+ # (e.g. via a command-line flag).
37
+ config.default_formatter = 'doc'
38
+ end
39
+
40
+ # Print the 10 slowest examples and example groups at the
41
+ # end of the spec run, to help surface which specs are running
42
+ # particularly slow.
43
+ # config.profile_examples = 10
44
+
45
+ # Run specs in random order to surface order dependencies. If you find an
46
+ # order dependency and want to debug it, you can fix the order by providing
47
+ # the seed, which is printed after each run.
48
+ # --seed 1234
49
+ config.order = :random
50
+
51
+ # Seed global randomization in this process using the `--seed` CLI option.
52
+ # Setting this allows you to use `--seed` to deterministically reproduce
53
+ # test failures related to randomization by passing the same `--seed` value
54
+ # as the one that triggered the failure.
55
+ Kernel.srand config.seed
56
+
57
+ # rspec-expectations config goes here. You can use an alternate
58
+ # assertion/expectation library such as wrong or the stdlib/minitest
59
+ # assertions if you prefer.
60
+ config.expect_with :rspec do |expectations|
61
+ # Enable only the newer, non-monkey-patching expect syntax.
62
+ # For more details, see:
63
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
64
+ expectations.syntax = :expect
65
+ end
66
+
67
+ # rspec-mocks config goes here. You can use an alternate test double
68
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
69
+ config.mock_with :rspec do |mocks|
70
+ # Enable only the newer, non-monkey-patching expect syntax.
71
+ # For more details, see:
72
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
73
+ mocks.syntax = :expect
74
+
75
+ # Prevents you from mocking or stubbing a method that does not exist on
76
+ # a real object. This is generally recommended.
77
+ mocks.verify_partial_doubles = true
78
+ end
79
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nightcrawler_swift
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - tulios
8
+ - roberto
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-08-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 1.7.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 1.7.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.6'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.6'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rspec
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: byebug
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ description: Like the X-Men nightcrawler it teleports your assets to a OpenStack Swift
85
+ bucket/container
86
+ email:
87
+ - ornelas.tulio@gmail.com
88
+ - roberto.tech@gmail.com
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - ".gitignore"
94
+ - ".rspec"
95
+ - ".ruby-gemset"
96
+ - ".ruby-version"
97
+ - Gemfile
98
+ - Gemfile.lock
99
+ - LICENSE.txt
100
+ - README.md
101
+ - Rakefile
102
+ - lib/nightcrawler_swift.rb
103
+ - lib/nightcrawler_swift/command.rb
104
+ - lib/nightcrawler_swift/connection.rb
105
+ - lib/nightcrawler_swift/delete.rb
106
+ - lib/nightcrawler_swift/exceptions.rb
107
+ - lib/nightcrawler_swift/list.rb
108
+ - lib/nightcrawler_swift/sync.rb
109
+ - lib/nightcrawler_swift/tasks/asset_sync.rake
110
+ - lib/nightcrawler_swift/upload.rb
111
+ - lib/nightcrawler_swift/version.rb
112
+ - nightcrawler_swift.gemspec
113
+ - spec/fixtures/assets/ex1.txt
114
+ - spec/fixtures/assets/ex2.txt
115
+ - spec/fixtures/assets/ex3/ex4.txt
116
+ - spec/fixtures/auth_success.json
117
+ - spec/lib/nightcrawler_swift/command_spec.rb
118
+ - spec/lib/nightcrawler_swift/connection_spec.rb
119
+ - spec/lib/nightcrawler_swift/delete_spec.rb
120
+ - spec/lib/nightcrawler_swift/list_spec.rb
121
+ - spec/lib/nightcrawler_swift/sync_spec.rb
122
+ - spec/lib/nightcrawler_swift/upload_spec.rb
123
+ - spec/lib/nightcrawler_swift_spec.rb
124
+ - spec/spec_helper.rb
125
+ homepage: https://github.com/tulios/nightcrawler_swift
126
+ licenses:
127
+ - MIT
128
+ metadata: {}
129
+ post_install_message:
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ required_rubygems_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ requirements: []
144
+ rubyforge_project:
145
+ rubygems_version: 2.2.2
146
+ signing_key:
147
+ specification_version: 4
148
+ summary: Like the X-Men nightcrawler it teleports your assets to a OpenStack Swift
149
+ bucket/container
150
+ test_files:
151
+ - spec/fixtures/assets/ex1.txt
152
+ - spec/fixtures/assets/ex2.txt
153
+ - spec/fixtures/assets/ex3/ex4.txt
154
+ - spec/fixtures/auth_success.json
155
+ - spec/lib/nightcrawler_swift/command_spec.rb
156
+ - spec/lib/nightcrawler_swift/connection_spec.rb
157
+ - spec/lib/nightcrawler_swift/delete_spec.rb
158
+ - spec/lib/nightcrawler_swift/list_spec.rb
159
+ - spec/lib/nightcrawler_swift/sync_spec.rb
160
+ - spec/lib/nightcrawler_swift/upload_spec.rb
161
+ - spec/lib/nightcrawler_swift_spec.rb
162
+ - spec/spec_helper.rb