Merge branch '58375-proxy-service' into 'master'
Add a service to proxy calls to Prometheus API See merge request gitlab-org/gitlab-ce!26840
This commit is contained in:
commit
9646e451a8
4 changed files with 419 additions and 22 deletions
116
app/services/prometheus/proxy_service.rb
Normal file
116
app/services/prometheus/proxy_service.rb
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Prometheus
|
||||||
|
class ProxyService < BaseService
|
||||||
|
include ReactiveCaching
|
||||||
|
include Gitlab::Utils::StrongMemoize
|
||||||
|
|
||||||
|
self.reactive_cache_key = ->(service) { service.cache_key }
|
||||||
|
self.reactive_cache_lease_timeout = 30.seconds
|
||||||
|
self.reactive_cache_refresh_interval = 30.seconds
|
||||||
|
self.reactive_cache_lifetime = 1.minute
|
||||||
|
self.reactive_cache_worker_finder = ->(_id, *args) { from_cache(*args) }
|
||||||
|
|
||||||
|
attr_accessor :proxyable, :method, :path, :params
|
||||||
|
|
||||||
|
PROXY_SUPPORT = {
|
||||||
|
'query' => {
|
||||||
|
method: ['GET'],
|
||||||
|
params: %w(query time timeout)
|
||||||
|
},
|
||||||
|
'query_range' => {
|
||||||
|
method: ['GET'],
|
||||||
|
params: %w(query start end step timeout)
|
||||||
|
}
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
def self.from_cache(proxyable_class_name, proxyable_id, method, path, params)
|
||||||
|
proxyable_class = begin
|
||||||
|
proxyable_class_name.constantize
|
||||||
|
rescue NameError
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
return unless proxyable_class
|
||||||
|
|
||||||
|
proxyable = proxyable_class.find(proxyable_id)
|
||||||
|
|
||||||
|
new(proxyable, method, path, params)
|
||||||
|
end
|
||||||
|
|
||||||
|
# proxyable can be any model which responds to .prometheus_adapter
|
||||||
|
# like Environment.
|
||||||
|
def initialize(proxyable, method, path, params)
|
||||||
|
@proxyable = proxyable
|
||||||
|
@path = path
|
||||||
|
|
||||||
|
# Convert ActionController::Parameters to hash because reactive_cache_worker
|
||||||
|
# does not play nice with ActionController::Parameters.
|
||||||
|
@params = filter_params(params, path).to_hash
|
||||||
|
|
||||||
|
@method = method
|
||||||
|
end
|
||||||
|
|
||||||
|
def id
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute
|
||||||
|
return cannot_proxy_response unless can_proxy?
|
||||||
|
return no_prometheus_response unless can_query?
|
||||||
|
|
||||||
|
with_reactive_cache(*cache_key) do |result|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def calculate_reactive_cache(proxyable_class_name, proxyable_id, method, path, params)
|
||||||
|
return no_prometheus_response unless can_query?
|
||||||
|
|
||||||
|
response = prometheus_client_wrapper.proxy(path, params)
|
||||||
|
|
||||||
|
success(http_status: response.code, body: response.body)
|
||||||
|
rescue Gitlab::PrometheusClient::Error => err
|
||||||
|
service_unavailable_response(err)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_key
|
||||||
|
[@proxyable.class.name, @proxyable.id, @method, @path, @params]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def service_unavailable_response(exception)
|
||||||
|
error(exception.message, :service_unavailable)
|
||||||
|
end
|
||||||
|
|
||||||
|
def no_prometheus_response
|
||||||
|
error('No prometheus server found', :service_unavailable)
|
||||||
|
end
|
||||||
|
|
||||||
|
def cannot_proxy_response
|
||||||
|
error('Proxy support for this API is not available currently')
|
||||||
|
end
|
||||||
|
|
||||||
|
def prometheus_adapter
|
||||||
|
strong_memoize(:prometheus_adapter) do
|
||||||
|
@proxyable.prometheus_adapter
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def prometheus_client_wrapper
|
||||||
|
prometheus_adapter&.prometheus_client_wrapper
|
||||||
|
end
|
||||||
|
|
||||||
|
def can_query?
|
||||||
|
prometheus_adapter&.can_query?
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter_params(params, path)
|
||||||
|
params.slice(*PROXY_SUPPORT.dig(path, :params))
|
||||||
|
end
|
||||||
|
|
||||||
|
def can_proxy?
|
||||||
|
PROXY_SUPPORT.dig(@path, :method)&.include?(@method)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -24,6 +24,19 @@ module Gitlab
|
||||||
json_api_get('query', query: '1')
|
json_api_get('query', query: '1')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def proxy(type, args)
|
||||||
|
path = api_path(type)
|
||||||
|
get(path, args)
|
||||||
|
rescue RestClient::ExceptionWithResponse => ex
|
||||||
|
if ex.response
|
||||||
|
ex.response
|
||||||
|
else
|
||||||
|
raise PrometheusClient::Error, "Network connection error"
|
||||||
|
end
|
||||||
|
rescue RestClient::Exception
|
||||||
|
raise PrometheusClient::Error, "Network connection error"
|
||||||
|
end
|
||||||
|
|
||||||
def query(query, time: Time.now)
|
def query(query, time: Time.now)
|
||||||
get_result('vector') do
|
get_result('vector') do
|
||||||
json_api_get('query', query: query, time: time.to_f)
|
json_api_get('query', query: query, time: time.to_f)
|
||||||
|
@ -64,22 +77,14 @@ module Gitlab
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def json_api_get(type, args = {})
|
def api_path(type)
|
||||||
path = ['api', 'v1', type].join('/')
|
['api', 'v1', type].join('/')
|
||||||
get(path, args)
|
|
||||||
rescue JSON::ParserError
|
|
||||||
raise PrometheusClient::Error, 'Parsing response failed'
|
|
||||||
rescue Errno::ECONNREFUSED
|
|
||||||
raise PrometheusClient::Error, 'Connection refused'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get(path, args)
|
def json_api_get(type, args = {})
|
||||||
response = rest_client[path].get(params: args)
|
path = api_path(type)
|
||||||
|
response = get(path, args)
|
||||||
handle_response(response)
|
handle_response(response)
|
||||||
rescue SocketError
|
|
||||||
raise PrometheusClient::Error, "Can't connect to #{rest_client.url}"
|
|
||||||
rescue OpenSSL::SSL::SSLError
|
|
||||||
raise PrometheusClient::Error, "#{rest_client.url} contains invalid SSL data"
|
|
||||||
rescue RestClient::ExceptionWithResponse => ex
|
rescue RestClient::ExceptionWithResponse => ex
|
||||||
if ex.response
|
if ex.response
|
||||||
handle_exception_response(ex.response)
|
handle_exception_response(ex.response)
|
||||||
|
@ -90,8 +95,18 @@ module Gitlab
|
||||||
raise PrometheusClient::Error, "Network connection error"
|
raise PrometheusClient::Error, "Network connection error"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def get(path, args)
|
||||||
|
rest_client[path].get(params: args)
|
||||||
|
rescue SocketError
|
||||||
|
raise PrometheusClient::Error, "Can't connect to #{rest_client.url}"
|
||||||
|
rescue OpenSSL::SSL::SSLError
|
||||||
|
raise PrometheusClient::Error, "#{rest_client.url} contains invalid SSL data"
|
||||||
|
rescue Errno::ECONNREFUSED
|
||||||
|
raise PrometheusClient::Error, 'Connection refused'
|
||||||
|
end
|
||||||
|
|
||||||
def handle_response(response)
|
def handle_response(response)
|
||||||
json_data = JSON.parse(response.body)
|
json_data = parse_json(response.body)
|
||||||
if response.code == 200 && json_data['status'] == 'success'
|
if response.code == 200 && json_data['status'] == 'success'
|
||||||
json_data['data'] || {}
|
json_data['data'] || {}
|
||||||
else
|
else
|
||||||
|
@ -103,7 +118,7 @@ module Gitlab
|
||||||
if response.code == 200 && response['status'] == 'success'
|
if response.code == 200 && response['status'] == 'success'
|
||||||
response['data'] || {}
|
response['data'] || {}
|
||||||
elsif response.code == 400
|
elsif response.code == 400
|
||||||
json_data = JSON.parse(response.body)
|
json_data = parse_json(response.body)
|
||||||
raise PrometheusClient::QueryError, json_data['error'] || 'Bad data received'
|
raise PrometheusClient::QueryError, json_data['error'] || 'Bad data received'
|
||||||
else
|
else
|
||||||
raise PrometheusClient::Error, "#{response.code} - #{response.body}"
|
raise PrometheusClient::Error, "#{response.code} - #{response.body}"
|
||||||
|
@ -114,5 +129,11 @@ module Gitlab
|
||||||
data = yield
|
data = yield
|
||||||
data['result'] if data['resultType'] == expected_type
|
data['result'] if data['resultType'] == expected_type
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def parse_json(response_body)
|
||||||
|
JSON.parse(response_body)
|
||||||
|
rescue JSON::ParserError
|
||||||
|
raise PrometheusClient::Error, 'Parsing response failed'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -60,15 +60,13 @@ describe Gitlab::PrometheusClient do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'failure to reach a provided prometheus url' do
|
describe 'failure to reach a provided prometheus url' do
|
||||||
let(:prometheus_url) {"https://prometheus.invalid.example.com"}
|
let(:prometheus_url) {"https://prometheus.invalid.example.com/api/v1/query?query=1"}
|
||||||
|
|
||||||
subject { described_class.new(RestClient::Resource.new(prometheus_url)) }
|
shared_examples 'exceptions are raised' do
|
||||||
|
|
||||||
context 'exceptions are raised' do
|
|
||||||
it 'raises a Gitlab::PrometheusClient::Error error when a SocketError is rescued' do
|
it 'raises a Gitlab::PrometheusClient::Error error when a SocketError is rescued' do
|
||||||
req_stub = stub_prometheus_request_with_exception(prometheus_url, SocketError)
|
req_stub = stub_prometheus_request_with_exception(prometheus_url, SocketError)
|
||||||
|
|
||||||
expect { subject.send(:get, '/', {}) }
|
expect { subject }
|
||||||
.to raise_error(Gitlab::PrometheusClient::Error, "Can't connect to #{prometheus_url}")
|
.to raise_error(Gitlab::PrometheusClient::Error, "Can't connect to #{prometheus_url}")
|
||||||
expect(req_stub).to have_been_requested
|
expect(req_stub).to have_been_requested
|
||||||
end
|
end
|
||||||
|
@ -76,7 +74,7 @@ describe Gitlab::PrometheusClient do
|
||||||
it 'raises a Gitlab::PrometheusClient::Error error when a SSLError is rescued' do
|
it 'raises a Gitlab::PrometheusClient::Error error when a SSLError is rescued' do
|
||||||
req_stub = stub_prometheus_request_with_exception(prometheus_url, OpenSSL::SSL::SSLError)
|
req_stub = stub_prometheus_request_with_exception(prometheus_url, OpenSSL::SSL::SSLError)
|
||||||
|
|
||||||
expect { subject.send(:get, '/', {}) }
|
expect { subject }
|
||||||
.to raise_error(Gitlab::PrometheusClient::Error, "#{prometheus_url} contains invalid SSL data")
|
.to raise_error(Gitlab::PrometheusClient::Error, "#{prometheus_url} contains invalid SSL data")
|
||||||
expect(req_stub).to have_been_requested
|
expect(req_stub).to have_been_requested
|
||||||
end
|
end
|
||||||
|
@ -84,11 +82,23 @@ describe Gitlab::PrometheusClient do
|
||||||
it 'raises a Gitlab::PrometheusClient::Error error when a RestClient::Exception is rescued' do
|
it 'raises a Gitlab::PrometheusClient::Error error when a RestClient::Exception is rescued' do
|
||||||
req_stub = stub_prometheus_request_with_exception(prometheus_url, RestClient::Exception)
|
req_stub = stub_prometheus_request_with_exception(prometheus_url, RestClient::Exception)
|
||||||
|
|
||||||
expect { subject.send(:get, '/', {}) }
|
expect { subject }
|
||||||
.to raise_error(Gitlab::PrometheusClient::Error, "Network connection error")
|
.to raise_error(Gitlab::PrometheusClient::Error, "Network connection error")
|
||||||
expect(req_stub).to have_been_requested
|
expect(req_stub).to have_been_requested
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'ping' do
|
||||||
|
subject { described_class.new(RestClient::Resource.new(prometheus_url)).ping }
|
||||||
|
|
||||||
|
it_behaves_like 'exceptions are raised'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'proxy' do
|
||||||
|
subject { described_class.new(RestClient::Resource.new(prometheus_url)).proxy('query', { query: '1' }) }
|
||||||
|
|
||||||
|
it_behaves_like 'exceptions are raised'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#query' do
|
describe '#query' do
|
||||||
|
@ -258,4 +268,59 @@ describe Gitlab::PrometheusClient do
|
||||||
it { is_expected.to eq(step) }
|
it { is_expected.to eq(step) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'proxy' do
|
||||||
|
context 'get API' do
|
||||||
|
let(:prometheus_query) { prometheus_cpu_query('env-slug') }
|
||||||
|
let(:query_url) { prometheus_query_url(prometheus_query) }
|
||||||
|
|
||||||
|
around do |example|
|
||||||
|
Timecop.freeze { example.run }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when response status code is 200' do
|
||||||
|
it 'returns response object' do
|
||||||
|
req_stub = stub_prometheus_request(query_url, body: prometheus_value_body('vector'))
|
||||||
|
|
||||||
|
response = subject.proxy('query', { query: prometheus_query })
|
||||||
|
json_response = JSON.parse(response.body)
|
||||||
|
|
||||||
|
expect(response.code).to eq(200)
|
||||||
|
expect(json_response).to eq({
|
||||||
|
'status' => 'success',
|
||||||
|
'data' => {
|
||||||
|
'resultType' => 'vector',
|
||||||
|
'result' => [{ "metric" => {}, "value" => [1488772511.004, "0.000041021495238095323"] }]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(req_stub).to have_been_requested
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when response status code is not 200' do
|
||||||
|
it 'returns response object' do
|
||||||
|
req_stub = stub_prometheus_request(query_url, status: 400, body: { error: 'error' })
|
||||||
|
|
||||||
|
response = subject.proxy('query', { query: prometheus_query })
|
||||||
|
json_response = JSON.parse(response.body)
|
||||||
|
|
||||||
|
expect(req_stub).to have_been_requested
|
||||||
|
expect(response.code).to eq(400)
|
||||||
|
expect(json_response).to eq('error' => 'error')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when RestClient::Exception is raised' do
|
||||||
|
before do
|
||||||
|
stub_prometheus_request_with_exception(query_url, RestClient::Exception)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'raises PrometheusClient::Error' do
|
||||||
|
expect { subject.proxy('query', { query: prometheus_query }) }.to(
|
||||||
|
raise_error(Gitlab::PrometheusClient::Error, 'Network connection error')
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
195
spec/services/prometheus/proxy_service_spec.rb
Normal file
195
spec/services/prometheus/proxy_service_spec.rb
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Prometheus::ProxyService do
|
||||||
|
include ReactiveCachingHelpers
|
||||||
|
|
||||||
|
set(:project) { create(:project) }
|
||||||
|
set(:environment) { create(:environment, project: project) }
|
||||||
|
|
||||||
|
describe '#initialize' do
|
||||||
|
let(:params) { ActionController::Parameters.new(query: '1').permit! }
|
||||||
|
|
||||||
|
it 'initializes attributes' do
|
||||||
|
result = described_class.new(environment, 'GET', 'query', params)
|
||||||
|
|
||||||
|
expect(result.proxyable).to eq(environment)
|
||||||
|
expect(result.method).to eq('GET')
|
||||||
|
expect(result.path).to eq('query')
|
||||||
|
expect(result.params).to eq('query' => '1')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'converts ActionController::Parameters into hash' do
|
||||||
|
result = described_class.new(environment, 'GET', 'query', params)
|
||||||
|
|
||||||
|
expect(result.params).to be_an_instance_of(Hash)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with unknown params' do
|
||||||
|
let(:params) { ActionController::Parameters.new(query: '1', other_param: 'val').permit! }
|
||||||
|
|
||||||
|
it 'filters unknown params' do
|
||||||
|
result = described_class.new(environment, 'GET', 'query', params)
|
||||||
|
|
||||||
|
expect(result.params).to eq('query' => '1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#execute' do
|
||||||
|
let(:prometheus_adapter) { instance_double(PrometheusService) }
|
||||||
|
let(:params) { ActionController::Parameters.new(query: '1').permit! }
|
||||||
|
|
||||||
|
subject { described_class.new(environment, 'GET', 'query', params) }
|
||||||
|
|
||||||
|
context 'when prometheus_adapter is nil' do
|
||||||
|
before do
|
||||||
|
allow(environment).to receive(:prometheus_adapter).and_return(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns error' do
|
||||||
|
expect(subject.execute).to eq(
|
||||||
|
status: :error,
|
||||||
|
message: 'No prometheus server found',
|
||||||
|
http_status: :service_unavailable
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when prometheus_adapter cannot query' do
|
||||||
|
before do
|
||||||
|
allow(environment).to receive(:prometheus_adapter).and_return(prometheus_adapter)
|
||||||
|
allow(prometheus_adapter).to receive(:can_query?).and_return(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns error' do
|
||||||
|
expect(subject.execute).to eq(
|
||||||
|
status: :error,
|
||||||
|
message: 'No prometheus server found',
|
||||||
|
http_status: :service_unavailable
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'cannot proxy' do
|
||||||
|
subject { described_class.new(environment, 'POST', 'garbage', params) }
|
||||||
|
|
||||||
|
it 'returns error' do
|
||||||
|
expect(subject.execute).to eq(
|
||||||
|
message: 'Proxy support for this API is not available currently',
|
||||||
|
status: :error
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with caching', :use_clean_rails_memory_store_caching do
|
||||||
|
let(:return_value) { { 'http_status' => 200, 'body' => 'body' } }
|
||||||
|
|
||||||
|
let(:opts) do
|
||||||
|
[environment.class.name, environment.id, 'GET', 'query', { 'query' => '1' }]
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(environment).to receive(:prometheus_adapter)
|
||||||
|
.and_return(prometheus_adapter)
|
||||||
|
allow(prometheus_adapter).to receive(:can_query?).and_return(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when value present in cache' do
|
||||||
|
before do
|
||||||
|
stub_reactive_cache(subject, return_value, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns cached value' do
|
||||||
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result[:http_status]).to eq(return_value[:http_status])
|
||||||
|
expect(result[:body]).to eq(return_value[:body])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when value not present in cache' do
|
||||||
|
it 'returns nil' do
|
||||||
|
expect(ReactiveCachingWorker)
|
||||||
|
.to receive(:perform_async)
|
||||||
|
.with(subject.class, subject.id, *opts)
|
||||||
|
|
||||||
|
result = subject.execute
|
||||||
|
|
||||||
|
expect(result).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'call prometheus api' do
|
||||||
|
let(:prometheus_client) { instance_double(Gitlab::PrometheusClient) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
synchronous_reactive_cache(subject)
|
||||||
|
|
||||||
|
allow(environment).to receive(:prometheus_adapter)
|
||||||
|
.and_return(prometheus_adapter)
|
||||||
|
allow(prometheus_adapter).to receive(:can_query?).and_return(true)
|
||||||
|
allow(prometheus_adapter).to receive(:prometheus_client_wrapper)
|
||||||
|
.and_return(prometheus_client)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'connection to prometheus server succeeds' do
|
||||||
|
let(:rest_client_response) { instance_double(RestClient::Response) }
|
||||||
|
let(:prometheus_http_status_code) { 400 }
|
||||||
|
|
||||||
|
let(:response_body) do
|
||||||
|
'{"status":"error","errorType":"bad_data","error":"parse error at char 1: no expression found in input"}'
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(prometheus_client).to receive(:proxy).and_return(rest_client_response)
|
||||||
|
|
||||||
|
allow(rest_client_response).to receive(:code)
|
||||||
|
.and_return(prometheus_http_status_code)
|
||||||
|
allow(rest_client_response).to receive(:body).and_return(response_body)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the http status code and body from prometheus' do
|
||||||
|
expect(subject.execute).to eq(
|
||||||
|
http_status: prometheus_http_status_code,
|
||||||
|
body: response_body,
|
||||||
|
status: :success
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'connection to prometheus server fails' do
|
||||||
|
context 'prometheus client raises Gitlab::PrometheusClient::Error' do
|
||||||
|
before do
|
||||||
|
allow(prometheus_client).to receive(:proxy)
|
||||||
|
.and_raise(Gitlab::PrometheusClient::Error, 'Network connection error')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns error' do
|
||||||
|
expect(subject.execute).to eq(
|
||||||
|
status: :error,
|
||||||
|
message: 'Network connection error',
|
||||||
|
http_status: :service_unavailable
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.from_cache' do
|
||||||
|
it 'initializes an instance of ProxyService class' do
|
||||||
|
result = described_class.from_cache(
|
||||||
|
environment.class.name, environment.id, 'GET', 'query', { 'query' => '1' }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).to be_an_instance_of(described_class)
|
||||||
|
expect(result.proxyable).to eq(environment)
|
||||||
|
expect(result.method).to eq('GET')
|
||||||
|
expect(result.path).to eq('query')
|
||||||
|
expect(result.params).to eq('query' => '1')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue