gemirro 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +1 -1
- data/.gitignore +1 -0
- data/.rubocop.yml +3 -1
- data/Gemfile +2 -1
- data/Gemfile.lock +73 -61
- data/bin/gemirro +1 -8
- data/gemirro.gemspec +4 -6
- data/lib/gemirro/cli/index.rb +48 -28
- data/lib/gemirro/cli/init.rb +48 -24
- data/lib/gemirro/cli/list.rb +37 -17
- data/lib/gemirro/cli/server.rb +173 -114
- data/lib/gemirro/cli/update.rb +42 -17
- data/lib/gemirro/cli.rb +62 -21
- data/lib/gemirro/configuration.rb +23 -9
- data/lib/gemirro/gem_version.rb +1 -0
- data/lib/gemirro/gem_version_collection.rb +4 -4
- data/lib/gemirro/gems_fetcher.rb +7 -9
- data/lib/gemirro/http.rb +115 -41
- data/lib/gemirro/indexer.rb +1 -1
- data/lib/gemirro/mirror_file.rb +3 -10
- data/lib/gemirro/server.rb +2 -1
- data/lib/gemirro/version.rb +1 -1
- data/lib/gemirro.rb +3 -7
- data/spec/gemirro/cli_spec.rb +49 -15
- data/spec/gemirro/gems_fetcher_spec.rb +1 -1
- data/spec/gemirro/http_spec.rb +58 -54
- data/spec/gemirro/server_spec.rb +2 -1
- data/spec/gemirro/source_spec.rb +1 -0
- metadata +29 -66
data/lib/gemirro/http.rb
CHANGED
|
@@ -2,61 +2,135 @@
|
|
|
2
2
|
|
|
3
3
|
module Gemirro
|
|
4
4
|
##
|
|
5
|
-
# The Http class is responsible for executing GET
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# @!attribute [r] client
|
|
9
|
-
# @return [HTTPClient]
|
|
5
|
+
# The Http class is responsible for executing GET requests against a
|
|
6
|
+
# given URL, following redirects and reusing keep-alive connections.
|
|
10
7
|
#
|
|
11
8
|
class Http
|
|
12
|
-
attr_accessor :client
|
|
13
|
-
|
|
14
9
|
##
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# @param [String] url
|
|
18
|
-
# @return [HTTP::Message]
|
|
10
|
+
# Raised when a request comes back with a non-successful,
|
|
11
|
+
# non-redirect HTTP status.
|
|
19
12
|
#
|
|
20
|
-
|
|
21
|
-
response = client.get(url, follow_redirect: true)
|
|
13
|
+
class Error < StandardError; end
|
|
22
14
|
|
|
23
|
-
|
|
15
|
+
MAX_REDIRECTS = 10
|
|
24
16
|
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
class << self
|
|
18
|
+
##
|
|
19
|
+
# Requests the given HTTP resource, following redirects.
|
|
20
|
+
#
|
|
21
|
+
# @param [String] url
|
|
22
|
+
# @return [Net::HTTPResponse]
|
|
23
|
+
#
|
|
24
|
+
def get(url)
|
|
25
|
+
fetch(URI.parse(url), MAX_REDIRECTS)
|
|
26
|
+
end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
28
|
+
##
|
|
29
|
+
# Closes and forgets every connection cached for the current
|
|
30
|
+
# Thread. Mostly useful for tests.
|
|
31
|
+
#
|
|
32
|
+
def reset!
|
|
33
|
+
pool.each_value { |connection| connection.finish if connection.started? }
|
|
34
|
+
pool.clear
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
##
|
|
40
|
+
# @param [URI] uri
|
|
41
|
+
# @param [Integer] redirects_left
|
|
42
|
+
# @return [Net::HTTPResponse]
|
|
43
|
+
#
|
|
44
|
+
def fetch(uri, redirects_left)
|
|
45
|
+
response = connection_for(uri).request(build_request(uri))
|
|
46
|
+
|
|
47
|
+
case response
|
|
48
|
+
when Net::HTTPRedirection
|
|
49
|
+
raise Error, "Too many redirects for #{uri}" if redirects_left <= 0
|
|
50
|
+
|
|
51
|
+
fetch(URI.parse(response['location']), redirects_left - 1)
|
|
52
|
+
when Net::HTTPSuccess
|
|
53
|
+
response
|
|
54
|
+
else
|
|
55
|
+
raise Error, "#{response.code} #{response.message}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
##
|
|
60
|
+
# @param [URI] uri
|
|
61
|
+
# @return [Net::HTTP::Get]
|
|
62
|
+
#
|
|
63
|
+
def build_request(uri)
|
|
64
|
+
request = Net::HTTP::Get.new(uri)
|
|
65
|
+
config = Utils.configuration
|
|
66
|
+
request.basic_auth(config.upstream_user, config.upstream_password) if defined?(config.upstream_user)
|
|
67
|
+
|
|
68
|
+
request
|
|
39
69
|
end
|
|
40
70
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
71
|
+
##
|
|
72
|
+
# Returns a started, keep-alive connection for the given URI,
|
|
73
|
+
# reusing one already opened by the current Thread when possible.
|
|
74
|
+
#
|
|
75
|
+
# @param [URI] uri
|
|
76
|
+
# @return [Net::HTTP]
|
|
77
|
+
#
|
|
78
|
+
def connection_for(uri)
|
|
79
|
+
key = "#{uri.scheme}://#{uri.host}:#{uri.port}"
|
|
80
|
+
pool[key] ||= build_connection(uri)
|
|
44
81
|
end
|
|
45
82
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
83
|
+
##
|
|
84
|
+
# Connection pool for the current Thread. Kept per-Thread so
|
|
85
|
+
# sockets are never shared/interleaved across concurrent requests.
|
|
86
|
+
#
|
|
87
|
+
# @return [Hash]
|
|
88
|
+
#
|
|
89
|
+
def pool
|
|
90
|
+
Thread.current[:gemirro_http_pool] ||= {}
|
|
53
91
|
end
|
|
54
92
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
93
|
+
##
|
|
94
|
+
# @param [URI] uri
|
|
95
|
+
# @return [Net::HTTP]
|
|
96
|
+
#
|
|
97
|
+
def build_connection(uri)
|
|
98
|
+
config = Utils.configuration
|
|
99
|
+
http = Net::HTTP.new(uri.host, uri.port, *proxy_args(config))
|
|
100
|
+
http.use_ssl = uri.scheme == 'https'
|
|
101
|
+
configure_ssl(http, config)
|
|
102
|
+
|
|
103
|
+
http.start
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
##
|
|
107
|
+
# @param [Net::HTTP] http
|
|
108
|
+
# @param [Gemirro::Configuration] config
|
|
109
|
+
#
|
|
110
|
+
def configure_ssl(http, config)
|
|
111
|
+
if defined?(config.rootca)
|
|
112
|
+
abort "The configuration file #{config.rootca} does not exist" unless File.file?(config.rootca)
|
|
113
|
+
|
|
114
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
115
|
+
http.ca_file = config.rootca
|
|
116
|
+
elsif defined?(config.verify_mode) && !config.verify_mode
|
|
117
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
##
|
|
122
|
+
# Splits a `proxy 'http://user:pass@host:port'` configuration
|
|
123
|
+
# value into the args expected by `Net::HTTP.new`.
|
|
124
|
+
#
|
|
125
|
+
# @param [Gemirro::Configuration] config
|
|
126
|
+
# @return [Array]
|
|
127
|
+
#
|
|
128
|
+
def proxy_args(config)
|
|
129
|
+
return [] unless defined?(config.proxy) && config.proxy
|
|
130
|
+
|
|
131
|
+
proxy_uri = URI.parse(config.proxy)
|
|
132
|
+
[proxy_uri.host, proxy_uri.port, proxy_uri.user, proxy_uri.password]
|
|
58
133
|
end
|
|
59
|
-
@client = client
|
|
60
134
|
end
|
|
61
135
|
end
|
|
62
136
|
end
|
data/lib/gemirro/indexer.rb
CHANGED
|
@@ -119,7 +119,7 @@ module Gemirro
|
|
|
119
119
|
source_host = Gemirro.configuration.source.host
|
|
120
120
|
Utils.logger.info("Download from source #{source_host}/#{file}")
|
|
121
121
|
resp = Http.get("#{source_host}/#{File.basename(file)}")
|
|
122
|
-
return unless resp.code == 200
|
|
122
|
+
return unless resp.code.to_i == 200
|
|
123
123
|
|
|
124
124
|
resp.body
|
|
125
125
|
end
|
data/lib/gemirro/mirror_file.rb
CHANGED
|
@@ -27,10 +27,8 @@ module Gemirro
|
|
|
27
27
|
#
|
|
28
28
|
def write(content)
|
|
29
29
|
FileUtils.mkdir_p(File.dirname(@path))
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
handle.write(content)
|
|
33
|
-
handle.close
|
|
30
|
+
File.write(@path, content)
|
|
31
|
+
nil
|
|
34
32
|
end
|
|
35
33
|
|
|
36
34
|
##
|
|
@@ -39,12 +37,7 @@ module Gemirro
|
|
|
39
37
|
# @return [String]
|
|
40
38
|
#
|
|
41
39
|
def read
|
|
42
|
-
|
|
43
|
-
content = handle.read
|
|
44
|
-
|
|
45
|
-
handle.close
|
|
46
|
-
|
|
47
|
-
content
|
|
40
|
+
File.read(@path)
|
|
48
41
|
end
|
|
49
42
|
end
|
|
50
43
|
end
|
data/lib/gemirro/server.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'sinatra/base'
|
|
4
|
-
require '
|
|
4
|
+
require 'puma'
|
|
5
5
|
require 'uri'
|
|
6
6
|
require 'addressable/uri'
|
|
7
7
|
require 'base64'
|
|
@@ -33,6 +33,7 @@ module Gemirro
|
|
|
33
33
|
config.server.port = '2000' if config.server.port.nil?
|
|
34
34
|
|
|
35
35
|
set :static, true
|
|
36
|
+
set :server, 'puma'
|
|
36
37
|
|
|
37
38
|
set :views, Gemirro::Configuration.views_directory
|
|
38
39
|
set :port, config.server.port
|
data/lib/gemirro/version.rb
CHANGED
data/lib/gemirro.rb
CHANGED
|
@@ -4,14 +4,15 @@ require 'builder'
|
|
|
4
4
|
require 'confstruct'
|
|
5
5
|
require 'digest/sha2'
|
|
6
6
|
require 'fileutils'
|
|
7
|
-
require 'httpclient'
|
|
8
7
|
require 'json'
|
|
9
8
|
require 'logger'
|
|
9
|
+
require 'net/http'
|
|
10
|
+
require 'openssl'
|
|
11
|
+
require 'optparse'
|
|
10
12
|
require 'parallel'
|
|
11
13
|
require 'rubygems'
|
|
12
14
|
require 'rubygems/indexer'
|
|
13
15
|
require 'rubygems/user_interaction'
|
|
14
|
-
require 'slop'
|
|
15
16
|
require 'stringio'
|
|
16
17
|
require 'tempfile'
|
|
17
18
|
require 'zlib'
|
|
@@ -34,8 +35,3 @@ require 'gemirro/versions_fetcher'
|
|
|
34
35
|
require 'gemirro/gems_fetcher'
|
|
35
36
|
|
|
36
37
|
require 'gemirro/cli'
|
|
37
|
-
require 'gemirro/cli/index'
|
|
38
|
-
require 'gemirro/cli/init'
|
|
39
|
-
require 'gemirro/cli/list'
|
|
40
|
-
require 'gemirro/cli/server'
|
|
41
|
-
require 'gemirro/cli/update'
|
data/spec/gemirro/cli_spec.rb
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
require 'gemirro/cli'
|
|
3
3
|
require 'gemirro/mirror_file'
|
|
4
|
-
require 'slop'
|
|
5
4
|
|
|
6
5
|
# Gemirro tests
|
|
7
6
|
module Gemirro
|
|
@@ -10,21 +9,47 @@ module Gemirro
|
|
|
10
9
|
describe 'CLI' do
|
|
11
10
|
include FakeFS::SpecHelpers
|
|
12
11
|
|
|
13
|
-
it 'should
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
12
|
+
it 'should print version information for -v' do
|
|
13
|
+
expect { CLI.run(['-v']) }.to output(/gemirro v.* on ruby/).to_stdout
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'should print version information for --version' do
|
|
17
|
+
expect { CLI.run(['--version']) }.to output(/gemirro v.* on ruby/).to_stdout
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'should print usage for -h' do
|
|
21
|
+
expect { CLI.run(['-h']) }.to output(/Usage: gemirro \[COMMAND\] \[OPTIONS\]/).to_stdout
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'should print usage for --help' do
|
|
25
|
+
expect { CLI.run(['--help']) }.to output(/Usage: gemirro \[COMMAND\] \[OPTIONS\]/).to_stdout
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'should print usage when no argument is given' do
|
|
29
|
+
expect { CLI.run([]) }.to output(/Usage: gemirro \[COMMAND\] \[OPTIONS\]/).to_stdout
|
|
30
|
+
end
|
|
23
31
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
32
|
+
it 'should list the available commands in the usage banner' do
|
|
33
|
+
output = capture_stdout { CLI.run(['-h']) }
|
|
34
|
+
|
|
35
|
+
CLI::COMMANDS.each do |name, description|
|
|
36
|
+
expect(output).to match(/#{name}(\s+)#{Regexp.escape(description)}/)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'should set $PROGRAM_NAME' do
|
|
41
|
+
$PROGRAM_NAME = 'rspec'
|
|
42
|
+
CLI.run(['-v'])
|
|
43
|
+
expect($PROGRAM_NAME).to eq('gemirro')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'should print an error and exit for an unknown command' do
|
|
47
|
+
expect { CLI.run(['nope']) }.to output(/Unknown command: nope/).to_stdout.and raise_error(SystemExit)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'should print an option error for an unknown flag' do
|
|
51
|
+
expect { CLI.run(['list', '--nope']) }
|
|
52
|
+
.to output(/invalid option: --nope/).to_stdout.and raise_error(SystemExit)
|
|
28
53
|
end
|
|
29
54
|
|
|
30
55
|
it 'should retrieve version information' do
|
|
@@ -45,6 +70,15 @@ module Gemirro
|
|
|
45
70
|
file.write('test')
|
|
46
71
|
expect { CLI.load_configuration('config.rb') }.to raise_error LoadError
|
|
47
72
|
end
|
|
73
|
+
|
|
74
|
+
def capture_stdout
|
|
75
|
+
original = $stdout
|
|
76
|
+
$stdout = StringIO.new
|
|
77
|
+
yield
|
|
78
|
+
$stdout.string
|
|
79
|
+
ensure
|
|
80
|
+
$stdout = original
|
|
81
|
+
end
|
|
48
82
|
end
|
|
49
83
|
end
|
|
50
84
|
end
|
|
@@ -47,7 +47,7 @@ module Gemirro
|
|
|
47
47
|
version = ::Gem::Version.new('0.0.1')
|
|
48
48
|
Utils.configuration.ignore_gem('gemirro', '0.0.1', 'ruby')
|
|
49
49
|
allow(@source).to receive(:fetch_gem)
|
|
50
|
-
.once.with('gemirro'
|
|
50
|
+
.once.with('gemirro-0.0.1.gem').and_raise(ArgumentError)
|
|
51
51
|
allow(Utils.logger).to receive(:error)
|
|
52
52
|
.once.with(/Failed to retrieve/)
|
|
53
53
|
allow(Utils.logger).to receive(:debug)
|
data/spec/gemirro/http_spec.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
|
-
require '
|
|
2
|
+
require 'webmock/rspec'
|
|
3
|
+
require 'gemirro/utils'
|
|
3
4
|
require 'gemirro/http'
|
|
4
5
|
|
|
5
6
|
module Gemirro
|
|
@@ -7,88 +8,91 @@ module Gemirro
|
|
|
7
8
|
let(:config) { double('Configuration') }
|
|
8
9
|
|
|
9
10
|
before do
|
|
10
|
-
Http.
|
|
11
|
+
Http.reset!
|
|
11
12
|
allow(Utils).to receive(:configuration).and_return(config)
|
|
12
13
|
end
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
it 'initializes a new HTTPClient' do
|
|
16
|
-
expect(Http.client).to be_a(HTTPClient)
|
|
17
|
-
end
|
|
15
|
+
after { Http.reset! }
|
|
18
16
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
describe '.get' do
|
|
18
|
+
context 'with successful response' do
|
|
19
|
+
it 'returns the response' do
|
|
20
|
+
stub_request(:get, 'http://example.com/').to_return(status: 200, body: 'content')
|
|
21
|
+
|
|
22
|
+
response = Http.get('http://example.com/')
|
|
23
|
+
expect(response).to be_a(Net::HTTPSuccess)
|
|
24
|
+
expect(response.body).to eq('content')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'reuses the connection for a second request on the same host' do
|
|
28
|
+
stub_request(:get, 'http://example.com/one').to_return(status: 200, body: 'one')
|
|
29
|
+
stub_request(:get, 'http://example.com/two').to_return(status: 200, body: 'two')
|
|
30
|
+
|
|
31
|
+
Http.get('http://example.com/one')
|
|
32
|
+
Http.get('http://example.com/two')
|
|
22
33
|
|
|
23
|
-
expect(
|
|
34
|
+
expect(a_request(:get, 'http://example.com/one')).to have_been_made.once
|
|
35
|
+
expect(a_request(:get, 'http://example.com/two')).to have_been_made.once
|
|
24
36
|
end
|
|
25
37
|
end
|
|
26
38
|
|
|
27
|
-
context 'with
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
end
|
|
39
|
+
context 'with a redirect' do
|
|
40
|
+
it 'follows it and returns the final response' do
|
|
41
|
+
stub_request(:get, 'http://example.com/old')
|
|
42
|
+
.to_return(status: 302, headers: { 'Location' => 'http://example.com/new' })
|
|
43
|
+
stub_request(:get, 'http://example.com/new').to_return(status: 200, body: 'moved')
|
|
33
44
|
|
|
34
|
-
|
|
35
|
-
expect { Http.client }.to raise_error(SystemExit)
|
|
36
|
-
end
|
|
45
|
+
expect(Http.get('http://example.com/old').body).to eq('moved')
|
|
37
46
|
end
|
|
38
47
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
end
|
|
48
|
+
it 'raises after too many redirects' do
|
|
49
|
+
stub_request(:get, 'http://example.com/loop')
|
|
50
|
+
.to_return(status: 302, headers: { 'Location' => 'http://example.com/loop' })
|
|
43
51
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
end
|
|
52
|
+
expect { Http.get('http://example.com/loop') }
|
|
53
|
+
.to raise_error(Http::Error, /Too many redirects/)
|
|
47
54
|
end
|
|
48
55
|
end
|
|
49
56
|
|
|
50
|
-
context 'with
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
end
|
|
57
|
+
context 'with an error response' do
|
|
58
|
+
it 'raises Http::Error for a failed request' do
|
|
59
|
+
stub_request(:get, 'http://example.com/missing').to_return(status: [404, 'Not Found'])
|
|
54
60
|
|
|
55
|
-
|
|
56
|
-
|
|
61
|
+
expect { Http.get('http://example.com/missing') }
|
|
62
|
+
.to raise_error(Http::Error, '404 Not Found')
|
|
57
63
|
end
|
|
58
64
|
end
|
|
59
|
-
end
|
|
60
65
|
|
|
61
|
-
|
|
62
|
-
|
|
66
|
+
context 'with upstream authentication configured' do
|
|
67
|
+
it 'sends a basic auth header on every request' do
|
|
68
|
+
allow(config).to receive(:upstream_user).and_return('user')
|
|
69
|
+
allow(config).to receive(:upstream_password).and_return('pass')
|
|
70
|
+
stub_request(:get, 'http://example.com/private')
|
|
71
|
+
.with(basic_auth: %w[user pass])
|
|
72
|
+
.to_return(status: 200, body: 'ok')
|
|
63
73
|
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
expect(Http.get('http://example.com/private').body).to eq('ok')
|
|
75
|
+
end
|
|
66
76
|
end
|
|
67
77
|
|
|
68
|
-
context 'with
|
|
69
|
-
|
|
78
|
+
context 'with proxy configuration' do
|
|
79
|
+
it 'routes the request through the configured proxy' do
|
|
80
|
+
allow(config).to receive(:proxy).and_return('http://proxy.example.com:8080')
|
|
81
|
+
stub_request(:get, 'http://example.com/').to_return(status: 200, body: 'content')
|
|
70
82
|
|
|
71
|
-
|
|
72
|
-
allow(client).to receive(:get)
|
|
73
|
-
.with('http://example.com', follow_redirect: true)
|
|
74
|
-
.and_return(response)
|
|
83
|
+
Http.get('http://example.com/')
|
|
75
84
|
|
|
76
|
-
expect(
|
|
85
|
+
expect(WebMock).to have_requested(:get, 'http://example.com/')
|
|
77
86
|
end
|
|
78
87
|
end
|
|
79
88
|
|
|
80
|
-
context 'with
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
it 'raises BadResponseError for failed request' do
|
|
84
|
-
allow(client).to receive(:get)
|
|
85
|
-
.with('http://example.com', follow_redirect: true)
|
|
86
|
-
.and_return(response)
|
|
89
|
+
context 'with an invalid rootca path' do
|
|
90
|
+
it 'aborts with an error message' do
|
|
91
|
+
allow(config).to receive(:rootca).and_return('/nonexistent/ca.crt')
|
|
87
92
|
|
|
88
|
-
expect { Http.get('
|
|
89
|
-
.to raise_error(HTTPClient::BadResponseError, 'Not Found')
|
|
93
|
+
expect { Http.get('https://example.com/') }.to raise_error(SystemExit)
|
|
90
94
|
end
|
|
91
95
|
end
|
|
92
96
|
end
|
|
93
97
|
end
|
|
94
|
-
end
|
|
98
|
+
end
|
data/spec/gemirro/server_spec.rb
CHANGED