nightcrawler_swift 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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