Initial commit

This commit is contained in:
Yaser
2026-08-13 19:50:53 +03:30
commit 38084458fe
879 changed files with 95198 additions and 0 deletions

132
spec/support/api_helper.rb Normal file
View 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 }

View 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

View 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

View 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 }

View 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

View 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 }

View 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