Initial commit
This commit is contained in:
132
spec/support/api_helper.rb
Normal file
132
spec/support/api_helper.rb
Normal file
@@ -0,0 +1,132 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module APITestHelpers
|
||||
extend Memoist
|
||||
|
||||
def post_json(destination, body, headers = {})
|
||||
post destination,
|
||||
params: String === body ? body : body.to_json,
|
||||
headers: headers.reverse_merge('Content-Type' => 'application/json')
|
||||
end
|
||||
|
||||
def put_json(destination, body, headers = {})
|
||||
put destination,
|
||||
params: String === body ? body : body.to_json,
|
||||
headers: headers.reverse_merge('Content-Type' => 'application/json')
|
||||
end
|
||||
|
||||
def api_request(method, url, options = {})
|
||||
headers = options.fetch(:headers, {})
|
||||
params = options.fetch(:params, {})
|
||||
options[:token].tap { |t| headers['Authorization'] = 'Bearer ' + t if t }
|
||||
send(method, url, params: params, headers: headers)
|
||||
end
|
||||
|
||||
def api_get(*args)
|
||||
api_request(:get, *args)
|
||||
end
|
||||
|
||||
def api_post(*args)
|
||||
api_request(:post, *args)
|
||||
end
|
||||
|
||||
def api_put(*args)
|
||||
api_request(:put, *args)
|
||||
end
|
||||
|
||||
def api_patch(*args)
|
||||
api_request(:patch, *args)
|
||||
end
|
||||
|
||||
def api_delete(*args)
|
||||
api_request(:delete, *args)
|
||||
end
|
||||
|
||||
#
|
||||
# Generates valid JWT for member, allows to pass additional payload.
|
||||
#
|
||||
def jwt_for(member, payload = { x: 'x', y: 'y', z: 'z' })
|
||||
jwt_build(payload.merge(email: member.email, uid: member.uid, \
|
||||
role: member.role, state: member.state, level: member.level))
|
||||
end
|
||||
|
||||
#
|
||||
# Generates valid JWT. Accepts payload as argument. Add fields required for JWT to be valid.
|
||||
#
|
||||
def jwt_build(payload)
|
||||
jwt_encode payload.reverse_merge \
|
||||
iat: Time.now.to_i,
|
||||
exp: 20.minutes.from_now.to_i,
|
||||
jti: SecureRandom.uuid,
|
||||
sub: 'session',
|
||||
iss: 'peatio',
|
||||
aud: ['peatio']
|
||||
end
|
||||
|
||||
#
|
||||
# Generates JWT token based on payload. Doesn't add any extra fields to payload.
|
||||
#
|
||||
def jwt_encode(payload)
|
||||
OpenSSL::PKey.read(Base64.urlsafe_decode64(jwt_keypair_encoded[:private])).yield_self do |key|
|
||||
JWT.encode(payload, key, ENV.fetch('JWT_ALGORITHM'))
|
||||
end
|
||||
end
|
||||
|
||||
def jwt_keypair_encoded
|
||||
require 'openssl'
|
||||
require 'base64'
|
||||
OpenSSL::PKey::RSA.generate(2048).yield_self do |p|
|
||||
Rails.configuration.x.jwt_public_key = p.public_key
|
||||
{ public: Base64.urlsafe_encode64(p.public_key.to_pem),
|
||||
private: Base64.urlsafe_encode64(p.to_pem) }
|
||||
end
|
||||
end
|
||||
memoize :jwt_keypair_encoded
|
||||
|
||||
def multisig_jwt(payload, keychain, signers, algorithms)
|
||||
JWT::Multisig.generate_jwt(payload, keychain.slice(*signers), algorithms)
|
||||
end
|
||||
|
||||
def multisig_jwt_management_api_v1(payload, *signers)
|
||||
multisig_jwt(payload, management_api_v1_keychain, signers, management_api_v1_algorithms)
|
||||
end
|
||||
|
||||
def management_api_v1_keychain
|
||||
require 'openssl'
|
||||
{ james: OpenSSL::PKey::RSA.generate(2048),
|
||||
john: OpenSSL::PKey::RSA.generate(2048 ),
|
||||
david: OpenSSL::PKey::RSA.generate(2048 ),
|
||||
robert: OpenSSL::PKey::RSA.generate(2048 ),
|
||||
alex: OpenSSL::PKey::RSA.generate(2048 ),
|
||||
jeff: OpenSSL::PKey::RSA.generate(2048 ) }
|
||||
end
|
||||
memoize :management_api_v1_keychain
|
||||
|
||||
def management_api_v1_algorithms
|
||||
management_api_v1_keychain.each_with_object({}) { |(k, v), memo| memo[k] = 'RS256' }
|
||||
end
|
||||
memoize :management_api_v1_algorithms
|
||||
|
||||
def management_api_v1_security_configuration
|
||||
Rails.configuration.x.security_configuration
|
||||
end
|
||||
|
||||
def defaults_for_management_api_v1_security_configuration!
|
||||
config = { jwt: {} }
|
||||
config[:keychain] = management_api_v1_keychain.each_with_object({}) do |(signer, key), memo|
|
||||
memo[signer] = { algorithm: management_api_v1_algorithms.fetch(signer), value: key.public_key }
|
||||
end
|
||||
|
||||
Rails.configuration.x.security_configuration = config
|
||||
end
|
||||
|
||||
# TODO: Improvements:
|
||||
# - ability to use both symbol and string keys;
|
||||
# - handle nil response body;
|
||||
def response_body
|
||||
JSON.parse(response.body)
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure { |config| config.include APITestHelpers }
|
||||
20
spec/support/auth_helper.rb
Normal file
20
spec/support/auth_helper.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Authentication test helpers
|
||||
module AuthTestHelpers
|
||||
AUTH_HEADER_NAME = 'Authorization'.freeze
|
||||
|
||||
def inject_authorization!(member)
|
||||
@request.env['jwt.payload'] =
|
||||
{ email: member.email, uid: member.uid,
|
||||
role: member.role, state: member.state, level: member.level }
|
||||
end
|
||||
|
||||
def eject_authorization!
|
||||
@request.env['jwt.payload'] = nil
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.include AuthTestHelpers, type: :controller
|
||||
end
|
||||
20
spec/support/fake_blockchain.rb
Normal file
20
spec/support/fake_blockchain.rb
Normal file
@@ -0,0 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class FakeBlockchain < Peatio::Blockchain::Abstract
|
||||
def initialize
|
||||
@features = { cash_addr_format: false, case_sensitive: true }
|
||||
end
|
||||
|
||||
def configure(settings = {}); end
|
||||
end
|
||||
|
||||
class FakeWallet < Peatio::Wallet::Abstract
|
||||
def initialize(features = {})
|
||||
@features = features
|
||||
end
|
||||
|
||||
def configure(settings = {}); end
|
||||
end
|
||||
|
||||
Peatio::Blockchain.registry[:fake] = FakeBlockchain
|
||||
Peatio::Wallet.registry[:fake] = FakeWallet
|
||||
10
spec/support/influx_helper.rb
Normal file
10
spec/support/influx_helper.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# InfluxDB test helpers
|
||||
module InfluxTestHelper
|
||||
def delete_measurments(measurement)
|
||||
Peatio::InfluxDB.client.query("delete from #{measurement}")
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure { |config| config.include InfluxTestHelper }
|
||||
46
spec/support/matching_helper.rb
Normal file
46
spec/support/matching_helper.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
def who_is_billionaire
|
||||
member = create(:member, :level_3)
|
||||
member.get_account(:btc).update_attributes(
|
||||
locked: '1000000000.0'.to_d, balance: '1000000000.0'.to_d
|
||||
)
|
||||
member.get_account(:usd).update_attributes(
|
||||
locked: '1000000000.0'.to_d, balance: '1000000000.0'.to_d
|
||||
)
|
||||
member
|
||||
end
|
||||
|
||||
def print_time(time_hash)
|
||||
msg = time_hash.map { |k, v| "#{k}: #{v}" }.join(', ')
|
||||
puts " \u25BC #{msg}"
|
||||
end
|
||||
|
||||
module Matching
|
||||
class << self
|
||||
@@mock_order_id = 10_000
|
||||
|
||||
def mock_limit_order(attrs)
|
||||
@@mock_order_id += 1
|
||||
Matching::LimitOrder.new({
|
||||
id: @@mock_order_id,
|
||||
timestamp: Time.now.to_i,
|
||||
volume: 1 + rand(10),
|
||||
price: 3000 + rand(3000),
|
||||
market: 'btcusd'
|
||||
}.merge(attrs))
|
||||
end
|
||||
|
||||
def mock_market_order(attrs)
|
||||
@@mock_order_id += 1
|
||||
Matching::MarketOrder.new({
|
||||
id: @@mock_order_id,
|
||||
timestamp: Time.now.to_i,
|
||||
volume: 1 + rand(10),
|
||||
locked: 15_000 + rand(15_000),
|
||||
market: 'btcusd'
|
||||
}.merge(attrs))
|
||||
end
|
||||
end
|
||||
end
|
||||
10
spec/support/redis_helper.rb
Normal file
10
spec/support/redis_helper.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
module RedisTestHelper
|
||||
def clear_redis
|
||||
Rails.cache.redis.flushall
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure { |config| config.include RedisTestHelper }
|
||||
46
spec/support/rspec_matchers.rb
Normal file
46
spec/support/rspec_matchers.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec::Matchers.define :be_d do |expected|
|
||||
match do |actual|
|
||||
if expected.is_a? BigDecimal
|
||||
actual.to_d == expected
|
||||
elsif expected.is_a? String
|
||||
actual.to_d == expected.to_d
|
||||
else
|
||||
raise "not support type #{expected.class}"
|
||||
end
|
||||
end
|
||||
|
||||
failure_message do |actual|
|
||||
"expected #{actual} would be of #{expected}"
|
||||
end
|
||||
end
|
||||
|
||||
RSpec::Matchers.define :include_api_error do |expected|
|
||||
match do |actual|
|
||||
raise 'actual doesnt respond to body' unless actual.respond_to?(:body)
|
||||
raise 'expected is not a String' unless expected.is_a? String
|
||||
|
||||
errors = JSON.parse(actual.body)['errors']
|
||||
!errors.nil? && expected.in?(errors)
|
||||
end
|
||||
|
||||
# TODO: Better Error message. Same as in module RSpec::Matchers::BuiltIn::Include
|
||||
failure_message do |actual|
|
||||
"expected: #{JSON.parse(actual.body)['errors'].join(',')}\nto include: #{expected}\n"
|
||||
end
|
||||
end
|
||||
|
||||
RSpec::Matchers.define :include_ar_error do |attr, expected|
|
||||
match do |actual|
|
||||
raise 'actual is not subclass of ActiveRecord::Base' unless actual.is_a?(ActiveRecord::Base)
|
||||
|
||||
include(expected).matches?(actual.errors[attr])
|
||||
end
|
||||
|
||||
# TODO: Better Error message. Same as in module RSpec::Matchers::BuiltIn::Include
|
||||
failure_message do |actual|
|
||||
"expected: #{actual.errors}\nto include: #{expected}\n"
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user