nightcrawler_swift 0.4.0 → 0.5.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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +4 -1
- data/Changelog.md +12 -2
- data/Gemfile.lock +11 -1
- data/README.md +112 -7
- data/bin/nswift +1 -1
- data/lib/nightcrawler_swift/cli/commands/url_for.rb +9 -0
- data/lib/nightcrawler_swift/cli/formatters/basic.rb +40 -0
- data/lib/nightcrawler_swift/cli/opt_parser.rb +81 -0
- data/lib/nightcrawler_swift/cli/runner.rb +127 -0
- data/lib/nightcrawler_swift/cli.rb +16 -173
- data/lib/nightcrawler_swift/command.rb +5 -14
- data/lib/nightcrawler_swift/commands/delete.rb +4 -6
- data/lib/nightcrawler_swift/commands/download.rb +4 -6
- data/lib/nightcrawler_swift/commands/list.rb +0 -6
- data/lib/nightcrawler_swift/commands/upload.rb +1 -4
- data/lib/nightcrawler_swift/connection.rb +15 -15
- data/lib/nightcrawler_swift/exceptions.rb +2 -1
- data/lib/nightcrawler_swift/gateway.rb +68 -0
- data/lib/nightcrawler_swift/version.rb +1 -1
- data/lib/nightcrawler_swift.rb +7 -2
- data/nightcrawler_swift.gemspec +1 -0
- data/spec/lib/nightcrawler_swift/cli/commands/url_for_spec.rb +34 -0
- data/spec/lib/nightcrawler_swift/cli/formatters/basic_spec.rb +117 -0
- data/spec/lib/nightcrawler_swift/cli/opt_parser_spec.rb +135 -0
- data/spec/lib/nightcrawler_swift/{cli_spec.rb → cli/runner_spec.rb} +133 -136
- data/spec/lib/nightcrawler_swift/command_spec.rb +17 -32
- data/spec/lib/nightcrawler_swift/commands/delete_spec.rb +8 -29
- data/spec/lib/nightcrawler_swift/commands/download_spec.rb +8 -29
- data/spec/lib/nightcrawler_swift/commands/list_spec.rb +14 -44
- data/spec/lib/nightcrawler_swift/commands/upload_spec.rb +1 -8
- data/spec/lib/nightcrawler_swift/connection_spec.rb +26 -9
- data/spec/lib/nightcrawler_swift/gateway_spec.rb +139 -0
- data/spec/lib/nightcrawler_swift_spec.rb +15 -2
- data/spec/spec_helper.rb +3 -0
- metadata +31 -4
@@ -1,10 +1,16 @@
|
|
1
1
|
require "optparse"
|
2
2
|
require "json"
|
3
3
|
|
4
|
+
require "nightcrawler_swift/cli/opt_parser"
|
5
|
+
require "nightcrawler_swift/cli/runner"
|
6
|
+
require "nightcrawler_swift/cli/formatters/basic"
|
7
|
+
require "nightcrawler_swift/cli/commands/url_for"
|
8
|
+
|
4
9
|
module NightcrawlerSwift
|
5
|
-
|
10
|
+
module CLI
|
6
11
|
CONFIG_FILE = ".nswiftrc"
|
7
12
|
CACHE_FILE = ".nswift_cache"
|
13
|
+
|
8
14
|
COMMANDS = {
|
9
15
|
"list" => {
|
10
16
|
description: "Lists all files of the bucket/container. Ex: nswift list",
|
@@ -12,189 +18,27 @@ module NightcrawlerSwift
|
|
12
18
|
},
|
13
19
|
|
14
20
|
"download" => {
|
15
|
-
description: "Downloads a file by path. Format: nswift download <
|
21
|
+
description: "Downloads a file by path. Format: nswift download <swift_path> Ex: nswift download assets/robots.txt > my-robots.txt",
|
16
22
|
command: NightcrawlerSwift::Download
|
17
23
|
},
|
18
24
|
|
19
25
|
"upload" => {
|
20
|
-
description: "Uploads some file. Format: nswift upload <
|
26
|
+
description: "Uploads some file. Format: nswift upload <real_path> <swift_path> Ex: nswift upload assets/robots.txt robots.txt",
|
21
27
|
command: NightcrawlerSwift::Upload
|
22
28
|
},
|
23
29
|
|
24
30
|
"delete" => {
|
25
|
-
description: "Deletes a file by path. Format: nswift delete <
|
31
|
+
description: "Deletes a file by path. Format: nswift delete <swift_path> Ex: nswift delete robots.txt",
|
26
32
|
command: NightcrawlerSwift::Delete
|
33
|
+
},
|
34
|
+
|
35
|
+
"url-for" => {
|
36
|
+
description: "Returns the public url of an object. Format: nswift url-for <swift_path> Ex: nswift url-for robots.txt",
|
37
|
+
command: NightcrawlerSwift::CLI::UrlFor
|
27
38
|
}
|
28
39
|
}
|
29
40
|
|
30
|
-
|
31
|
-
attr_accessor :argv
|
32
|
-
|
33
|
-
def initialize argv
|
34
|
-
@argv = argv
|
35
|
-
STDOUT.sync = true
|
36
|
-
NightcrawlerSwift.logger.formatter = lambda {|severity, datetime, progname, msg| "#{msg}\n"}
|
37
|
-
end
|
38
|
-
|
39
|
-
def run
|
40
|
-
configure_default_options
|
41
|
-
parse_parameters
|
42
|
-
@command_name = argv.shift
|
43
|
-
validate_command_and_options
|
44
|
-
execute_command if @command_name
|
45
|
-
end
|
46
|
-
|
47
|
-
protected
|
48
|
-
def command_list command
|
49
|
-
array = command.new.execute
|
50
|
-
array.each {|hash| log hash["name"]}
|
51
|
-
end
|
52
|
-
|
53
|
-
def command_download command
|
54
|
-
filepath = argv.first
|
55
|
-
log command.new.execute(filepath)
|
56
|
-
end
|
57
|
-
|
58
|
-
def command_upload command
|
59
|
-
realpath = argv.shift
|
60
|
-
swiftpath = argv.shift
|
61
|
-
|
62
|
-
uploaded = command.new.execute swiftpath, File.open(File.expand_path(realpath), "r")
|
63
|
-
log(uploaded ? "success" : "failure")
|
64
|
-
end
|
65
|
-
|
66
|
-
def command_delete command
|
67
|
-
filepath = argv.first
|
68
|
-
deleted = command.new.execute(filepath).to_json
|
69
|
-
log(deleted ? "success" : "failure")
|
70
|
-
end
|
71
|
-
|
72
|
-
def user_home_dir
|
73
|
-
Dir.home
|
74
|
-
end
|
75
|
-
|
76
|
-
def log string
|
77
|
-
NightcrawlerSwift.logger.info string
|
78
|
-
end
|
79
|
-
|
80
|
-
private
|
81
|
-
def configure_default_options
|
82
|
-
@options = OpenStruct.new
|
83
|
-
@options.configured = true
|
84
|
-
@options.default_config_file = true
|
85
|
-
@options.config_file = File.expand_path(File.join(user_home_dir, CONFIG_FILE))
|
86
|
-
@options.cache_file = File.expand_path(File.join(user_home_dir, CACHE_FILE))
|
87
|
-
@options.command = nil
|
88
|
-
end
|
89
|
-
|
90
|
-
def validate_command_and_options
|
91
|
-
if @command_name.nil? or argv.nil?
|
92
|
-
log opt_parser.help
|
93
|
-
exit
|
94
|
-
end
|
95
|
-
|
96
|
-
unless options.configured
|
97
|
-
log "You must configure your swift credentials, take a look at:\n #{options.config_file}"
|
98
|
-
exit
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def config_hash
|
103
|
-
@config_hash ||= JSON.parse(File.read(options.config_file))
|
104
|
-
|
105
|
-
rescue Errno::ENOENT => e
|
106
|
-
log "No such file or directory - #{options.config_file}"
|
107
|
-
exit 1
|
108
|
-
end
|
109
|
-
|
110
|
-
def execute_command
|
111
|
-
NightcrawlerSwift.configure config_hash
|
112
|
-
connect_and_execute do
|
113
|
-
if command = COMMANDS[@command_name]
|
114
|
-
command_module = command[:command]
|
115
|
-
command_method = "command_#{@command_name}"
|
116
|
-
self.send(command_method, command_module)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
rescue Exceptions::BaseError => e
|
121
|
-
log e.message
|
122
|
-
exit 1
|
123
|
-
end
|
124
|
-
|
125
|
-
def connect_and_execute &block
|
126
|
-
path = options.cache_file
|
127
|
-
if File.exist?(path)
|
128
|
-
hash = JSON.parse File.read(path)
|
129
|
-
NightcrawlerSwift.connection.auth_response = OpenStruct.new(hash)
|
130
|
-
NightcrawlerSwift.connection.configure
|
131
|
-
end
|
132
|
-
|
133
|
-
begin
|
134
|
-
block.call
|
135
|
-
ensure
|
136
|
-
File.open(path, "w") do |f|
|
137
|
-
f.write(NightcrawlerSwift.connection.auth_response.to_h.to_json)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def parse_parameters
|
143
|
-
configure_opt_parser
|
144
|
-
opt_parser.parse!(argv)
|
145
|
-
check_rcfile if options.default_config_file
|
146
|
-
|
147
|
-
rescue OptionParser::InvalidOption => e
|
148
|
-
log e.message
|
149
|
-
exit 1
|
150
|
-
end
|
151
|
-
|
152
|
-
def configure_opt_parser
|
153
|
-
@opt_parser = OptionParser.new do |opts|
|
154
|
-
opts.banner = "nswift #{NightcrawlerSwift::VERSION}"
|
155
|
-
opts.separator "Usage: nswift command [options]"
|
156
|
-
|
157
|
-
opts.separator ""
|
158
|
-
opts.separator "commands:"
|
159
|
-
COMMANDS.keys.each do |key|
|
160
|
-
opts.separator " #{key}\t\t\t #{COMMANDS[key][:description]}"
|
161
|
-
end
|
162
|
-
|
163
|
-
opts.separator ""
|
164
|
-
opts.separator "options:"
|
165
|
-
|
166
|
-
opts.on("-c", "--config=PATH", String, "Alternative '#{CONFIG_FILE}' file") do |path|
|
167
|
-
path = File.expand_path(path.strip)
|
168
|
-
log "Using custom config file at: #{path}"
|
169
|
-
options.config_file = path
|
170
|
-
options.default_config_file = false
|
171
|
-
end
|
172
|
-
|
173
|
-
opts.on_tail("-h", "--help", "Show this message") do
|
174
|
-
log opts.help
|
175
|
-
exit
|
176
|
-
end
|
177
|
-
|
178
|
-
opts.on_tail("-v", "--version", "Show version") do
|
179
|
-
log NightcrawlerSwift::VERSION
|
180
|
-
exit
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def check_rcfile
|
186
|
-
unless File.exist?(options.config_file)
|
187
|
-
File.open(options.config_file, "w") { |f|
|
188
|
-
f.write(sample_rcfile)
|
189
|
-
}
|
190
|
-
end
|
191
|
-
|
192
|
-
if sample_rcfile == File.read(options.config_file)
|
193
|
-
options.configured = false
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
def sample_rcfile
|
41
|
+
def self.sample_rcfile
|
198
42
|
JSON.pretty_generate({
|
199
43
|
bucket: "<bucket/container name>",
|
200
44
|
tenant_name: "<tenant name>",
|
@@ -203,6 +47,5 @@ module NightcrawlerSwift
|
|
203
47
|
auth_url: "<auth url, ex: https://auth.url.com:123/v2.0/tokens>"
|
204
48
|
})
|
205
49
|
end
|
206
|
-
|
207
50
|
end
|
208
51
|
end
|
@@ -11,40 +11,31 @@ module NightcrawlerSwift
|
|
11
11
|
NightcrawlerSwift.options
|
12
12
|
end
|
13
13
|
|
14
|
+
# :nocov:
|
14
15
|
def execute
|
15
16
|
raise NotImplemented.new
|
16
17
|
end
|
18
|
+
# :nocov:
|
17
19
|
|
18
20
|
protected
|
19
21
|
|
20
22
|
def get url, params = {}
|
21
23
|
prepare_params params
|
22
|
-
|
23
|
-
resource.get(params[:headers])
|
24
|
+
Gateway.new(url).request {|r| r.get params[:headers]}
|
24
25
|
end
|
25
26
|
|
26
27
|
def put url, params = {}
|
27
28
|
prepare_params params
|
28
|
-
|
29
|
-
resource.put(params[:body], params[:headers])
|
29
|
+
Gateway.new(url).request {|r| r.put params[:body], params[:headers]}
|
30
30
|
end
|
31
31
|
|
32
32
|
def delete url, params
|
33
33
|
prepare_params params
|
34
|
-
|
35
|
-
resource.delete(params[:headers])
|
34
|
+
Gateway.new(url).request {|r| r.delete params[:headers]}
|
36
35
|
end
|
37
36
|
|
38
37
|
private
|
39
38
|
|
40
|
-
def resource_for url
|
41
|
-
RestClient::Resource.new(
|
42
|
-
url,
|
43
|
-
verify_ssl: options.verify_ssl,
|
44
|
-
timeout: options.timeout
|
45
|
-
)
|
46
|
-
end
|
47
|
-
|
48
39
|
def prepare_params params
|
49
40
|
params[:headers] ||= {}
|
50
41
|
params[:headers]["X-Storage-Token"] = connection.token_id
|
@@ -2,14 +2,12 @@ module NightcrawlerSwift
|
|
2
2
|
class Delete < Command
|
3
3
|
|
4
4
|
def execute path
|
5
|
+
if path.nil? or path.empty?
|
6
|
+
raise Exceptions::ValidationError.new "Delete command requires a path parameter"
|
7
|
+
end
|
8
|
+
|
5
9
|
response = delete "#{connection.upload_url}/#{path}", headers: {accept: :json }
|
6
10
|
[200, 201].include?(response.code)
|
7
|
-
|
8
|
-
rescue RestClient::ResourceNotFound => e
|
9
|
-
raise Exceptions::NotFoundError.new(e)
|
10
|
-
|
11
|
-
rescue StandardError => e
|
12
|
-
raise Exceptions::ConnectionError.new(e)
|
13
11
|
end
|
14
12
|
|
15
13
|
end
|
@@ -2,14 +2,12 @@ module NightcrawlerSwift
|
|
2
2
|
class Download < Command
|
3
3
|
|
4
4
|
def execute path
|
5
|
+
if path.nil? or path.empty?
|
6
|
+
raise Exceptions::ValidationError.new "Download command requires a path parameter"
|
7
|
+
end
|
8
|
+
|
5
9
|
response = get "#{connection.public_url}/#{options.bucket}/#{path}"
|
6
10
|
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
11
|
end
|
14
12
|
|
15
13
|
end
|
@@ -4,12 +4,6 @@ module NightcrawlerSwift
|
|
4
4
|
def execute
|
5
5
|
response = get connection.upload_url, headers: {accept: :json}
|
6
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
7
|
end
|
14
8
|
|
15
9
|
end
|
@@ -4,12 +4,9 @@ module NightcrawlerSwift
|
|
4
4
|
def execute path, file
|
5
5
|
content = file.read
|
6
6
|
headers = {etag: etag(content), content_type: content_type(file)}
|
7
|
-
headers.merge!(cache_control: "max-age=#{options.max_age}") if options.max_age
|
7
|
+
headers.merge!(cache_control: "public, max-age=#{options.max_age}") if options.max_age
|
8
8
|
response = put "#{connection.upload_url}/#{path}", body: content, headers: headers
|
9
9
|
[200, 201].include?(response.code)
|
10
|
-
|
11
|
-
rescue RestClient::UnprocessableEntity => e
|
12
|
-
raise Exceptions::ValidationError.new(e)
|
13
10
|
end
|
14
11
|
|
15
12
|
private
|
@@ -7,7 +7,7 @@ module NightcrawlerSwift
|
|
7
7
|
authenticate!
|
8
8
|
configure
|
9
9
|
|
10
|
-
NightcrawlerSwift.logger.debug
|
10
|
+
NightcrawlerSwift.logger.debug "[NightcrawlerSwift] Connected, token_id: #{token_id}"
|
11
11
|
self
|
12
12
|
end
|
13
13
|
|
@@ -28,24 +28,24 @@ module NightcrawlerSwift
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def authenticate!
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
}
|
35
|
-
|
36
|
-
resource = RestClient::Resource.new(
|
37
|
-
opts.auth_url,
|
38
|
-
verify_ssl: NightcrawlerSwift.options.verify_ssl,
|
39
|
-
timeout: NightcrawlerSwift.options.timeout
|
40
|
-
)
|
41
|
-
|
42
|
-
response = resource.post({ auth: auth_options }.to_json, content_type: :json, accept: :json)
|
31
|
+
url = opts.auth_url
|
32
|
+
headers = {content_type: :json, accept: :json}
|
33
|
+
response = Gateway.new(url).request {|r| r.post(auth_options.to_json, headers)}
|
43
34
|
|
44
35
|
@auth_response = OpenStruct.new(JSON.parse(response.body))
|
45
36
|
rescue StandardError => e
|
46
37
|
raise Exceptions::ConnectionError.new(e)
|
47
38
|
end
|
48
39
|
|
40
|
+
def auth_options
|
41
|
+
{
|
42
|
+
auth: {
|
43
|
+
tenantName: opts.tenant_name,
|
44
|
+
passwordCredentials: {username: opts.username, password: opts.password}
|
45
|
+
}
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
49
|
def select_token
|
50
50
|
@token_id = auth_response.access["token"]["id"]
|
51
51
|
@expires_at = auth_response.access["token"]["expires"]
|
@@ -63,9 +63,9 @@ module NightcrawlerSwift
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def configure_urls
|
66
|
-
@admin_url = @endpoints["adminURL"]
|
66
|
+
@admin_url = opts.admin_url || @endpoints["adminURL"]
|
67
|
+
@public_url = opts.public_url || @endpoints["publicURL"]
|
67
68
|
@upload_url = "#{@admin_url}/#{opts.bucket}"
|
68
|
-
@public_url = @endpoints["publicURL"]
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
@@ -5,12 +5,13 @@ module NightcrawlerSwift
|
|
5
5
|
attr_accessor :original_exception
|
6
6
|
|
7
7
|
def initialize exception
|
8
|
-
super(exception.message)
|
8
|
+
super(exception.is_a?(String) ? exception : exception.message)
|
9
9
|
@original_exception = exception
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
class ConnectionError < BaseError; end
|
14
|
+
class UnauthorizedError < ConnectionError; end
|
14
15
|
class ValidationError < ConnectionError; end
|
15
16
|
class NotFoundError < BaseError; end
|
16
17
|
class ConfigurationError < StandardError; end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module NightcrawlerSwift
|
2
|
+
class Gateway
|
3
|
+
|
4
|
+
attr_reader :resource, :attempts, :current_retry_time
|
5
|
+
|
6
|
+
RETRY_BLACKLIST = [
|
7
|
+
RestClient::Unauthorized,
|
8
|
+
RestClient::ResourceNotFound,
|
9
|
+
RestClient::UnprocessableEntity
|
10
|
+
]
|
11
|
+
|
12
|
+
def initialize url
|
13
|
+
@url = url
|
14
|
+
@attempts = 0
|
15
|
+
@current_retry_time = 1
|
16
|
+
@retries = NightcrawlerSwift.options.retries
|
17
|
+
@max_retry_time = NightcrawlerSwift.options.max_retry_time
|
18
|
+
|
19
|
+
@resource = RestClient::Resource.new(
|
20
|
+
@url,
|
21
|
+
verify_ssl: NightcrawlerSwift.options.verify_ssl,
|
22
|
+
timeout: NightcrawlerSwift.options.timeout
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def request &block
|
27
|
+
begin
|
28
|
+
@attempts += 1
|
29
|
+
block.call(resource)
|
30
|
+
|
31
|
+
rescue => e
|
32
|
+
raise e unless recoverable?(e)
|
33
|
+
wait(e) and retry
|
34
|
+
end
|
35
|
+
|
36
|
+
rescue RestClient::Unauthorized => e
|
37
|
+
raise Exceptions::UnauthorizedError.new(e)
|
38
|
+
|
39
|
+
rescue RestClient::ResourceNotFound => e
|
40
|
+
raise Exceptions::NotFoundError.new(e)
|
41
|
+
|
42
|
+
rescue RestClient::UnprocessableEntity => e
|
43
|
+
raise Exceptions::ValidationError.new(e)
|
44
|
+
|
45
|
+
rescue => e
|
46
|
+
raise Exceptions::ConnectionError.new(e)
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def log message
|
51
|
+
NightcrawlerSwift.logger.debug message
|
52
|
+
end
|
53
|
+
|
54
|
+
def recoverable? e
|
55
|
+
@retries and
|
56
|
+
!RETRY_BLACKLIST.include?(e.class) and
|
57
|
+
@attempts <= @retries
|
58
|
+
end
|
59
|
+
|
60
|
+
def wait e
|
61
|
+
number = "#{@attempts}/#{@retries}"
|
62
|
+
log "Attempt #{number} to call '#{@url}', waiting #{@current_retry_time}s and retrying. Error: #{e.message}"
|
63
|
+
sleep @current_retry_time
|
64
|
+
@current_retry_time = [@current_retry_time * 2, @max_retry_time].min
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
data/lib/nightcrawler_swift.rb
CHANGED
@@ -6,8 +6,9 @@ require "multi_mime"
|
|
6
6
|
require "rest_client"
|
7
7
|
require "nightcrawler_swift/version"
|
8
8
|
require "nightcrawler_swift/exceptions"
|
9
|
-
require "nightcrawler_swift/
|
9
|
+
require "nightcrawler_swift/gateway"
|
10
10
|
require "nightcrawler_swift/connection"
|
11
|
+
require "nightcrawler_swift/command"
|
11
12
|
require "nightcrawler_swift/commands/upload"
|
12
13
|
require "nightcrawler_swift/commands/download"
|
13
14
|
require "nightcrawler_swift/commands/list"
|
@@ -36,8 +37,12 @@ module NightcrawlerSwift
|
|
36
37
|
# - verify_ssl (optional, default: false)
|
37
38
|
# - timeout (in seconds. Optional, default: nil)
|
38
39
|
#
|
40
|
+
# - retries (default: 3)
|
41
|
+
# - max_retry_time (in seconds, default: 30)
|
42
|
+
#
|
39
43
|
def configure opts = {}
|
40
|
-
|
44
|
+
defaults = {verify_ssl: false, retries: 5, max_retry_time: 30}
|
45
|
+
@options = OpenStruct.new(defaults.merge(opts))
|
41
46
|
|
42
47
|
if @options.max_age and not @options.max_age.is_a?(Numeric)
|
43
48
|
raise Exceptions::ConfigurationError.new "max_age should be an Integer"
|
data/nightcrawler_swift.gemspec
CHANGED
@@ -24,5 +24,6 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_development_dependency "bundler", "~> 1.6"
|
25
25
|
spec.add_development_dependency "rake"
|
26
26
|
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "codeclimate-test-reporter"
|
27
28
|
spec.add_development_dependency "byebug"
|
28
29
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "nightcrawler_swift/cli"
|
3
|
+
|
4
|
+
describe NightcrawlerSwift::CLI::UrlFor do
|
5
|
+
|
6
|
+
let(:connection) { NightcrawlerSwift::Connection.new }
|
7
|
+
let(:token) { "token" }
|
8
|
+
let(:expires_at) { (DateTime.now + 60).to_time }
|
9
|
+
let(:public_url) { "server-url" }
|
10
|
+
let(:bucket) { "rogue" }
|
11
|
+
|
12
|
+
subject do
|
13
|
+
NightcrawlerSwift::CLI::UrlFor.new
|
14
|
+
end
|
15
|
+
|
16
|
+
before do
|
17
|
+
allow(NightcrawlerSwift).to receive(:connection).and_return(connection)
|
18
|
+
allow(connection).to receive(:token_id).and_return(token)
|
19
|
+
allow(connection).to receive(:expires_at).and_return(expires_at)
|
20
|
+
allow(connection).to receive(:public_url).and_return(public_url)
|
21
|
+
NightcrawlerSwift.configure bucket: bucket
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#execute" do
|
25
|
+
let :execute do
|
26
|
+
subject.execute "file_path"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "returns the public url of the given path" do
|
30
|
+
expect(execute).to eql("server-url/#{bucket}/file_path")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "nightcrawler_swift/cli"
|
3
|
+
|
4
|
+
describe NightcrawlerSwift::CLI::Formatters::Basic do
|
5
|
+
|
6
|
+
let :config_dir do
|
7
|
+
File.expand_path(File.join(File.dirname(__FILE__), "../../../../fixtures"))
|
8
|
+
end
|
9
|
+
|
10
|
+
let :filepath do
|
11
|
+
"testfile.txt"
|
12
|
+
end
|
13
|
+
|
14
|
+
let :runner do
|
15
|
+
instance_double "Runner"
|
16
|
+
end
|
17
|
+
|
18
|
+
let :command do
|
19
|
+
command_class.new
|
20
|
+
end
|
21
|
+
|
22
|
+
subject do
|
23
|
+
NightcrawlerSwift::CLI::Formatters::Basic.new runner
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#command_list" do
|
27
|
+
let :result do
|
28
|
+
[{
|
29
|
+
"hash"=>"c9df50d4a29542f8b6d426a50c72b3de",
|
30
|
+
"last_modified"=>"2014-08-27T19:35:46.053560",
|
31
|
+
"bytes"=>4994,
|
32
|
+
"name"=>"assets/file.png",
|
33
|
+
"content_type"=>"image/png"
|
34
|
+
}]
|
35
|
+
end
|
36
|
+
|
37
|
+
let :command_class do
|
38
|
+
NightcrawlerSwift::List
|
39
|
+
end
|
40
|
+
|
41
|
+
it "lists all files in the bucket/container configured" do
|
42
|
+
expect(command_class).to receive(:new).and_return(command)
|
43
|
+
expect(command).to receive(:execute).and_return(result)
|
44
|
+
expect(runner).to receive(:log).with(result.first["name"])
|
45
|
+
subject.command_list command_class
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "#command_download" do
|
50
|
+
let :command_class do
|
51
|
+
NightcrawlerSwift::Download
|
52
|
+
end
|
53
|
+
|
54
|
+
it "downloads the file" do
|
55
|
+
expect(command_class).to receive(:new).and_return(command)
|
56
|
+
expect(command).to receive(:execute).with(filepath).and_return("test-content")
|
57
|
+
expect(runner).to receive(:log).with("test-content")
|
58
|
+
expect(runner).to receive(:argv).and_return([filepath])
|
59
|
+
subject.command_download command_class
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#command_upload" do
|
64
|
+
let :realpath do
|
65
|
+
File.join config_dir, filepath
|
66
|
+
end
|
67
|
+
|
68
|
+
let :command_class do
|
69
|
+
NightcrawlerSwift::Upload
|
70
|
+
end
|
71
|
+
|
72
|
+
before do
|
73
|
+
File.open(realpath, "w") {|f| f.write("test") }
|
74
|
+
end
|
75
|
+
|
76
|
+
after do
|
77
|
+
File.delete(realpath) if File.exist?(realpath)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "uploads the file" do
|
81
|
+
expect(command_class).to receive(:new).and_return(command)
|
82
|
+
expect(command).to receive(:execute).with(filepath, instance_of(File)).and_return(true)
|
83
|
+
expect(runner).to receive(:log).with("success")
|
84
|
+
expect(runner).to receive(:argv).twice.and_return([realpath, filepath])
|
85
|
+
subject.command_upload command_class
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#command_delete" do
|
90
|
+
let :command_class do
|
91
|
+
NightcrawlerSwift::Delete
|
92
|
+
end
|
93
|
+
|
94
|
+
it "deletes the file" do
|
95
|
+
expect(command_class).to receive(:new).and_return(command)
|
96
|
+
expect(command).to receive(:execute).with(filepath).and_return(true)
|
97
|
+
expect(runner).to receive(:log).with("success")
|
98
|
+
expect(runner).to receive(:argv).and_return([filepath])
|
99
|
+
subject.command_delete command_class
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#command_url_for" do
|
104
|
+
let :command_class do
|
105
|
+
NightcrawlerSwift::CLI::UrlFor
|
106
|
+
end
|
107
|
+
|
108
|
+
it "returns the public url of the given path" do
|
109
|
+
expect(command_class).to receive(:new).and_return(command)
|
110
|
+
expect(command).to receive(:execute).with(filepath).and_return("public-url")
|
111
|
+
expect(runner).to receive(:log).with("public-url")
|
112
|
+
expect(runner).to receive(:argv).and_return([filepath])
|
113
|
+
subject.command_url_for command_class
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|