Initial commit
This commit is contained in:
35
spec/api/v2/admin/abilities_spec.rb
Normal file
35
spec/api/v2/admin/abilities_spec.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Abilities, type: :request do
|
||||
describe 'GET /api/v2/admin/abilities' do
|
||||
context 'member role' do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
it 'get all roles and permissions' do
|
||||
api_get '/api/v2/admin/abilities', token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result).to eq(
|
||||
"create" => ["Deposits::Fiat"],
|
||||
"manage" => ["Operations::Account", "Operations::Asset", "Operations::Expense", "Operations::Liability", "Operations::Revenue", "Member", "Account", "Beneficiary", "PaymentAddress", "Deposit", "Withdraw", "WithdrawLimit", "Blockchain", "Currency", "Engine", "Market", "TradingFee", "Wallet", "Adjustment", "InternalTransfer", "WhitelistedSmartContract"],
|
||||
"read" => ["Trade", "Order"],
|
||||
"update" => ["Order"],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'member role' do
|
||||
let(:member) { create(:member, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(member) }
|
||||
it 'get all roles and permissions' do
|
||||
api_get '/api/v2/admin/abilities', token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result).to eq({})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
420
spec/api/v2/admin/adjustments_spec.rb
Normal file
420
spec/api/v2/admin/adjustments_spec.rb
Normal file
@@ -0,0 +1,420 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Adjustments, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:member) { create(:member) }
|
||||
|
||||
describe 'GET /api/v2/admin/adjustments' do
|
||||
let!(:adjustments) do
|
||||
create(:adjustment, currency_id: 'btc')
|
||||
create(:adjustment, currency_id: 'btc')
|
||||
create(:adjustment, currency_id: 'btc')
|
||||
end
|
||||
let!(:accepted) { create(:adjustment, currency_id: 'btc', receiving_account_number: "BTC-202-#{member.uid}").tap { |a| a.accept!(validator: member) } }
|
||||
let!(:rejected) { create(:adjustment, currency_id: 'btc', receiving_account_number: "BTC-202-#{member.uid}").tap { |a| a.reject!(validator: member) } }
|
||||
|
||||
it 'get all adjustments' do
|
||||
api_get '/api/v2/admin/adjustments', token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers['Total'].to_i).to eq Adjustment.count
|
||||
expect(result.length).to eq Adjustment.count
|
||||
end
|
||||
|
||||
context 'with rejected/accepted' do
|
||||
it 'fetches operations from db' do
|
||||
api_get '/api/v2/admin/adjustments', token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.length).to eq 5
|
||||
expect(result[-1].key?('asset')).to be_truthy
|
||||
expect(result[-1].key?('liability')).to be_truthy
|
||||
expect(result[-1]['state']).to eq('rejected')
|
||||
# We don't create operations for rejected adj.
|
||||
expect(result[-1]['liability']['id'].nil?).to be_truthy
|
||||
expect(result[-1]['asset']['id'].nil?).to be_truthy
|
||||
expect(result[-2].key?('asset')).to be_truthy
|
||||
expect(result[-2].key?('liability')).to be_truthy
|
||||
expect(result[-2]['liability']['id']).to eq accepted.liability.id
|
||||
expect(result[-2]['asset']['id']).to eq accepted.asset.id
|
||||
expect(result[-2]['state']).to eq('accepted')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with filters' do
|
||||
let!(:adjustment_with_category) { create(:adjustment, currency_id: 'btc', category: 'balance_anomaly', receiving_account_number: "BTC-202-#{member.uid}") }
|
||||
let!(:eth_adjustment) { create(:adjustment, currency_id: 'eth', receiving_account_number: "eth-202-#{member.uid}").tap { |a| a.accept!(validator: member) } }
|
||||
|
||||
it 'filter by accepted state' do
|
||||
api_get '/api/v2/admin/adjustments', token: token, params: { state: 'accepted' }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers['Total'].to_i).to eq(Adjustment.where(state: 'accepted').count)
|
||||
expect(result.first['id']).to eq(accepted.id)
|
||||
end
|
||||
|
||||
it 'filter by rejected state' do
|
||||
api_get '/api/v2/admin/adjustments', token: token, params: { state: 'rejected' }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers['Total'].to_i).to eq(Adjustment.where(state: 'rejected').count)
|
||||
expect(result.first['id']).to eq(rejected.id)
|
||||
end
|
||||
|
||||
it 'filters by eth currency' do
|
||||
api_get '/api/v2/admin/adjustments', token: token, params: { currency: 'eth' }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers['Total'].to_i).to eq(Adjustment.where(currency_id: 'eth').count)
|
||||
expect(result.first['id']).to eq(eth_adjustment.id)
|
||||
end
|
||||
|
||||
it 'filters by btc currency' do
|
||||
api_get '/api/v2/admin/adjustments', token: token, params: { currency: 'btc' }
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers['Total'].to_i).to eq(Adjustment.where(currency_id: 'btc').count)
|
||||
end
|
||||
|
||||
it 'validates currency' do
|
||||
api_get '/api/v2/admin/adjustments', token: token, params: { currency: 'uah' }
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(response).to include_api_error('admin.currency.doesnt_exist')
|
||||
end
|
||||
|
||||
it 'filter by accepted category' do
|
||||
api_get '/api/v2/admin/adjustments', token: token, params: { category: 'balance_anomaly' }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers['Total'].to_i).to eq(Adjustment.where(category: 'balance_anomaly').count)
|
||||
expect(result.first['id']).to eq(adjustment_with_category.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/adjustments/:id' do
|
||||
let!(:adjustment1) { create(:adjustment, currency_id: 'btc') }
|
||||
let!(:adjustment2) { create(:adjustment, currency_id: 'eth', receiving_account_number: "ETH-202-#{member.uid}") }
|
||||
let!(:adjustment3) { create(:adjustment, currency_id: 'eth', receiving_account_number: "ETH-302-#{member.uid}") }
|
||||
|
||||
it 'get specified adjustment' do
|
||||
api_get "/api/v2/admin/adjustments/#{adjustment1.id}", token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['id']).to eq adjustment1.id
|
||||
expect(result['currency']).to eq adjustment1.currency_id
|
||||
end
|
||||
|
||||
it 'get specified adjustment' do
|
||||
api_get "/api/v2/admin/adjustments/#{adjustment2.id}", token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['id']).to eq adjustment2.id
|
||||
expect(result['currency']).to eq adjustment2.currency_id
|
||||
expect(result['receiving_account_code']).to eq '202'
|
||||
expect(result['receiving_member_uid']).to eq member.uid
|
||||
end
|
||||
|
||||
it 'get specified adjustment' do
|
||||
api_get "/api/v2/admin/adjustments/#{adjustment3.id}", token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['id']).to eq adjustment3.id
|
||||
expect(result['currency']).to eq adjustment3.currency_id
|
||||
expect(result['receiving_account_code']).to eq '302'
|
||||
expect(result['receiving_member_uid'].blank?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/adjustments/new' do
|
||||
let(:params) do
|
||||
{
|
||||
reason: 'Adjustment',
|
||||
description: 'sample sdjustment',
|
||||
category: 'asset_registration',
|
||||
amount: 100.0,
|
||||
currency_id: :btc,
|
||||
asset_account_code: 102,
|
||||
receiving_account_code: 202,
|
||||
receiving_member_uid: member.uid
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates new adjustment' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params
|
||||
}.to change { Adjustment.count }.by 1
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'returns new adjustment and prebuild operations' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result['reason']).to eq('Adjustment')
|
||||
expect(result['description']).to eq('sample sdjustment')
|
||||
expect(result['category']).to eq('asset_registration')
|
||||
expect(result['amount']).to eq('100.0')
|
||||
expect(result['currency']).to eq('btc')
|
||||
expect(result.key?('asset')).to be_truthy
|
||||
expect(result.key?('liability')).to be_truthy
|
||||
end
|
||||
|
||||
it 'checks account decimal amount' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(amount: '100btc')
|
||||
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.adjustment.non_decimal_amount')
|
||||
end
|
||||
|
||||
it 'checks right asset_account_code' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(asset_account_code: 111)
|
||||
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.adjustment.invalid_asset_account_code')
|
||||
end
|
||||
|
||||
it 'checks right receiving_account_code' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(receiving_account_code: 444)
|
||||
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.adjustment.invalid_receiving_account_code')
|
||||
end
|
||||
|
||||
it 'validates right category' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(category: 'some_category')
|
||||
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.adjustment.invalid_category')
|
||||
end
|
||||
|
||||
it 'validates right currency' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(currency_id: 'uah')
|
||||
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.adjustment.currency_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validates coin and fiat accounts numbers' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(currency_id: 'btc', asset_account_code: 101)
|
||||
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('Prebuild operations are invalid')
|
||||
end
|
||||
|
||||
context 'receiving_member_uid validatations' do
|
||||
it 'requires for liability receiving account' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(receiving_account_code: 202).except(:receiving_member_uid)
|
||||
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.adjustment.missing_receiving_member_uid')
|
||||
end
|
||||
|
||||
it 'doesnt requires for revenue receiving account' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(receiving_account_code: 302).except(:receiving_member_uid)
|
||||
|
||||
expect(response).to be_successful
|
||||
result = JSON.parse(response.body)
|
||||
expect(result['reason']).to eq('Adjustment')
|
||||
end
|
||||
|
||||
|
||||
it 'doesnt requires for expense receiving account' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(receiving_account_code: 402).except(:receiving_member_uid)
|
||||
|
||||
expect(response).to be_successful
|
||||
result = JSON.parse(response.body)
|
||||
expect(result['reason']).to eq('Adjustment')
|
||||
end
|
||||
|
||||
it 'creates adjustment with expense without member_uid' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(receiving_account_code: 402)
|
||||
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.adjustment.redundant_receiving_member_uid')
|
||||
end
|
||||
|
||||
it 'creates adjustment with revenue that contains member uid' do
|
||||
api_post '/api/v2/admin/adjustments/new', token: token, params: params.merge(receiving_account_code: 302)
|
||||
|
||||
expect(response).to be_successful
|
||||
result = JSON.parse(response.body)
|
||||
expect(result['reason']).to eq('Adjustment')
|
||||
expect(result['receiving_member_uid'].blank?).to be_truthy
|
||||
adjustment_db = Adjustment.find(result['id'])
|
||||
account_number_hash = Operations.split_account_number(account_number: adjustment_db.receiving_account_number)
|
||||
expect(account_number_hash[:member_uid].present?).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/adjustments/action (accept)' do
|
||||
let!(:adjustment) { create(:adjustment, currency_id: 'btc', receiving_account_number: "btc-202-#{member.uid}") }
|
||||
|
||||
it 'accepts adjustment' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
}.to change { adjustment.reload.state }.to('accepted')
|
||||
.and change { Operations::Asset.count }.by(1)
|
||||
.and change { Operations::Liability.count }.by(1)
|
||||
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'udpates member\'s balance' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
}.to change { member.get_account(adjustment.currency).balance }.by(adjustment.amount)
|
||||
end
|
||||
|
||||
it 'does not accept invalid asset_account_code.' do
|
||||
adjustment.update(asset_account_code: 3000)
|
||||
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
|
||||
expect(adjustment.reload.state).to eq('pending')
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.adjustment.cannot_perform_accept_action')
|
||||
end
|
||||
|
||||
it 'does not accept negative adjustment for sum bigger than member\'s balance' do
|
||||
adjustment.update(amount: -10000000.0)
|
||||
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
|
||||
expect(adjustment.reload.state).to eq('pending')
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.adjustment.user_insufficient_balance')
|
||||
end
|
||||
|
||||
it 'does not update member\'s balance if it is lower than negative adjustment' do
|
||||
adjustment.update(amount: -10000000.0)
|
||||
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
}.not_to change { member.get_account(adjustment.currency).balance }
|
||||
end
|
||||
|
||||
context 'already accepted' do
|
||||
let!(:adjustment) { create(:adjustment, currency_id: 'btc', receiving_account_number: "btc-202-#{member.uid}").tap { |a| a.accept!(validator: member) } }
|
||||
|
||||
it 'returns status and error' do
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.adjustment.cannot_perform_accept_action')
|
||||
end
|
||||
|
||||
it 'does not udpate member\'s balance' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
}.not_to change { member.accounts }
|
||||
end
|
||||
|
||||
it 'does not create operations' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
}.not_to change { Operations::Asset.count }
|
||||
end
|
||||
end
|
||||
|
||||
context 'already rejected' do
|
||||
let!(:adjustment) { create(:adjustment, currency_id: 'btc', receiving_account_number: "btc-202-#{member.uid}").tap { |a| a.reject!(validator: member) } }
|
||||
|
||||
it 'returns status and error' do
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.adjustment.cannot_perform_accept_action')
|
||||
end
|
||||
|
||||
it 'does not udpate member\'s balance' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
}.not_to change { member.accounts }
|
||||
end
|
||||
|
||||
it 'does not create operations' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
}.not_to change { Operations::Asset.count }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/adjustments/action (reject)' do
|
||||
let!(:adjustment) { create(:adjustment, currency_id: 'btc', receiving_account_number: "btc-202-#{member.uid}") }
|
||||
|
||||
it 'rejects adjustment' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :reject }
|
||||
}.to change { adjustment.reload.state }.to('rejected')
|
||||
end
|
||||
|
||||
it 'does not create operations' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :reject }
|
||||
}.not_to change { Operations::Asset.count }
|
||||
end
|
||||
|
||||
context 'already rejected' do
|
||||
let!(:adjustment) { create(:adjustment, currency_id: 'btc', receiving_account_number: "btc-202-#{member.uid}").tap { |a| a.reject!(validator: member) } }
|
||||
|
||||
it 'returns status and error' do
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :accept }
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.adjustment.cannot_perform_accept_action')
|
||||
end
|
||||
|
||||
it 'does not udpate member\'s balance' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :reject }
|
||||
}.not_to change { member.accounts }
|
||||
end
|
||||
|
||||
it 'does not create operations' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :reject }
|
||||
}.not_to change { Operations::Asset.count }
|
||||
end
|
||||
end
|
||||
|
||||
context 'already accepted' do
|
||||
let!(:adjustment) { create(:adjustment, currency_id: 'btc', receiving_account_number: "btc-202-#{member.uid}").tap { |a| a.accept!(validator: member) } }
|
||||
|
||||
it 'returns status and error' do
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :reject }
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.adjustment.cannot_perform_reject_action')
|
||||
end
|
||||
|
||||
it 'does not udpate member\'s balance' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :reject }
|
||||
}.not_to change { member.accounts }
|
||||
end
|
||||
|
||||
it 'does not create operations' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/adjustments/action', token: token, params: { id: adjustment.id, action: :reject }
|
||||
}.not_to change { Operations::Asset.count }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
92
spec/api/v2/admin/beneficiaries_spec.rb
Normal file
92
spec/api/v2/admin/beneficiaries_spec.rb
Normal file
@@ -0,0 +1,92 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Beneficiaries, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:member) { create(:member, :level_3) }
|
||||
let(:member_token) { jwt_for(level_3_member) }
|
||||
|
||||
let!(:pending_beneficiaries_for_member) do
|
||||
create_list(:beneficiary, 2, member: member, state: :pending)
|
||||
end
|
||||
|
||||
let!(:active_beneficiaries_for_member) do
|
||||
create_list(:beneficiary, 3, member: member, state: :active)
|
||||
end
|
||||
|
||||
let!(:archived_beneficiaries_for_member) do
|
||||
create_list(:beneficiary, 2, member: member, state: :archived)
|
||||
end
|
||||
|
||||
let!(:other_member_beneficiaries) do
|
||||
create_list(:beneficiary, 5)
|
||||
end
|
||||
|
||||
let!(:fiat_beneficiary) {
|
||||
create(:beneficiary, state: :active, currency: Currency.find('usd'))
|
||||
}
|
||||
|
||||
describe 'GET /api/v2/admin/beneficiaries' do
|
||||
let(:url) { '/api/v2/admin/beneficiaries' }
|
||||
|
||||
it 'get all beneficiaries' do
|
||||
api_get url, token: token
|
||||
expect(response_body.count).to eq(Beneficiary.count)
|
||||
end
|
||||
|
||||
context 'ordering' do
|
||||
it 'ascending by id' do
|
||||
api_get url, token: token, params: { order_by: 'id', ordering: 'asc' }
|
||||
|
||||
expect(response_body.first['id']).to eq Beneficiary.first.id
|
||||
end
|
||||
|
||||
it 'descending by id' do
|
||||
api_get url, token: token, params: { order_by: 'id', ordering: 'desc' }
|
||||
|
||||
expect(response_body.first['id']).to eq Beneficiary.last.id
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
it 'by member' do
|
||||
api_get url, token: token, params: { uid: member.uid }
|
||||
|
||||
expect(response_body.count).to eq(member.beneficiaries.count)
|
||||
end
|
||||
|
||||
it 'by state' do
|
||||
api_get url, token: token, params: { state: ['pending', 'archived'] }
|
||||
|
||||
expect(response_body.count).to eq(Beneficiary.where(state: ['pending', 'archived']).count)
|
||||
end
|
||||
|
||||
context 'by currency' do
|
||||
it 'by crypto currency' do
|
||||
api_get url, token: token, params: { currency: ['eth', 'btc'] }
|
||||
|
||||
expect(response_body.count).to eq(Beneficiary.where(currency_id: ['eth', 'btc']).count)
|
||||
end
|
||||
|
||||
it 'by fiat currency' do
|
||||
api_get url, token: token, params: { currency: 'usd' }
|
||||
|
||||
expect(response_body.count).to eq(Beneficiary.where(currency_id: 'usd').count)
|
||||
expect(response_body.last['data']).to eq Beneficiary.where(currency_id: 'usd').last.data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'actions' do
|
||||
let(:url) { '/api/v2/admin/beneficiaries/actions' }
|
||||
|
||||
it 'by archived' do
|
||||
api_post url, token: token, params: { action: 'archive', id: fiat_beneficiary.id }
|
||||
|
||||
expect(response_body['data']).to eq fiat_beneficiary.data.with_indifferent_access
|
||||
expect(response_body['state']).to eq('archived')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
450
spec/api/v2/admin/blockchains_spec.rb
Normal file
450
spec/api/v2/admin/blockchains_spec.rb
Normal file
@@ -0,0 +1,450 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Blockchains, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
|
||||
describe 'GET /api/v2/admin/blockchains/:id' do
|
||||
let(:blockchain) { Blockchain.find_by(key: 'eth-rinkeby') }
|
||||
|
||||
it 'returns information about specified blockchain' do
|
||||
api_get "/api/v2/admin/blockchains/#{blockchain.id}", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.fetch('id')).to eq blockchain.id
|
||||
expect(result.fetch('name')).to eq blockchain.name
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid id' do
|
||||
api_get "/api/v2/admin/blockchains/#{Blockchain.last.id + 42}", token: token
|
||||
|
||||
expect(response.code).to eq '404'
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get "/api/v2/admin/blockchains/#{blockchain.id}", token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/blockchains/clients' do
|
||||
it 'get list of all available clients' do
|
||||
api_get '/api/v2/admin/blockchains/clients', token: token
|
||||
expect(JSON.parse(response.body)).to match_array Blockchain.clients.map &:to_s
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/blockchains/:id/latest_block' do
|
||||
let(:blockchain) { Blockchain.find_by(key: "eth-rinkeby") }
|
||||
|
||||
it 'returns error in case of invalid id' do
|
||||
api_get "/api/v2/admin/blockchains/#{Blockchain.last.id + 42}/latest_block", token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.blockchain.latest_block')
|
||||
end
|
||||
|
||||
it 'returns error in case of node inaccessibility' do
|
||||
api_get "/api/v2/admin/blockchains/#{blockchain.id}/latest_block", token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.blockchain.latest_block')
|
||||
end
|
||||
|
||||
context 'get latest_block' do
|
||||
let(:blockchain) { Blockchain.find_by(key: "eth-rinkeby") }
|
||||
|
||||
around do |example|
|
||||
WebMock.disable_net_connect!
|
||||
example.run
|
||||
WebMock.allow_net_connect!
|
||||
end
|
||||
|
||||
let(:eth_blockchain) do
|
||||
Ethereum::Blockchain.new.tap { |b| b.configure(server: 'http://127.0.0.1:8545') }
|
||||
end
|
||||
|
||||
it 'returns node latest block' do
|
||||
block_number = '0x16b916'
|
||||
|
||||
stub_request(:post, 'http://127.0.0.1:8545')
|
||||
.with(body: { jsonrpc: '2.0',
|
||||
id: 1,
|
||||
method: :eth_blockNumber,
|
||||
params: [] }.to_json)
|
||||
.to_return(body: { result: block_number,
|
||||
error: nil,
|
||||
id: 1 }.to_json)
|
||||
|
||||
api_get "/api/v2/admin/blockchains/#{blockchain.id}/latest_block", token: token
|
||||
|
||||
expect(response.code).to eq '200'
|
||||
expect(response_body).to eq 1489174
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/blockchains' do
|
||||
it 'lists of blockchains' do
|
||||
api_get '/api/v2/admin/blockchains', token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq 3
|
||||
end
|
||||
|
||||
it 'returns blockchains by ascending order' do
|
||||
api_get '/api/v2/admin/blockchains', params: { ordering: 'asc', order_by: 'client'}, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.first['client']).to eq 'bitcoin'
|
||||
end
|
||||
|
||||
it 'returns paginated blockchains' do
|
||||
api_get '/api/v2/admin/blockchains', params: { limit: 2, page: 1 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
|
||||
expect(response.headers.fetch('Total')).to eq '3'
|
||||
expect(result.size).to eq 2
|
||||
expect(result.first['key']).to eq 'eth-kovan'
|
||||
|
||||
api_get '/api/v2/admin/blockchains', params: { limit: 1, page: 2 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
|
||||
expect(response.headers.fetch('Total')).to eq '3'
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['key']).to eq 'eth-rinkeby'
|
||||
end
|
||||
|
||||
it 'returns blockchains filtered by key' do
|
||||
api_get '/api/v2/admin/blockchains', params: { key: "eth-kovan" }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '1'
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['key']).to eq 'eth-kovan'
|
||||
end
|
||||
|
||||
it 'returns error in case invalid blockchain key' do
|
||||
api_get '/api/v2/admin/blockchains', params: { key: "inv" }, token: token
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.blockchain.blockchain_key_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'returns blockchains filtered by client' do
|
||||
api_get '/api/v2/admin/blockchains', params: { client: "parity" }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '1'
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['name']).to eq 'Ethereum Kovan'
|
||||
end
|
||||
|
||||
it 'returns error in case invalid blockchain client' do
|
||||
api_get '/api/v2/admin/blockchains', params: { client: "inv" }, token: token
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.blockchain.blockchain_client_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'returns blockchains filtered by status' do
|
||||
api_get '/api/v2/admin/blockchains', params: { status: "active" }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '3'
|
||||
expect(result.size).to eq 3
|
||||
expect(result.map { |r| r["status"]}).to all eq "active"
|
||||
end
|
||||
|
||||
it 'returns error in case invalid blockchain status' do
|
||||
api_get '/api/v2/admin/blockchains', params: { status: "inv" }, token: token
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.blockchain.blockchain_status_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'returns blockchains filtered by name' do
|
||||
api_get '/api/v2/admin/blockchains', params: { name: "Ethereum Kovan" }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '1'
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['name']).to eq 'Ethereum Kovan'
|
||||
end
|
||||
|
||||
it 'returns error in case invalid blockchain name' do
|
||||
api_get '/api/v2/admin/blockchains', params: { name: "inv" }, token: token
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.blockchain.blockchain_name_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get "/api/v2/admin/blockchains", token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/blockchains/new' do
|
||||
it 'creates new blockchain' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { key: 'test-blockchain', name: 'Test', client: 'geth',server: 'http://127.0.0.1', height: 123333, explorer_transaction: 'test', explorer_address: 'test'}
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['key']).to eq 'test-blockchain'
|
||||
end
|
||||
|
||||
it 'long blockchain key' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { key: Faker::String.random(1024), name: 'Test', client: 'geth',server: 'http://127.0.0.1', height: 123333, explorer_transaction: 'test', explorer_address: 'test'}
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.blockchain.key_too_long')
|
||||
end
|
||||
|
||||
it 'long blockchain name' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { key: Faker::String.random(24), name: Faker::String.random(1024), client: 'geth',server: 'http://127.0.0.1', height: 123333, explorer_transaction: 'test', explorer_address: 'test'}
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.blockchain.name_too_long')
|
||||
end
|
||||
|
||||
it 'validate height param' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { key: 'test-blockchain', name: 'Test', client: 'geth',server: 'http://127.0.0.1', height: -123333, explorer_transaction: 'test', explorer_address: 'test', status: 'active', min_confirmations: 6, step: 2 }
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.blockchain.non_positive_height')
|
||||
end
|
||||
|
||||
it 'validate min_confirmations param' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { key: 'test-blockchain', name: 'Test', client: 'geth',server: 'http://127.0.0.1', height: 123333, explorer_transaction: 'test', explorer_address: 'test', status: 'active', min_confirmations: -6, step: 2 }
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.blockchain.non_positive_min_confirmations')
|
||||
end
|
||||
|
||||
it 'validate status param' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { key: 'test-blockchain', name: 'Test', client: 'geth',server: 'http://127.0.0.1', height: 123333, explorer_transaction: 'test', explorer_address: 'test', status: 'actived', min_confirmations: 6, step: 2 }
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.blockchain.invalid_status')
|
||||
end
|
||||
|
||||
it 'validate client param' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { key: 'test-blockchain', name: 'Test', client: 'gezz',server: 'http://127.0.0.1', height: 123333, explorer_transaction: 'test', explorer_address: 'test', status: 'active', min_confirmations: 6, step: 2 }
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.blockchain.invalid_client')
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { }
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.blockchain.missing_key')
|
||||
expect(response).to include_api_error('admin.blockchain.missing_name')
|
||||
expect(response).to include_api_error('admin.blockchain.missing_client')
|
||||
expect(response).to include_api_error('admin.blockchain.missing_height')
|
||||
end
|
||||
|
||||
it 'validates server' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { key: 'test-blockchain', name: 'Test', client: 'geth',server: 'not_a_url', height: 123333, explorer_transaction: 'test', explorer_address: 'test'}
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.blockchain.invalid_server')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: level_3_member_token, params: { key: 'test-blockchain', name: 'Test', client: 'geth', server: 'http://127.0.0.1', height: 123333, explorer_transaction: 'test', explorer_address: 'test', status: 'active', min_confirmations: 6, step: 2 }
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'key already exists' do
|
||||
api_post '/api/v2/admin/blockchains/new', token: token, params: { key: Blockchain.first.key, name: 'Test', client: 'geth',server: 'http://127.0.0.1', height: 123333, explorer_transaction: 'test', explorer_address: 'test'}
|
||||
expect(response.status).to eq 422
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/blockchains/update' do
|
||||
context 'permissions' do
|
||||
let(:support) { create(:member, :admin, :level_3, role: :support, email: 'example@gmail.com', uid: 'ID73BF61C8H1') }
|
||||
let(:support_token) { jwt_for(support) }
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/blockchains/update', params: { key: 'test-blockchain', id: Blockchain.first.id }, token: support_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'returns updated blockchain' do
|
||||
api_post '/api/v2/admin/blockchains/update', params: { name: 'Test Blockchain', id: Blockchain.first.id }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['name']).to eq 'Test Blockchain'
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns updated blockchain' do
|
||||
api_post '/api/v2/admin/blockchains/update', params: { key: 'test-blockchain', id: Blockchain.first.id }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['key']).to eq 'test-blockchain'
|
||||
end
|
||||
|
||||
it 'returns updated blockchain' do
|
||||
api_post '/api/v2/admin/blockchains/update', token: token, params: { key: 'Test-blockchain ', id: Blockchain.first.id }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['key']).to eq 'test-blockchain'
|
||||
end
|
||||
|
||||
it 'long blockchain key' do
|
||||
api_post '/api/v2/admin/blockchains/update', token: token, params: { key: Faker::String.random(1024) }
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.blockchain.key_too_long')
|
||||
end
|
||||
|
||||
it 'long blockchain name' do
|
||||
api_post '/api/v2/admin/blockchains/update', token: token, params: { name: Faker::String.random(1024) }
|
||||
expect(response).not_to be_successful
|
||||
expect(response).to include_api_error('admin.blockchain.name_too_long')
|
||||
end
|
||||
|
||||
it 'validate height param' do
|
||||
api_post '/api/v2/admin/blockchains/update', token: token, params: { height: -123333 }
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.blockchain.non_positive_height')
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_post '/api/v2/admin/blockchains/update', token: level_3_member_token, params: { key: 'test-blockchain'}
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.blockchain.missing_id')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/blockchains/update', token: level_3_member_token, params: { id: Blockchain.first.id }
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/blockchains/process_block' do
|
||||
context 'returns error' do
|
||||
it 'in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/blockchains/process_block', token: level_3_member_token, params: { block_number: 1, id: Blockchain.last.id }
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'when blockchain doesnt exist' do
|
||||
api_post "/api/v2/admin/blockchains/process_block", params: { block_number: 1, id: Blockchain.last.id + 1 }, token: token
|
||||
expect(response.code).to eq '404'
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
it 'when blockchain is not accessible' do
|
||||
api_post "/api/v2/admin/blockchains/process_block", params: { block_number: 1, id: Blockchain.last.id }, token: token
|
||||
|
||||
expect(response).to include_api_error('admin.blockchain.process_block')
|
||||
end
|
||||
end
|
||||
|
||||
context 'successful' do
|
||||
let!(:blockchain) { Blockchain.find_by(key: 'btc-testnet') }
|
||||
let(:service) { BlockchainService.new(blockchain) }
|
||||
let!(:currency) { create(:currency, :btc, id: 'fake') }
|
||||
let(:block_number) { 3 }
|
||||
let!(:member) { create(:member) }
|
||||
let!(:fake_blockchain) { create(:blockchain, 'fake-testnet') }
|
||||
let!(:wallet) { create(:wallet, :fake_deposit) }
|
||||
|
||||
before do
|
||||
Blockchain.any_instance.stubs(:blockchain_api).returns(service)
|
||||
service.stubs(:latest_block_number).returns(4)
|
||||
clear_redis
|
||||
PaymentAddress.create!(member: member,
|
||||
wallet: wallet,
|
||||
address: 'fake_address')
|
||||
end
|
||||
|
||||
context 'deposit' do
|
||||
let(:transaction) { Peatio::Transaction.new(hash: 'fake_txid', from_addresses: ['fake_address'], to_address: 'fake_address', amount: 5, block_number: block_number, currency_id: 'fake', txout: 4, status: 'success') }
|
||||
let(:expected_block) { Peatio::Block.new(block_number, [transaction]) }
|
||||
|
||||
before do
|
||||
service.adapter.stubs(:fetch_block!).returns(expected_block)
|
||||
end
|
||||
|
||||
it 'detects in the block' do
|
||||
expect(Deposits::Coin.where(currency: currency).exists?).to be false
|
||||
|
||||
api_post '/api/v2/admin/blockchains/process_block', token: token, params: { block_number: block_number, id: blockchain.id }
|
||||
result = JSON.parse(response.body)
|
||||
expect(response).to be_successful
|
||||
expect(Deposits::Coin.where(currency: currency).exists?).to be true
|
||||
end
|
||||
|
||||
it 'doesn\'t update height of blockchain' do
|
||||
blockchain_height = blockchain.height
|
||||
expect(blockchain_height).not_to eq (block_number)
|
||||
|
||||
api_post '/api/v2/admin/blockchains/process_block', token: token, params: { block_number: block_number, id: blockchain.id }
|
||||
result = JSON.parse(response.body)
|
||||
expect(response).to be_successful
|
||||
expect(result['height']).not_to eq block_number
|
||||
expect(result['height']).to eq blockchain_height
|
||||
end
|
||||
end
|
||||
|
||||
context 'withdraw' do
|
||||
let!(:member_account) { member.get_account(:fake).tap { |ac| ac.update!(balance: 50, locked: 10) } }
|
||||
let!(:withdrawal) do
|
||||
Withdraw.create!(member: member,
|
||||
currency: currency,
|
||||
amount: 1,
|
||||
txid: "fake_hash",
|
||||
rid: 'fake_address',
|
||||
sum: 1,
|
||||
type: Withdraws::Coin,
|
||||
aasm_state: :confirming)
|
||||
end
|
||||
|
||||
let!(:transaction) do
|
||||
Peatio::Transaction.new(hash: 'fake_hash', to_address: 'fake_address', amount: 1, block_number: block_number, currency_id: currency.id, txout: 10, status: 'pending')
|
||||
end
|
||||
|
||||
let!(:succeed_transaction) do
|
||||
Peatio::Transaction.new(hash: 'fake_hash', to_address: 'fake_address', from_addresses: ['fake_address'], amount: 1, block_number: block_number, currency_id: currency.id, txout: 10, status: 'success')
|
||||
end
|
||||
|
||||
let(:expected_block) { Peatio::Block.new(block_number, [transaction]) }
|
||||
|
||||
before do
|
||||
service.adapter.stubs(:fetch_block!).returns(expected_block)
|
||||
service.adapter.stubs(:fetch_transaction).with(transaction).returns(succeed_transaction)
|
||||
end
|
||||
|
||||
it 'detects successfuly in the block' do
|
||||
expect(Withdraws::Coin.find_by(currency: currency, txid: transaction.hash).succeed?).to be false
|
||||
|
||||
api_post '/api/v2/admin/blockchains/process_block', token: token, params: { block_number: block_number, id: blockchain.id }
|
||||
result = JSON.parse(response.body)
|
||||
expect(response).to be_successful
|
||||
expect(Withdraws::Coin.find_by(currency: currency, txid: transaction.hash).succeed?).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
467
spec/api/v2/admin/currencies_spec.rb
Normal file
467
spec/api/v2/admin/currencies_spec.rb
Normal file
@@ -0,0 +1,467 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Currencies, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
|
||||
describe 'GET /api/v2/admin/currencies/:code' do
|
||||
let(:fiat) { Currency.find(:usd) }
|
||||
let(:coin) { Currency.find(:btc) }
|
||||
|
||||
let(:expected_for_fiat) do
|
||||
%w[code type deposit_fee withdraw_fee withdraw_limit_24h withdraw_limit_72h min_collection_amount base_factor precision position]
|
||||
end
|
||||
let(:expected_for_coin) do
|
||||
expected_for_fiat.concat(%w[blockchain_key base_factor precision subunits options])
|
||||
end
|
||||
|
||||
it 'returns information about specified currency' do
|
||||
api_get "/api/v2/admin/currencies/#{coin.code}", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.fetch('code')).to eq coin.code
|
||||
end
|
||||
|
||||
it 'returns correct keys for fiat' do
|
||||
api_get "/api/v2/admin/currencies/#{fiat.code}", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expected_for_fiat.each { |key| expect(result).to have_key key }
|
||||
|
||||
(expected_for_coin - expected_for_fiat).each do |key|
|
||||
expect(result).not_to have_key key
|
||||
end
|
||||
end
|
||||
|
||||
context 'currency code with dot' do
|
||||
let!(:currency) { create(:currency, :xagm_cx) }
|
||||
|
||||
it 'returns information about specified currency' do
|
||||
api_get "/api/v2/admin/currencies/#{currency.code}", token: token
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.fetch('code')).to eq currency.code
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns correct keys for coin' do
|
||||
api_get "/api/v2/admin/currencies/#{coin.code}", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expected_for_coin.each { |key| expect(result).to have_key key }
|
||||
end
|
||||
|
||||
it 'returns ordered by position currencies' do
|
||||
api_get "/api/v2/admin/currencies/", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.pluck('position')).to eq Currency.ordered.pluck(:position)
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid code' do
|
||||
api_get '/api/v2/admin/currencies/invalid', token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.doesnt_exist')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get "/api/v2/admin/currencies/#{coin.code}", token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/currencies' do
|
||||
it 'list of currencies' do
|
||||
api_get '/api/v2/admin/currencies', token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.count
|
||||
end
|
||||
|
||||
it 'list of coins' do
|
||||
api_get '/api/v2/admin/currencies', params: { type: 'coin' }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.coins.size
|
||||
end
|
||||
|
||||
it 'list of fiats' do
|
||||
api_get '/api/v2/admin/currencies', params: { type: 'fiat' }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body, symbolize_names: true)
|
||||
expect(result.size).to eq Currency.fiats.size
|
||||
expect(result.dig(0, :code)).to eq 'usd'
|
||||
end
|
||||
|
||||
it 'list of deposit enabled currencies' do
|
||||
api_get '/api/v2/admin/currencies', params: { deposit_enabled: true }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.deposit_enabled.count
|
||||
end
|
||||
|
||||
it 'list of deposit disabled currencies' do
|
||||
api_get '/api/v2/admin/currencies', params: { deposit_enabled: false }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.where(deposit_enabled: false).count
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid deposit_enabled type' do
|
||||
api_get '/api/v2/admin/currencies', params: { deposit_enabled: 'invalid' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_boolean_deposit_enabled')
|
||||
end
|
||||
|
||||
it 'list of withdrawal enabled currencies' do
|
||||
api_get '/api/v2/admin/currencies', params: { withdrawal_enabled: true }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.withdrawal_enabled.count
|
||||
end
|
||||
|
||||
it 'list of withdrawal disabled currencies' do
|
||||
api_get '/api/v2/admin/currencies', params: { withdrawal_enabled: false }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.where(withdrawal_enabled: false).count
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid withdrawal_enabled type' do
|
||||
api_get '/api/v2/admin/currencies', params: { withdrawal_enabled: 'invalid' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_boolean_withdrawal_enabled')
|
||||
end
|
||||
|
||||
it 'list of visible currencies' do
|
||||
api_get '/api/v2/admin/currencies', params: { visible: true }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.visible.count
|
||||
end
|
||||
|
||||
it 'list of not visible currencies' do
|
||||
api_get '/api/v2/admin/currencies', params: { visible: false }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.where(visible: false).count
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid visible type' do
|
||||
api_get '/api/v2/admin/currencies', params: { visible: 'invalid' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_boolean_visible')
|
||||
end
|
||||
|
||||
it 'list of visible coins' do
|
||||
api_get '/api/v2/admin/currencies', params: { visible: true, type: 'coin' }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.coins.select { |c| c['visible'] == true }.count
|
||||
end
|
||||
|
||||
it 'list of not visible coins' do
|
||||
api_get '/api/v2/admin/currencies', params: { visible: false, type: 'coin' }, token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Currency.coins.where(visible: false).count
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid type' do
|
||||
api_get '/api/v2/admin/currencies', params: { type: 'invalid' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
end
|
||||
|
||||
it 'returns currencies by ascending order' do
|
||||
api_get '/api/v2/admin/currencies', params: { ordering: 'asc', order_by: 'code'}, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.first['code']).to eq 'btc'
|
||||
end
|
||||
|
||||
it 'returns paginated currencies' do
|
||||
api_get '/api/v2/admin/currencies', params: { limit: 3, page: 1 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
|
||||
expect(response.headers.fetch('Total')).to eq '6'
|
||||
expect(result.size).to eq 3
|
||||
expect(result.first['code']).to eq 'usd'
|
||||
|
||||
api_get '/api/v2/admin/currencies', params: { limit: 3, page: 2 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
|
||||
expect(response.headers.fetch('Total')).to eq '6'
|
||||
expect(result.size).to eq 3
|
||||
expect(result.first['code']).to eq 'eth'
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get '/api/v2/admin/currencies', token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/currencies/new' do
|
||||
it 'create coin' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'btc-testnet' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['type']).to eq 'coin'
|
||||
end
|
||||
|
||||
it 'create token' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'btc-testnet', parent_id: 'btc' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['type']).to eq 'coin'
|
||||
expect(result['parent_id']).to eq 'btc'
|
||||
end
|
||||
|
||||
it 'create fiat' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', type: 'fiat' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['type']).to eq 'fiat'
|
||||
end
|
||||
|
||||
it 'validate blockchain_key param' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'test-blockchain' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.blockchain_key_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate type param' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'test-blockchain' , type: 'test'}, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.invalid_type')
|
||||
end
|
||||
|
||||
it 'validate visible param' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', type: 'fiat', visible: '123'}, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_boolean_visible')
|
||||
end
|
||||
|
||||
it 'validate parent_id param' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', type: 'coin', parent_id: 'trst'}, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.parent_id_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate deposit_enabled param' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: Currency.first.id, deposit_enabled: '123' }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_boolean_deposit_enabled')
|
||||
end
|
||||
|
||||
it 'validate withdrawal_enabled param' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: Currency.first.id, withdrawal_enabled: '123' }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_boolean_withdrawal_enabled')
|
||||
end
|
||||
|
||||
it 'validate options param' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', type: 'fiat', options: 'test'}, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_json_options')
|
||||
end
|
||||
|
||||
it 'verifies subunits >= 0' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'btc-testnet', subunits: -1 }, token: token
|
||||
|
||||
expect(response).to include_api_error 'admin.currency.invalid_subunits'
|
||||
expect(response).not_to be_successful
|
||||
end
|
||||
|
||||
it 'verifies subunits <= 18' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'btc-testnet', subunits: 19 }, token: token
|
||||
|
||||
expect(response).to include_api_error 'admin.currency.invalid_subunits'
|
||||
expect(response).not_to be_successful
|
||||
end
|
||||
|
||||
it 'creates 1_000_000_000_000_000_000 base_factor' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'btc-testnet', subunits: 18 }, token: token
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(response).to be_successful
|
||||
expect(result['base_factor']).to eq 1_000_000_000_000_000_000
|
||||
expect(result['subunits']).to eq 18
|
||||
end
|
||||
|
||||
it 'return error while putting base_factor and subunit params' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'btc-testnet', subunits: 18, base_factor: 1 }, token: token
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(result['errors']).to eq(['admin.currency.one_of_base_factor_subunits_fields'])
|
||||
end
|
||||
|
||||
it 'creates currency with 1000 base_factor' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'btc-testnet', base_factor: 1000 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['base_factor']).to eq 1000
|
||||
expect(result['subunits']).to eq 3
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.missing_code')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/currencies/new', params: { code: 'test', blockchain_key: 'btc-testnet' }, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/currencies/update' do
|
||||
context 'permissions' do
|
||||
let(:support) { create(:member, :admin, :level_3, role: :support, email: 'example@gmail.com', uid: 'ID73BF61C8H1') }
|
||||
let(:support_token) { jwt_for(support) }
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.find_by(type: 'fiat').code, precision: 1 }, token: support_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'updates fiat' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.find_by(type: 'fiat').code, name: 'Test' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['name']).to eq 'Test'
|
||||
end
|
||||
end
|
||||
|
||||
it 'update fiat' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.find_by(type: 'fiat').code, min_collection_amount: 1.2 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['min_collection_amount']).to eq '1.2'
|
||||
end
|
||||
|
||||
it 'update coin' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.find_by(type: 'coin').code, min_collection_amount: 1.2 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['min_collection_amount']).to eq '1.2'
|
||||
end
|
||||
|
||||
it 'validate blockchain_key param' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.find_by(type: 'coin').code, blockchain_key: 'test' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.blockchain_key_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate parent_id param' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.find_by(type: 'coin').code, parent_id: 'trst' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.parent_id_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate position param' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.find_by(type: 'coin').code, position: 0 }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.invalid_position')
|
||||
end
|
||||
|
||||
it 'validate visible param' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.first.id, visible: '123' }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_boolean_visible')
|
||||
end
|
||||
|
||||
it 'validate deposit_enabled param' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.first.id, deposit_enabled: '123' }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_boolean_deposit_enabled')
|
||||
end
|
||||
|
||||
it 'validate withdrawal_enabled param' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.first.id, withdrawal_enabled: '123' }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_boolean_withdrawal_enabled')
|
||||
end
|
||||
|
||||
it 'validates negative precision' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.first.id, precision: -1 }, token: token
|
||||
}.not_to change { Currency.first }
|
||||
|
||||
expect(response).not_to be_successful
|
||||
expect(response.status).to eq 422
|
||||
end
|
||||
|
||||
it 'validate options param' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.first.id, options: 'test' }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.non_json_options')
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.currency.missing_code')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/currencies/update', params: { code: Currency.first.id }, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
end
|
||||
293
spec/api/v2/admin/deposits_spec.rb
Normal file
293
spec/api/v2/admin/deposits_spec.rb
Normal file
@@ -0,0 +1,293 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Deposits, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
let!(:fiat_deposits) do
|
||||
[
|
||||
create(:deposit_usd, amount: 10.0),
|
||||
create(:deposit_usd, amount: 9.0),
|
||||
create(:deposit_usd, amount: 100.0, member: level_3_member),
|
||||
]
|
||||
end
|
||||
let!(:coin_deposits) do
|
||||
[
|
||||
create(:deposit_btc, amount: 102.0),
|
||||
create(:deposit_btc, amount: 11.0, member: level_3_member),
|
||||
create(:deposit_btc, amount: 12.0, member: level_3_member),
|
||||
]
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/deposits' do
|
||||
let(:url) { '/api/v2/admin/deposits' }
|
||||
|
||||
it 'get all deposits' do
|
||||
api_get url, token: token
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = coin_deposits + fiat_deposits
|
||||
|
||||
expect(actual.length).to eq expected.length
|
||||
expect(actual.map { |a| a['state'] }).to match_array expected.map(&:aasm_state)
|
||||
expect(actual.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
expect(actual.map { |a| a['currency'] }).to match_array expected.map(&:currency_id)
|
||||
expect(actual.map { |a| a['member'] }).to match_array expected.map(&:member_id)
|
||||
expect(actual.map { |a| a['type'] }).to match_array(expected.map { |d| d.currency.coin? ? 'coin' : 'fiat' })
|
||||
expect(actual.map { |a| a['uid'] }).to match_array(expected.map { |d| d.member.uid })
|
||||
expect(actual.map { |a| a['email'] }).to match_array(expected.map { |d| d.member.email })
|
||||
end
|
||||
|
||||
context 'ordering' do
|
||||
it 'ascending by id' do
|
||||
api_get url, token: token, params: { order_by: 'id', ordering: 'asc' }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = (coin_deposits + fiat_deposits).sort { |a, b| a.id <=> b.id }
|
||||
|
||||
expect(actual.map { |a| a['id'] }).to eq expected.map(&:id)
|
||||
end
|
||||
|
||||
it 'descending by amount' do
|
||||
api_get url, token: token, params: { order_by: 'amount', ordering: 'desc' }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = (coin_deposits + fiat_deposits).sort { |a, b| b.amount <=> a.amount }
|
||||
|
||||
expect(actual.map { |a| a['id'] }).to eq expected.map(&:id)
|
||||
end
|
||||
|
||||
it 'ordering by unexisting field' do
|
||||
api_get url, token: token, params: { order_by: 'cutiness', ordering: 'desc' }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = coin_deposits + fiat_deposits
|
||||
|
||||
expect(actual.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
it 'by member' do
|
||||
api_get url, token: token, params: { uid: level_3_member.uid }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = (coin_deposits + fiat_deposits).select { |d| d.member_id == level_3_member.id }
|
||||
|
||||
expect(actual.length).to eq expected.length
|
||||
expect(actual.map { |a| a['state'] }).to match_array expected.map(&:aasm_state)
|
||||
expect(actual.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
expect(actual.map { |a| a['currency'] }).to match_array expected.map(&:currency_id)
|
||||
expect(actual.map { |a| a['member'] }).to all eq level_3_member.id
|
||||
expect(actual.map { |a| a['type'] }).to match_array(expected.map { |d| d.currency.coin? ? 'coin' : 'fiat' })
|
||||
expect(actual.map { |a| a['uid'] }).to match_array(expected.map { |d| d.member.uid })
|
||||
expect(actual.map { |a| a['email'] }).to match_array(expected.map { |d| d.member.email })
|
||||
end
|
||||
|
||||
it 'by type' do
|
||||
api_get url, token: token, params: { type: 'coin' }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = coin_deposits
|
||||
|
||||
expect(actual.length).to eq expected.length
|
||||
expect(actual.map { |a| a['state'] }).to match_array expected.map(&:aasm_state)
|
||||
expect(actual.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
expect(actual.map { |a| a['currency'] }).to match_array expected.map(&:currency_id)
|
||||
expect(actual.map { |a| a['member'] }).to match_array expected.map(&:member_id)
|
||||
expect(actual.map { |a| a['type'] }).to all eq 'coin'
|
||||
end
|
||||
|
||||
it 'by email' do
|
||||
api_get url, token: token, params: { email: level_3_member.email }
|
||||
|
||||
expected = (coin_deposits + fiat_deposits).select { |d| d.member.email == level_3_member.email }
|
||||
|
||||
expect(response_body.length).to eq expected.length
|
||||
expect(response_body.map { |a| a['state'] }).to match_array expected.map(&:aasm_state)
|
||||
expect(response_body.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
expect(response_body.map { |a| a['currency'] }).to match_array expected.map(&:currency_id)
|
||||
expect(response_body.map { |a| a['member'] }).to all eq level_3_member.id
|
||||
expect(response_body.map { |a| a['type'] }).to match_array(expected.map { |d| d.currency.coin? ? 'coin' : 'fiat' })
|
||||
expect(response_body.map { |a| a['uid'] }).to match_array(expected.map { |d| d.member.uid })
|
||||
expect(response_body.map { |a| a['email'] }).to match_array(expected.map { |d| d.member.email })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/deposits/actions' do
|
||||
let(:url) { '/api/v2/admin/deposits/actions' }
|
||||
let(:fiat) { fiat_deposits.first }
|
||||
let!(:coin) { create(:deposit, :deposit_trst, aasm_state: :accepted) }
|
||||
|
||||
context 'validates params' do
|
||||
it 'does not pass unsupported action' do
|
||||
api_post url, token: token, params: { action: 'illegal', id: fiat.id }
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(response).to include_api_error('admin.deposit.invalid_action')
|
||||
end
|
||||
|
||||
it 'passes supported action for fiat' do
|
||||
api_post url, token: token, params: { action: 'reject', id: fiat.id }
|
||||
|
||||
expect(response).not_to include_api_error('admin.deposit.invalid_action')
|
||||
end
|
||||
|
||||
it 'does not pass coin action for fiat' do
|
||||
api_post url, token: token, params: { action: 'collect', id: fiat.id }
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(response).to include_api_error('admin.deposit.invalid_action')
|
||||
end
|
||||
end
|
||||
|
||||
context 'updates deposit' do
|
||||
let!(:coin) { create(:deposit, :deposit_trst) }
|
||||
|
||||
it 'accept fiat' do
|
||||
api_post url, token: token, params: { action: 'accept', id: fiat.id }
|
||||
expect(fiat.reload.aasm_state).to eq('accepted')
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'accept coin' do
|
||||
api_post url, token: token, params: { action: 'accept', id: coin.id }
|
||||
expect(coin.reload.aasm_state).to eq('accepted')
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'reject fiat' do
|
||||
api_post url, token: token, params: { action: 'reject', id: fiat.id }
|
||||
expect(response).to be_successful
|
||||
expect(fiat.reload.aasm_state).to eq('rejected')
|
||||
end
|
||||
end
|
||||
|
||||
context 'action :process' do
|
||||
it 'sends event to deposit_collection daemon' do
|
||||
api_post url, token: token, params: { action: 'process', id: coin.id }
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(Deposit.find(response_body['id']).processing?).to be_truthy
|
||||
end
|
||||
|
||||
it 'sends event to deposit_collection daemon' do
|
||||
api_post url, token: token, params: { action: 'fee_process', fees: true, id: coin.id }
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(Deposit.find(response_body['id']).fee_processing?).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/deposits/new' do
|
||||
let(:url) { '/api/v2/admin/deposits/new' }
|
||||
let(:fiat) { Currency.find(:usd) }
|
||||
let(:coin) { Currency.find(:btc) }
|
||||
|
||||
context 'validates params' do
|
||||
it 'returns error when user doesnt exist' do
|
||||
api_post url, token: token, params: { uid: SecureRandom.uuid, currency: fiat.code, amount: 12.2 }
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(response).to include_api_error('admin.deposit.user_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'returns error when currency doesnt exist' do
|
||||
api_post url, token: token, params: { uid: admin.uid, currency: coin.code, amount: 12.2 }
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(response).to include_api_error('admin.deposit.currency_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'returns error when amount is not decimal' do
|
||||
api_post url, token: token, params: { uid: admin.uid, currency: fiat.code, amount: 'amount' }
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(response).to include_api_error('admin.deposit.non_decimal_amount')
|
||||
end
|
||||
end
|
||||
|
||||
it 'creates fiat deposit' do
|
||||
api_post url, token: token, params: { uid: admin.uid, currency: fiat.code, amount: '13.4' }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response.status).to eq 201
|
||||
expect(result['currency']).to eq fiat.id
|
||||
expect(result['member']).to eq admin.id
|
||||
expect(result['uid']).to eq admin.uid
|
||||
expect(result['email']).to eq admin.email
|
||||
expect(result['amount']).to eq '13.4'
|
||||
expect(result['type']).to eq 'fiat'
|
||||
expect(result['state']).to eq 'submitted'
|
||||
expect(result['transfer_type']).to eq 'fiat'
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post url, token: level_3_member_token, params: { uid: admin.uid, currency: fiat.code, amount: 12.1 }
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/deposit_address' do
|
||||
let(:url) { '/api/v2/admin/deposit_address' }
|
||||
|
||||
context 'failed' do
|
||||
let(:currency) { :eth }
|
||||
|
||||
it 'validates currency with address_format param' do
|
||||
api_post url, params: { currency: 'abc', uid: '' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.deposit.user_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validates currency' do
|
||||
api_post url, params: { currency: 'dildocoin', uid: level_3_member.uid }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.deposit.currency_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validates currency address format' do
|
||||
api_post url, params: { currency: 'eth', uid: level_3_member.uid, address_format: 'cash' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.deposit.doesnt_support_cash_address_format')
|
||||
end
|
||||
end
|
||||
|
||||
context 'successful' do
|
||||
context 'eth address' do
|
||||
let(:currency) { :eth }
|
||||
let(:wallet) { Wallet.deposit_wallet(currency) }
|
||||
before { level_3_member.payment_address(wallet.id).update!(address: '2N2wNXrdo4oEngp498XGnGCbru29MycHogR') }
|
||||
|
||||
it 'expose data about eth address' do
|
||||
api_post url, params: { currency: currency, uid: level_3_member.uid}, token: token
|
||||
expect(response.body).to eq '{"currencies":["eth"],"address":"2n2wnxrdo4oengp498xgngcbru29mychogr","state":"active"}'
|
||||
end
|
||||
|
||||
it 'pending user address state' do
|
||||
level_3_member.payment_address(wallet.id).update!(address: nil)
|
||||
api_post url, params: { currency: currency, uid: level_3_member.uid}, token: token
|
||||
expect(response.body).to eq '{"currencies":["eth"],"address":null,"state":"pending"}'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'disabled deposit for currency' do
|
||||
let(:currency) { :btc }
|
||||
|
||||
before { Currency.find(currency).update!(deposit_enabled: false) }
|
||||
|
||||
it 'returns error' do
|
||||
api_post url, params: { currency: currency, uid: level_3_member.uid}, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.deposit.deposit_disabled')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
150
spec/api/v2/admin/engines_spec.rb
Normal file
150
spec/api/v2/admin/engines_spec.rb
Normal file
@@ -0,0 +1,150 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Engines, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
|
||||
describe 'GET /api/v2/admin/engines/:id' do
|
||||
let(:engine) { Engine.first }
|
||||
|
||||
it 'returns information about specified engine' do
|
||||
api_get "/api/v2/admin/engines/#{engine.id}", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.fetch('id')).to eq engine.id
|
||||
expect(result.fetch('name')).to eq engine.name
|
||||
expect(result.fetch('driver')).to eq engine.driver
|
||||
expect(result.fetch('state')).to eq engine.state
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid id' do
|
||||
api_get "/api/v2/admin/engines/#{Engine.last.id + 1}", token: token
|
||||
|
||||
expect(response.code).to eq '404'
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get "/api/v2/admin/engines/#{engine.id}", token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/engines' do
|
||||
it 'lists of engines' do
|
||||
api_get '/api/v2/admin/engines', token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq 2
|
||||
end
|
||||
|
||||
it 'returns engines by ascending order' do
|
||||
api_get '/api/v2/admin/engines', params: { ordering: 'asc' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.first['id']).to eq Engine.first.id
|
||||
end
|
||||
|
||||
it 'returns paginated engines' do
|
||||
api_get '/api/v2/admin/engines', params: { limit: 1, page: 1 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '2'
|
||||
expect(result.size).to eq 1
|
||||
|
||||
api_get '/api/v2/admin/engines', params: { limit: 1, page: 2 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '2'
|
||||
expect(result.size).to eq 1
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get '/api/v2/admin/engines', token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/engines/new' do
|
||||
let(:engine) { create(:engine) }
|
||||
let(:valid_params) do
|
||||
{
|
||||
name: 'new-engine',
|
||||
driver: 'new_driver',
|
||||
uid: 'UID123456',
|
||||
key: 'your_key',
|
||||
secret: 'your_secret',
|
||||
data: { some_data: 'some data' }
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates new engine' do
|
||||
api_post '/api/v2/admin/engines/new', token: token, params: valid_params
|
||||
result = JSON.parse(response.body)
|
||||
expect(response).to be_successful
|
||||
expect(result['name']).to eq 'new-engine'
|
||||
expect(result['data'].blank?).to eq true
|
||||
|
||||
api_post '/api/v2/admin/engines/new', token: token, params: valid_params
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.engine.duplicate_name')
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_post '/api/v2/admin/engines/new', params: {}, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.engine.missing_name')
|
||||
expect(response).to include_api_error('admin.engine.missing_driver')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/engines/new', params: valid_params, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/engines/update' do
|
||||
it 'updates attributes' do
|
||||
api_post '/api/v2/admin/engines/update', params: { id: Engine.first.id, name: 'Second Engine', driver: 'second_driver' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['name']).to eq 'Second Engine'
|
||||
expect(result['driver']).to eq 'second_driver'
|
||||
end
|
||||
|
||||
it 'updates secret' do
|
||||
api_post '/api/v2/admin/engines/update', params: { id: Engine.first.id, secret: 'my_secret' }, token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(Engine.first.secret).to eq('my_secret')
|
||||
end
|
||||
|
||||
it 'checkes required params' do
|
||||
api_post '/api/v2/admin/engines/update', params: {}, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.engine.missing_id')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/engines/update', params: { id: Engine.first.id, name: :new }, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
end
|
||||
101
spec/api/v2/admin/internal_transfer_spec.rb
Normal file
101
spec/api/v2/admin/internal_transfer_spec.rb
Normal file
@@ -0,0 +1,101 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::InternalTransfers, type: :request do
|
||||
let(:endpoint) { '/api/v2/admin/internal_transfers' }
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0', username: 'test') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3, uid: 'ID84BF61C8H0', username: 'member') }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
|
||||
describe 'GET /api/v2/admin/internal_transfer' do
|
||||
let!(:internal_transfer_btc) { create_list(:internal_transfer_btc, 4, :with_deposit_liability, sender: admin, receiver: level_3_member) }
|
||||
let!(:internal_transfer_usd) { create_list(:internal_transfer_usd, 3, :with_deposit_liability, sender: level_3_member) }
|
||||
|
||||
it 'lists of internal transfers' do
|
||||
api_get endpoint, token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response_body.size).to eq 7
|
||||
end
|
||||
|
||||
it 'returns paginated internal transfers' do
|
||||
api_get endpoint, params: { limit: 1, page: 1 }, token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '7'
|
||||
expect(response_body.size).to eq 1
|
||||
|
||||
api_get endpoint, params: { limit: 1, page: 2 }, token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '7'
|
||||
expect(response_body.size).to eq 1
|
||||
end
|
||||
|
||||
it 'returns internal transfers by desc order' do
|
||||
api_get endpoint, params: { ordering: 'desc' }, token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response_body.first['id']).to eq InternalTransfer.last.id
|
||||
end
|
||||
|
||||
it 'returns internal transfers by ascending order' do
|
||||
api_get endpoint, params: { ordering: 'asc' }, token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response_body.first['id']).to eq InternalTransfer.first.id
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get endpoint, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
it 'by currency' do
|
||||
api_get endpoint, token: token, params: { currency: 'btc' }
|
||||
|
||||
expect(response_body.count).to eq(InternalTransfer.where(currency_id: 'btc').count)
|
||||
end
|
||||
|
||||
it 'returns orders for specific sender by uid' do
|
||||
api_get endpoint, params: { sender: admin.uid }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['sender_uid']}.size).to eq 4
|
||||
expect(result.map{|r| r['sender_uid']}).to all eq admin.uid
|
||||
end
|
||||
|
||||
it 'returns orders for specific sender by username' do
|
||||
api_get endpoint, params: { sender: admin.username }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['sender_username']}.size).to eq 4
|
||||
expect(result.map{|r| r['sender_username']}).to all eq admin.username
|
||||
end
|
||||
|
||||
it 'returns orders for specific receiver by uid' do
|
||||
api_get endpoint, params: { receiver: level_3_member.uid }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['receiver_uid']}.size).to eq 4
|
||||
expect(result.map{|r| r['receiver_uid']}).to all eq level_3_member.uid
|
||||
end
|
||||
|
||||
it 'returns orders for specific receiver by username' do
|
||||
api_get endpoint, params: { receiver: level_3_member.username }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['receiver_username']}.size).to eq 4
|
||||
expect(result.map{|r| r['receiver_username']}).to all eq level_3_member.username
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
241
spec/api/v2/admin/markets_spec.rb
Normal file
241
spec/api/v2/admin/markets_spec.rb
Normal file
@@ -0,0 +1,241 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Markets, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
|
||||
describe 'GET /api/v2/admin/markets/:id' do
|
||||
let(:market) { Market.find_by(id: 'btcusd') }
|
||||
|
||||
it 'returns information about specified market' do
|
||||
api_get "/api/v2/admin/markets/#{market.id}", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.fetch('id')).to eq market.id
|
||||
expect(result.fetch('base_unit')).to eq market.base_currency
|
||||
expect(result.fetch('quote_unit')).to eq market.quote_currency
|
||||
expect(result.fetch('data')).to eq market.data
|
||||
end
|
||||
|
||||
it 'returns ordered by position currencies' do
|
||||
api_get "/api/v2/admin/markets/", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.pluck('position')).to eq Market.ordered.pluck(:position)
|
||||
end
|
||||
|
||||
context 'market name with dot' do
|
||||
let!(:currency) { create(:currency, :xagm_cx) }
|
||||
let!(:market) { create(:market, :xagm_cxusd) }
|
||||
|
||||
it 'returns information about specified market' do
|
||||
api_get "/api/v2/admin/markets/#{market.id}", token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.fetch('id')).to eq market.id
|
||||
expect(result.fetch('base_unit')).to eq market.base_currency
|
||||
expect(result.fetch('quote_unit')).to eq market.quote_currency
|
||||
expect(result.fetch('data')).to eq market.data
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid id' do
|
||||
api_get '/api/v2/admin/markets/120', token: token
|
||||
|
||||
expect(response.code).to eq '404'
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get "/api/v2/admin/markets/#{market.id}", token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/markets' do
|
||||
it 'lists of markets' do
|
||||
api_get '/api/v2/admin/markets', token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq 2
|
||||
end
|
||||
|
||||
it 'returns markets by ascending order' do
|
||||
api_get '/api/v2/admin/markets', params: { ordering: 'asc', order_by: 'quote_currency' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.first['quote_unit']).to eq 'eth'
|
||||
end
|
||||
|
||||
it 'returns paginated markets' do
|
||||
api_get '/api/v2/admin/markets', params: { limit: 1, page: 1 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '2'
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['id']).to eq 'btcusd'
|
||||
|
||||
api_get '/api/v2/admin/markets', params: { limit: 1, page: 2 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response.headers.fetch('Total')).to eq '2'
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['id']).to eq 'btceth'
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get '/api/v2/admin/markets', token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/markets/new' do
|
||||
let(:engine) { create(:engine) }
|
||||
let(:valid_params) do
|
||||
{
|
||||
base_currency: 'trst',
|
||||
quote_currency: 'btc',
|
||||
engine_id: engine.id,
|
||||
price_precision: 2,
|
||||
amount_precision: 2,
|
||||
min_price: 0.01,
|
||||
min_amount: 0.01,
|
||||
data: {
|
||||
upstream: {
|
||||
driver: :opendax
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates new market' do
|
||||
api_post '/api/v2/admin/markets/new', token: token, params: valid_params
|
||||
result = JSON.parse(response.body)
|
||||
expect(response).to be_successful
|
||||
expect(result['id']).to eq 'trstbtc'
|
||||
expect(result['engine_id']).to eq Market.last.engine_id
|
||||
expect(result['data']).to eq({ 'upstream' => { 'driver' => 'opendax' } })
|
||||
end
|
||||
|
||||
it 'create new market with engine name param' do
|
||||
api_post '/api/v2/admin/markets/new', token: token, params: valid_params.except(:engine_id).merge(engine_name: engine.name)
|
||||
result = JSON.parse(response.body)
|
||||
expect(response).to be_successful
|
||||
expect(result['id']).to eq 'trstbtc'
|
||||
expect(result['engine_id']).to eq Market.last.engine_id
|
||||
expect(result['data']).to eq({ 'upstream' => { 'driver' => 'opendax' } })
|
||||
end
|
||||
|
||||
it 'validate base_currency param' do
|
||||
api_post '/api/v2/admin/markets/new', token: token, params: valid_params.merge(base_currency: 'test')
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.currency_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate quote_currency param' do
|
||||
api_post '/api/v2/admin/markets/new', token: token, params: valid_params.merge(quote_currency: 'test')
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.currency_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate enabled param' do
|
||||
api_post '/api/v2/admin/markets/new', token: token, params: valid_params.merge(state: '123')
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.invalid_state')
|
||||
end
|
||||
|
||||
it 'validate engine name param' do
|
||||
api_post '/api/v2/admin/markets/new', token: token, params: valid_params.except(:engine_id).merge(engine_name: 'test')
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.engine_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'checked exactly_one_ofr params' do
|
||||
api_post '/api/v2/admin/markets/new', token: token, params: valid_params.merge(engine_name: 'test')
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.one_of_engine_id_engine_name_fields')
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_post '/api/v2/admin/markets/new', params: {}, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.missing_base_currency')
|
||||
expect(response).to include_api_error('admin.market.missing_quote_currency')
|
||||
expect(response).to include_api_error('admin.market.one_of_engine_id_engine_name_fields')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/markets/new', params: valid_params, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/markets/update' do
|
||||
it 'updates attributes' do
|
||||
api_post '/api/v2/admin/markets/update', params: { id: Market.first.id, amount_precision: 3, price_precision: 5, min_amount: 0.1, min_price: 0.1 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['amount_precision']).to eq 3
|
||||
expect(result['price_precision']).to eq 5
|
||||
expect(result['min_amount']).to eq '0.1'
|
||||
expect(result['min_price']).to eq '0.1'
|
||||
end
|
||||
|
||||
it 'updates data' do
|
||||
api_post '/api/v2/admin/markets/update', params: { id: Market.first.id, data: { 'upstream' => { 'driver' => 'opendax' } } }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['data']).to eq({ 'upstream' => { 'driver' => 'opendax' } })
|
||||
end
|
||||
|
||||
it 'validates data field' do
|
||||
api_post '/api/v2/admin/markets/update', params: { id: Market.first.id, data: 'data' }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.invalid_data')
|
||||
end
|
||||
|
||||
it 'validates position' do
|
||||
api_post '/api/v2/admin/markets/update', params: { id: Market.first.id, position: 0 }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.invalid_position')
|
||||
end
|
||||
|
||||
it 'checkes required params' do
|
||||
api_post '/api/v2/admin/markets/update', params: {}, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.missing_id')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/markets/update', params: { id: Market.first.id, state: :disabled }, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
end
|
||||
195
spec/api/v2/admin/members_spec.rb
Normal file
195
spec/api/v2/admin/members_spec.rb
Normal file
@@ -0,0 +1,195 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Members, type: :request do
|
||||
let(:uid) { 'ID00FEE1DEAD' }
|
||||
let(:email) { 'someone@mailbox.com' }
|
||||
let(:admin) { create(:member, :admin, :level_3, email: email, uid: uid) }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:member) { create(:member, :level_3) }
|
||||
let(:member_token) { jwt_for(member) }
|
||||
let!(:members) do
|
||||
[
|
||||
create(:member, role: 'admin', state: 'pending'),
|
||||
create(:member, role: 'admin', state: 'active'),
|
||||
create(:member, group: 'any'),
|
||||
]
|
||||
end
|
||||
|
||||
describe 'GET' do
|
||||
context 'authentication' do
|
||||
it 'requires token' do
|
||||
get '/api/v2/admin/members'
|
||||
expect(response.code).to eq '401'
|
||||
end
|
||||
|
||||
it 'validates permissions' do
|
||||
api_get'/api/v2/admin/members', token: member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'authenticate admin' do
|
||||
api_get'/api/v2/admin/members', token: token
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
it 'returns all members' do
|
||||
api_get'/api/v2/admin/members', token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result.length).to eq(Member.count)
|
||||
end
|
||||
|
||||
it 'filters by role & state' do
|
||||
api_get'/api/v2/admin/members', token: token, params: { role: 'admin', state: 'active' }
|
||||
result = JSON.parse(response.body)
|
||||
expected = Member.where(role: 'admin', state: 'active').pluck(:id)
|
||||
|
||||
expect(result.map { |r| r['id'] }).to match_array expected
|
||||
end
|
||||
|
||||
it 'filters by group' do
|
||||
api_get'/api/v2/admin/members', token: token, params: { group: 'any' }
|
||||
result = JSON.parse(response.body)
|
||||
expected = Member.where(group: 'any').pluck(:id)
|
||||
|
||||
expect(result.map { |r| r['id'] }).to match_array expected
|
||||
end
|
||||
|
||||
it 'filters by uid' do
|
||||
api_get'/api/v2/admin/members', token: token, params: { uid: uid }
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.length).to eq 1
|
||||
expect(result.first['id']).to eq admin.id
|
||||
end
|
||||
end
|
||||
|
||||
context 'accounts' do
|
||||
before { admin.touch_accounts }
|
||||
it 'returns accounts for all currencies' do
|
||||
api_get'/api/v2/admin/members', token: token, params: { uid: uid }
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.first['accounts'].count).to eq(Currency.count)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Get by uid' do
|
||||
context 'authentication' do
|
||||
it 'requires token' do
|
||||
get "/api/v2/admin/members/#{member.uid}"
|
||||
expect(response.code).to eq '401'
|
||||
end
|
||||
|
||||
it 'validates permissions' do
|
||||
api_get "/api/v2/admin/members/#{member.uid}", token: member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'authenticate admin' do
|
||||
api_get "/api/v2/admin/members/#{member.uid}", token: token
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
context 'get user by uid' do
|
||||
let!(:account) { member.touch_accounts }
|
||||
let(:address) { Faker::Blockchain::Ethereum.address }
|
||||
let(:coin) { Currency.find(:btc) }
|
||||
|
||||
let!(:beneficiary) { create(:beneficiary,
|
||||
member: member,
|
||||
currency: coin,
|
||||
state: :active,
|
||||
data: generate(:coin_beneficiary_data).merge(address: address)) }
|
||||
|
||||
|
||||
it 'returns user entities' do
|
||||
api_get "/api/v2/admin/members/UID1234", token: token
|
||||
expect(response.code).to eq '404'
|
||||
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
it 'returns user entities' do
|
||||
api_get "/api/v2/admin/members/#{member.uid}", token: token
|
||||
expect(response).to be_successful
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result['uid']).to eq(member.uid)
|
||||
expect(result['email']).to eq(member.email)
|
||||
expect(result['uid']).to eq(member.uid)
|
||||
expect(result['group']).to eq(member.group)
|
||||
expect(result['accounts'][0]['currency']).to eq(member.accounts[0].currency.id)
|
||||
expect(result['accounts'][0]['balance']).to eq(member.accounts[0].balance.to_s)
|
||||
expect(result['accounts'][0]['locked']).to eq(member.accounts[0].locked.to_s)
|
||||
expect(result['beneficiaries'][0]['currency']).to eq(member.beneficiaries[0].currency_id)
|
||||
expect(result['beneficiaries'][0]['data']['address']).to eq(member.beneficiaries[0].data['address'])
|
||||
end
|
||||
|
||||
context 'fiat beneficiary' do
|
||||
let(:fiat) { Currency.find(:usd) }
|
||||
|
||||
let!(:beneficiary) { create(:beneficiary,
|
||||
member: member,
|
||||
currency: fiat,
|
||||
state: :active,
|
||||
data: generate(:fiat_beneficiary_data)) }
|
||||
|
||||
it 'returns user entities' do
|
||||
api_get "/api/v2/admin/members/#{member.uid}", token: token
|
||||
expect(response).to be_successful
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result['uid']).to eq(member.uid)
|
||||
expect(result['email']).to eq(member.email)
|
||||
expect(result['uid']).to eq(member.uid)
|
||||
expect(result['group']).to eq(member.group)
|
||||
expect(result['accounts'][0]['currency']).to eq(member.accounts[0].currency.id)
|
||||
expect(result['accounts'][0]['balance']).to eq(member.accounts[0].balance.to_s)
|
||||
expect(result['accounts'][0]['locked']).to eq(member.accounts[0].locked.to_s)
|
||||
expect(result['beneficiaries'][0]['currency']).to eq(member.beneficiaries[0].currency_id)
|
||||
expect(result['beneficiaries'][0]['data']['address']).to eq(member.beneficiaries[0].data['address'])
|
||||
expect(result['beneficiaries'][0]['data']['account_number']).to eq(member.beneficiaries[0].data['account_number'])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/members/groups' do
|
||||
it 'get list of all existing groups' do
|
||||
api_get '/api/v2/admin/members/groups', token: token
|
||||
expect(JSON.parse(response.body)).to match_array Member.groups.map &:to_s
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/members/groups' do
|
||||
it 'returns user with updated role' do
|
||||
api_put "/api/v2/admin/members/#{member.uid}", token: token, params: { group: 'vip-2' }
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-2')
|
||||
end
|
||||
|
||||
it 'returns user with updated group' do
|
||||
api_put "/api/v2/admin/members/#{member.uid}", token: token, params: { group: ' Vip-2 ' }
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-2')
|
||||
end
|
||||
|
||||
it 'returns status 404 and error' do
|
||||
api_put "/api/v2/admin/members/U1234", token: token, params: { group: 'vip-2' }
|
||||
expect(response).to have_http_status(404)
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
it 'validate params' do
|
||||
api_put "/api/v2/admin/members/#{member.uid}", token: token
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.member.missing_group')
|
||||
end
|
||||
end
|
||||
end
|
||||
175
spec/api/v2/admin/operations_spec.rb
Normal file
175
spec/api/v2/admin/operations_spec.rb
Normal file
@@ -0,0 +1,175 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Operations, type: :request do
|
||||
let(:uid) { 'ID00FEE1DEAD' }
|
||||
let(:email) { 'someone@mailbox.com' }
|
||||
let(:admin) { create(:member, :admin, :level_3, email: email, uid: uid) }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:member) { create(:member, :level_3) }
|
||||
let(:member_token) { jwt_for(member) }
|
||||
|
||||
describe 'GET' do
|
||||
context 'authentication' do
|
||||
it 'requires token' do
|
||||
get '/api/v2/admin/assets'
|
||||
expect(response.code).to eq '401'
|
||||
end
|
||||
|
||||
it 'validates permissions' do
|
||||
api_get'/api/v2/admin/expenses', token: member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'authenticate admin' do
|
||||
api_get'/api/v2/admin/liabilities', token: token
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
context 'assets' do
|
||||
let!(:assets) do
|
||||
[
|
||||
create(:asset, currency: Currency.find(:btc), debit: 80.0),
|
||||
create(:asset, currency: Currency.find(:btc), debit: 120.0),
|
||||
create(:asset, currency: Currency.find(:usd), debit: 220.0),
|
||||
]
|
||||
end
|
||||
|
||||
it 'entity present valid fields' do
|
||||
api_get '/api/v2/admin/assets', token: token
|
||||
result = JSON.parse(response.body)
|
||||
expected = %w[id rid currency reference_type credit debit created_at code account_kind]
|
||||
|
||||
expect(result.first.keys).to match_array expected
|
||||
end
|
||||
|
||||
it 'filters by currency' do
|
||||
api_get '/api/v2/admin/assets', token: token, params: { currency: 'usd' }
|
||||
result = JSON.parse(response.body)
|
||||
expected = assets.select { |a| a.currency_id == 'usd' }
|
||||
|
||||
expect(result.map { |a| a['id'] }).to match_array expected.map { |e| e.id }
|
||||
end
|
||||
|
||||
it 'orders by debit ascending' do
|
||||
api_get '/api/v2/admin/assets', token: token, params: { order_by: 'debit', ordering: 'asc' }
|
||||
result = JSON.parse(response.body)
|
||||
expected = assets.sort { |a, b| a.debit <=> b.debit }
|
||||
|
||||
expect(result.map { |a| a['id'] }).to match_array expected.map { |e| e.id }
|
||||
end
|
||||
end
|
||||
|
||||
context 'expenses' do
|
||||
let!(:expenses) do
|
||||
[
|
||||
create(:expense, created_at: 5.days.ago, reference_type: 'Deposit'),
|
||||
create(:expense, created_at: 2.days.ago, reference_type: 'Trade'),
|
||||
create(:expense, created_at: 2.days.ago, reference_type: 'Deposit'),
|
||||
]
|
||||
end
|
||||
|
||||
it 'entity presents valid fields' do
|
||||
api_get '/api/v2/admin/expenses', token: token
|
||||
result = JSON.parse(response.body)
|
||||
expected = %w[id rid currency reference_type credit debit created_at code account_kind]
|
||||
|
||||
expect(result.first.keys).to match_array expected
|
||||
end
|
||||
|
||||
it 'filters by reference type' do
|
||||
api_get '/api/v2/admin/expenses', token: token, params: { reference_type: 'Deposit' }
|
||||
result = JSON.parse(response.body)
|
||||
expected = expenses.select { |a| a.reference_type == 'Deposit' }
|
||||
|
||||
expect(result.map { |e| e['id'] }).to match_array expected.map { |e| e.id }
|
||||
end
|
||||
|
||||
it 'fileters by created_at_to' do
|
||||
api_get '/api/v2/admin/expenses', token: token, params: { range: 'created', to: 3.days.ago }
|
||||
result = JSON.parse(response.body)
|
||||
expected = expenses.select { |l| l.created_at < 3.days.ago }
|
||||
|
||||
expect(result.map { |a| a['id'] }).to match_array expected.map { |e| e.id }
|
||||
end
|
||||
|
||||
it 'filters by created_at_from' do
|
||||
api_get '/api/v2/admin/expenses', token: token, params: { range: 'created', from: 3.days.ago }
|
||||
result = JSON.parse(response.body)
|
||||
expected = expenses.select { |l| l.created_at >= 3.days.ago }
|
||||
|
||||
expect(result.map { |a| a['id'] }).to match_array expected.map { |e| e.id }
|
||||
end
|
||||
end
|
||||
|
||||
context 'revenues' do
|
||||
let!(:revenues) do
|
||||
[
|
||||
create(:revenue, code: 301, currency: Currency.find(:usd), reference_id: 1),
|
||||
create(:revenue, code: 302, currency: Currency.find(:btc), reference_id: 1),
|
||||
create(:revenue, code: 302, currency: Currency.find(:btc), reference_id: 2),
|
||||
]
|
||||
end
|
||||
|
||||
it 'entity presents valid fields' do
|
||||
api_get '/api/v2/admin/revenues', token: token
|
||||
result = JSON.parse(response.body)
|
||||
expected = %w[id rid currency reference_type credit debit created_at code account_kind]
|
||||
|
||||
expect(result.first.keys).to match_array expected
|
||||
end
|
||||
|
||||
it 'filters by code' do
|
||||
api_get '/api/v2/admin/revenues', token: token, params: { code: 302 }
|
||||
result = JSON.parse(response.body)
|
||||
expected = revenues.select { |a| a.code == 302 }
|
||||
|
||||
expect(result.map { |r| r['id'] }).to match_array expected.map { |e| e.id }
|
||||
end
|
||||
|
||||
it 'filters by reference id' do
|
||||
api_get '/api/v2/admin/revenues', token: token, params: { rid: 1 }
|
||||
result = JSON.parse(response.body)
|
||||
expected = revenues.select { |a| a.reference_id == 1 }
|
||||
|
||||
expect(result.map { |r| r['id'] }).to match_array expected.map { |e| e.id }
|
||||
end
|
||||
end
|
||||
|
||||
context 'liabilities' do
|
||||
let!(:liabilities) do
|
||||
[
|
||||
create(:liability, member: member, credit: 110.0),
|
||||
create(:liability, member: member, credit: 190.0),
|
||||
create(:liability, member: admin, credit: 80.0),
|
||||
]
|
||||
end
|
||||
|
||||
it 'entity presents valid fields' do
|
||||
api_get '/api/v2/admin/liabilities', token: token
|
||||
result = JSON.parse(response.body)
|
||||
expected = %w[id rid currency reference_type credit debit created_at code uid account_kind]
|
||||
|
||||
expect(result.first.keys).to match_array expected
|
||||
end
|
||||
|
||||
it 'filters by member uid' do
|
||||
api_get '/api/v2/admin/liabilities', token: token, params: { uid: member.uid }
|
||||
result = JSON.parse(response.body)
|
||||
expected = liabilities.select { |l| l.member.uid == member.uid }
|
||||
|
||||
expect(result.map { |a| a['id'] }).to match_array expected.map { |e| e.id }
|
||||
end
|
||||
|
||||
it 'orders by credit descending' do
|
||||
api_get '/api/v2/admin/liabilities', token: token, params: { order_by: 'credit', ordering: 'asc' }
|
||||
result = JSON.parse(response.body)
|
||||
expected = liabilities.sort { |a, b| b.credit <=> a.credit }
|
||||
|
||||
expect(result.map { |a| a['id'] }).to match_array expected.map { |e| e.id }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
262
spec/api/v2/admin/orders_spec.rb
Normal file
262
spec/api/v2/admin/orders_spec.rb
Normal file
@@ -0,0 +1,262 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Orders, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
|
||||
describe 'GET /api/v2/admin/orders' do
|
||||
before do
|
||||
# NOTE: We specify updated_at attribute for testing order of Order.
|
||||
create(:order_bid, :btcusd, price: '11'.to_d, origin_volume: '123.12', member: admin, updated_at: Time.at(1548224524), created_at: Time.at(1548234524))
|
||||
create(:order_bid, :btceth, price: '11'.to_d, origin_volume: '123.12', member: admin, updated_at: Time.at(1548234524), created_at: Time.at(1548254524))
|
||||
create(:order_bid, :btcusd, price: '12'.to_d, origin_volume: '123.12', member: admin, state: Order::CANCEL, updated_at: Time.at(1548244524), created_at: Time.at(1548254524))
|
||||
create(:order_ask, :btcusd, price: '13'.to_d, origin_volume: '123.12', member: admin, state: Order::WAIT, updated_at: Time.at(1548254524), created_at: Time.at(1548254524))
|
||||
create(:order_ask, :btcusd, price: '14'.to_d, origin_volume: '123.12', member: admin, state: Order::DONE, created_at: Time.at(1548254524))
|
||||
end
|
||||
|
||||
it 'csv export' do
|
||||
api_get'/api/v2/admin/orders', token: token, params: { format: :csv }
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'requires authentication' do
|
||||
get '/api/v2/admin/orders', params: { market: 'btcusd' }
|
||||
expect(response.code).to eq '401'
|
||||
end
|
||||
|
||||
it 'validates market param' do
|
||||
api_get '/api/v2/admin/orders', params: { market: 'usdusd' }, token: token
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.market.doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validates limit param' do
|
||||
api_get '/api/v2/admin/orders', params: { market: 'btcusd', limit: -1 }, token: token
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.pagination.invalid_limit')
|
||||
end
|
||||
|
||||
it 'validates price param' do
|
||||
api_get '/api/v2/admin/orders', params: { market: 'btcusd', price: -1 }, token: token
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.order.non_positive_price')
|
||||
end
|
||||
|
||||
it 'validates origin_volume param' do
|
||||
api_get '/api/v2/admin/orders', params: { market: 'btcusd', origin_volume: -1 }, token: token
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.order.non_positive_origin_volume')
|
||||
end
|
||||
|
||||
it 'validates page param' do
|
||||
api_get '/api/v2/admin/orders', params: { market: 'btcusd', limit: 2, page: "page 2" }, token: token
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.pagination.non_integer_page')
|
||||
end
|
||||
|
||||
it 'validates ord_type param' do
|
||||
api_get '/api/v2/admin/orders', params: { ord_type: 'test' }, token: token
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.order.invalid_ord_type')
|
||||
end
|
||||
|
||||
it 'returns orders with state done' do
|
||||
api_get '/api/v2/admin/orders', params: { market: 'btcusd', state: Order::DONE }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['state']).to eq Order::DONE
|
||||
end
|
||||
|
||||
it 'returns all my orders for btcusd market' do
|
||||
api_get '/api/v2/admin/orders', params: { market: 'btcusd' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.size).to eq 4
|
||||
end
|
||||
|
||||
it 'returns orders with ord_type limit' do
|
||||
api_get '/api/v2/admin/orders', params: { ord_type: 'limit' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['ord_type']}).to all eq 'limit'
|
||||
end
|
||||
|
||||
it 'returns orders with type sell' do
|
||||
api_get '/api/v2/admin/orders', params: { type: 'sell' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['side']}).to all eq 'sell'
|
||||
end
|
||||
|
||||
it 'returns orders for specific price' do
|
||||
api_get '/api/v2/admin/orders', params: { price: '11'.to_d }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['price']}.size).to eq 2
|
||||
expect(result.map{|r| r['price']}).to all eq '11.0'
|
||||
end
|
||||
|
||||
it 'returns orders for specific origin_volume' do
|
||||
api_get '/api/v2/admin/orders', params: { origin_volume: '123.12' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['origin_volume']}.size).to eq 5
|
||||
expect(result.map{|r| r['origin_volume']}).to all eq '123.12'
|
||||
end
|
||||
|
||||
it 'returns orders for specific user by email' do
|
||||
api_get '/api/v2/admin/orders', params: { email: 'example@gmail.com' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['email']}.size).to eq 5
|
||||
expect(result.map{|r| r['email']}).to all eq 'example@gmail.com'
|
||||
end
|
||||
|
||||
it 'returns orders for specific user by uid' do
|
||||
api_get '/api/v2/admin/orders', params: { uid: 'ID73BF61C8H0' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.map{|r| r['uid']}.size).to eq 5
|
||||
expect(result.map{|r| r['uid']}).to all eq 'ID73BF61C8H0'
|
||||
end
|
||||
|
||||
it 'returns paginated orders' do
|
||||
api_get '/api/v2/admin/orders', params: { market: 'btcusd', limit: 1, page: 1 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['price']).to eq '11.0'
|
||||
|
||||
api_get '/api/v2/admin/orders', params: { market: 'btcusd', limit: 1, page: 2 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['price']).to eq '12.0'
|
||||
end
|
||||
|
||||
it 'returns orders by ascending order' do
|
||||
api_get '/api/v2/admin/orders', params: { market: 'btcusd', ordering: 'asc', order_by: 'updated_at'}, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.first['price']).to eq '11.0'
|
||||
end
|
||||
|
||||
it 'returns orders for updated time range' do
|
||||
api_get '/api/v2/admin/orders', params: { range: 'updated', from: Time.at(1548224524).iso8601, to: Time.at(1548244524).iso8601 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.size).to eq 3
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get'/api/v2/admin/orders', token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/orders/:id/cancel' do
|
||||
let!(:order) { create(:order_bid, :btcusd, price: '12.32'.to_d, volume: '3.14', origin_volume: '12.13', locked: '20.1082', origin_locked: '38.0882', member: level_3_member) }
|
||||
|
||||
before do
|
||||
level_3_member.get_account(:usd).update_attributes(locked: order.price * order.volume)
|
||||
end
|
||||
|
||||
it 'should cancel specified order' do
|
||||
AMQP::Queue.expects(:enqueue).with(:matching, action: 'cancel', order: order.to_matching_attributes)
|
||||
expect do
|
||||
api_post "/api/v2/admin/orders/#{order.id}/cancel", token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['id']).to eq order.id
|
||||
end.not_to change(Order, :count)
|
||||
end
|
||||
|
||||
it 'return error in case of non existent order' do
|
||||
api_post '/api/v2/admin/orders/0/cancel', token: token
|
||||
expect(response.code).to eq '404'
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/orders/0/cancel', token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/orders/cancel' do
|
||||
before do
|
||||
create(:order_ask, :btcusd, price: '12.32', volume: '3.14', origin_volume: '12.13', member: level_3_member)
|
||||
create(:order_bid, :btcusd, price: '12.32', volume: '3.14', origin_volume: '12.13', member: level_3_member)
|
||||
create(:order_bid, :btceth, price: '12.32', volume: '3.14', origin_volume: '12.13', member: level_3_member)
|
||||
|
||||
level_3_member.get_account(:btc).update_attributes(locked: '5')
|
||||
level_3_member.get_account(:usd).update_attributes(locked: '50')
|
||||
end
|
||||
|
||||
it 'should cancel all my orders for specific market' do
|
||||
level_3_member.orders.where(market: 'btceth').each do |o|
|
||||
AMQP::Queue.expects(:enqueue).with(:matching, action: 'cancel', order: o.to_matching_attributes)
|
||||
end
|
||||
|
||||
expect do
|
||||
api_post '/api/v2/admin/orders/cancel', token: token, params: { market: 'btceth' }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.size).to eq 1
|
||||
end.not_to change(Order, :count)
|
||||
end
|
||||
|
||||
it 'should cancel all asks for specific market' do
|
||||
level_3_member.orders.where(type: 'OrderAsk', market_id: 'btcusd').each do |o|
|
||||
AMQP::Queue.expects(:enqueue).with(:matching, action: 'cancel', order: o.to_matching_attributes)
|
||||
end
|
||||
|
||||
expect do
|
||||
api_post '/api/v2/admin/orders/cancel', token: token, params: { market: 'btcusd', side: 'sell' }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.size).to eq 1
|
||||
expect(result.first['id']).to eq level_3_member.orders.where(type: 'OrderAsk').first.id
|
||||
end.not_to change(Order, :count)
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/orders/cancel', token: level_3_member_token, params: { market: 'btceth' }
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'return error in case of invalid order type' do
|
||||
api_post '/api/v2/admin/orders/cancel', token: token, params: { market: 'btceth', side: 'ask' }
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.order.invalid_side')
|
||||
end
|
||||
|
||||
it 'return error in case of invalid market' do
|
||||
api_post '/api/v2/admin/orders/cancel', token: token, params: { market: 'testusd' }
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.order.market_doesnt_exist')
|
||||
end
|
||||
end
|
||||
end
|
||||
230
spec/api/v2/admin/trades_spec.rb
Normal file
230
spec/api/v2/admin/trades_spec.rb
Normal file
@@ -0,0 +1,230 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Trades, type: :request do
|
||||
let(:uid) { 'ID00FEE1DEAD' }
|
||||
let(:email) { 'someone@mailbox.com' }
|
||||
let(:admin) { create(:member, :admin, :level_3, email: email, uid: uid) }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:member) { create(:member, :level_3) }
|
||||
let(:member_token) { jwt_for(member) }
|
||||
|
||||
describe 'GET /api/v2/admin/trades' do
|
||||
let!(:trades) do
|
||||
[
|
||||
create(:trade, :btcusd, price: 12.0, amount: 2.0, created_at: 3.days.ago),
|
||||
create(:trade, :btcusd, price: 3.0, amount: 13.0, created_at: 5.days.ago),
|
||||
create(:trade, :btcusd, price: 25.0, amount: 5.0, created_at: 1.days.ago, maker: member),
|
||||
create(:trade, :btcusd, price: 6.0, amount: 5.0, created_at: 5.days.ago, taker: member),
|
||||
create(:trade, :btcusd, price: 5.0, amount: 6.0, created_at: 5.days.ago, taker: member),
|
||||
]
|
||||
end
|
||||
|
||||
it 'entity provides correct fields' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { limit: 5 }
|
||||
result = JSON.parse(response.body).first
|
||||
keys = %w[id amount price total maker_order_email taker_order_email created_at maker_uid taker_uid
|
||||
taker_type market maker_fee_currency maker_fee_amount taker_fee_currency taker_fee_amount]
|
||||
|
||||
expect(result.keys).to match_array keys
|
||||
expect(result.values).not_to include nil
|
||||
end
|
||||
|
||||
it 'csv export' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { format: :csv }
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
context 'authentication' do
|
||||
it 'requires token' do
|
||||
get '/api/v2/admin/trades'
|
||||
expect(response.code).to eq '401'
|
||||
end
|
||||
|
||||
it 'validates permissions' do
|
||||
api_get'/api/v2/admin/trades', token: member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'authenticate admin' do
|
||||
api_get'/api/v2/admin/trades', token: token
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
context 'pagination' do
|
||||
it 'with default values' do
|
||||
api_get'/api/v2/admin/trades', token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result.length).to eq trades.length
|
||||
end
|
||||
|
||||
it 'validates limit' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { limit: 'meow' }
|
||||
expect(response).to include_api_error 'admin.pagination.non_integer_limit'
|
||||
end
|
||||
|
||||
it 'validates page' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { page: 'meow' }
|
||||
expect(response).to include_api_error 'admin.pagination.non_integer_page'
|
||||
end
|
||||
|
||||
it 'first 5 trades ordered by id' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { limit: 5 }
|
||||
result = JSON.parse(response.body)
|
||||
expected = trades[0...5]
|
||||
|
||||
expect(result.map { |t| t['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
|
||||
it 'second 5 trades ordered by id' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { limit: 5, page: 2 }
|
||||
result = JSON.parse(response.body)
|
||||
expected = trades[5...10]
|
||||
|
||||
expect(result.map { |t| t['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'ordering' do
|
||||
it 'validates ordering' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { ordering: 'straight' }
|
||||
|
||||
expect(response).not_to be_successful
|
||||
end
|
||||
|
||||
it 'orders by price ascending' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { order_by: 'price', ordering: 'asc' }
|
||||
result = JSON.parse(response.body)
|
||||
expected = trades.sort { |a, b| a.price <=> b.price }
|
||||
expect(result.map { |t| t['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
|
||||
it 'orders by amount descending' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { order_by: 'amount', ordering: 'asc' }
|
||||
result = JSON.parse(response.body)
|
||||
expected = trades.sort { |a, b| b.amount <=> a.amount }
|
||||
|
||||
expect(result.map { |t| t['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
context 'with market' do
|
||||
it 'validates market param' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { market: 'btcbtc' }
|
||||
expect(response).to include_api_error "admin.market.doesnt_exist"
|
||||
end
|
||||
|
||||
it 'filters by market' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { market: 'btcusd' }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expected = trades.select { |t| t.market_id == 'btcusd' }
|
||||
|
||||
expect(result.map { |t| t['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with uid' do
|
||||
it 'returns orders for specific user (both maker and taker sides)' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { uid: member.uid }
|
||||
result = JSON.parse(response.body)
|
||||
expected = member.trades
|
||||
|
||||
expect(result.map { |t| t['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
|
||||
it 'return error when user does not exist' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { uid: 'ID00DEADBEEF' }
|
||||
expect(response).to include_api_error 'admin.user.doesnt_exist'
|
||||
end
|
||||
|
||||
it 'empty collection when user has no trades' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { uid: admin.uid }
|
||||
expect(JSON.parse(response.body)).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'with timestamps' do
|
||||
it 'validates created_at_from' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { from: 'yesterday' }
|
||||
expect(response).to include_api_error 'admin.filter.range_from_invalid'
|
||||
end
|
||||
|
||||
it 'validates created_at_to' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { to: 'today' }
|
||||
expect(response).to include_api_error 'admin.filter.range_to_invalid'
|
||||
end
|
||||
|
||||
it 'returns trades created after specidfied date' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { from: 4.days.ago }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expected = trades.select { |t| t.created_at >= 4.days.ago }
|
||||
|
||||
expect(result.map { |t| t['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
|
||||
it 'return trades created before specidfied date' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { to: 2.days.ago }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expected = trades.select { |t| t.created_at < 2.days.ago }
|
||||
|
||||
expect(result.map { |t| t['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
|
||||
it 'returns trades created after and before specidfied dates' do
|
||||
api_get'/api/v2/admin/trades', token: token, params: { from: 4.days.ago, to: 2.days.ago }
|
||||
result = JSON.parse(response.body)
|
||||
expected = trades.select { |t| t.created_at >= 4.days.ago && t.created_at < 2.days.ago }
|
||||
|
||||
expect(result.map { |t| t['id'] }).to match_array expected.map(&:id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/trades/:id' do
|
||||
let(:maker) { create(:order_ask, :btcusd) }
|
||||
let(:taker) { create(:order_bid, :btcusd) }
|
||||
let(:trade) { create(:trade, :btcusd, price: 12.0, amount: 2.0, maker_order: maker, taker_order: taker) }
|
||||
|
||||
it 'entity provides correct fields' do
|
||||
api_get "/api/v2/admin/trades/#{trade.id}", token: token
|
||||
result = JSON.parse(response.body)
|
||||
keys = %w[id amount price total maker_order_email taker_order_email created_at maker_uid taker_uid taker_type
|
||||
market maker_fee_currency maker_fee maker_fee_amount taker_fee_currency taker_fee taker_fee_amount maker_order taker_order]
|
||||
|
||||
expect(result.keys).to match_array keys
|
||||
expect(result.values).not_to include nil
|
||||
end
|
||||
|
||||
it 'exposes correct orders' do
|
||||
api_get "/api/v2/admin/trades/#{trade.id}", token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result['maker_order']['id']).to eq maker.id
|
||||
expect(result['taker_order']['id']).to eq taker.id
|
||||
end
|
||||
|
||||
it 'fee calculation' do
|
||||
api_get "/api/v2/admin/trades/#{trade.id}", token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result['maker_fee_amount']).to eq((trade.total * maker.maker_fee).to_s)
|
||||
expect(result['taker_fee_amount']).to eq((trade.amount * taker.taker_fee).to_s)
|
||||
end
|
||||
|
||||
it 'fee currency' do
|
||||
api_get "/api/v2/admin/trades/#{trade.id}", token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result['maker_fee_currency']).to eq 'usd'
|
||||
expect(result['taker_fee_currency']).to eq 'btc'
|
||||
end
|
||||
end
|
||||
end
|
||||
266
spec/api/v2/admin/trading_fees_spec.rb
Normal file
266
spec/api/v2/admin/trading_fees_spec.rb
Normal file
@@ -0,0 +1,266 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::TradingFees, type: :request do
|
||||
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H1') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
|
||||
describe 'GET /trading_fees' do
|
||||
before do
|
||||
create(:trading_fee, maker: 0.0005, taker: 0.001, market_id: :btcusd, group: 'vip-0')
|
||||
create(:trading_fee, maker: 0.0008, taker: 0.001, market_id: :any, group: 'vip-0')
|
||||
create(:trading_fee, maker: 0.001, taker: 0.0012, market_id: :btcusd, group: :any)
|
||||
end
|
||||
|
||||
it 'returns all trading fees' do
|
||||
api_get '/api/v2/admin/trading_fees', token: token
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(JSON.parse(response.body).length).to eq TradingFee.count
|
||||
end
|
||||
|
||||
it 'pagination' do
|
||||
api_get '/api/v2/admin/trading_fees', token: token, params: { limit: 1 }
|
||||
expect(JSON.parse(response.body).length).to eq 1
|
||||
end
|
||||
|
||||
it 'filters by market_id' do
|
||||
api_get '/api/v2/admin/trading_fees', token: token, params: { market_id: 'btcusd' }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.map { |r| r['market_id'] }).to all eq 'btcusd'
|
||||
expect(result.length).to eq TradingFee.where(market_id: 'btcusd').count
|
||||
end
|
||||
|
||||
it 'filters by group' do
|
||||
api_get '/api/v2/admin/trading_fees', token: token, params: { group: 'vip-0' }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.map { |r| r['group'] }).to all eq 'vip-0'
|
||||
expect(result.length).to eq TradingFee.where(group: 'vip-0').count
|
||||
end
|
||||
|
||||
it 'capitalized fee group' do
|
||||
api_get '/api/v2/admin/trading_fees', token: token, params: { group: 'Vip-0' }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.map { |r| r['group'] }).to all eq 'vip-0'
|
||||
expect(result.length).to eq TradingFee.where(group: 'vip-0').count
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /trading_fees/new' do
|
||||
it 'creates a table with default group' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { maker: 0.001, taker: 0.0015, market_id: 'btcusd' }
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(JSON.parse(response.body)['maker']).to eq('0.001')
|
||||
expect(JSON.parse(response.body)['taker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['group']).to eq('any')
|
||||
expect(JSON.parse(response.body)['market_id']).to eq('btcusd')
|
||||
end
|
||||
|
||||
it 'creates a table with default market' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { group: 'vip-1', maker: 0.001, taker: 0.0015 }
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(JSON.parse(response.body)['maker']).to eq('0.001')
|
||||
expect(JSON.parse(response.body)['taker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['market_id']).to eq('any')
|
||||
end
|
||||
|
||||
it 'returns created trading fee table' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { group: 'vip-1', market_id: 'btcusd', maker: 0.001, taker: 0.0015 }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['maker']).to eq('0.001')
|
||||
expect(JSON.parse(response.body)['taker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['market_id']).to eq('btcusd')
|
||||
end
|
||||
|
||||
context 'returns created trading fee table without group' do
|
||||
it 'returns created trading fee table' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { market_id: 'btcusd', maker: 0.001, taker: 0.0015 }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['maker']).to eq('0.001')
|
||||
expect(JSON.parse(response.body)['taker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['group']).to eq('any')
|
||||
expect(JSON.parse(response.body)['market_id']).to eq('btcusd')
|
||||
end
|
||||
end
|
||||
|
||||
context 'returns created trading fee table without market_id' do
|
||||
it 'returns created trading fee table' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { maker: 0.001, taker: 0.0015, group: 'vip-1' }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['maker']).to eq('0.001')
|
||||
expect(JSON.parse(response.body)['taker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['market_id']).to eq('any')
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid market_id' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { maker: 0.001, taker: 0.0015, market_id: 'uahusd' }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.trading_fee.market_doesnt_exist')
|
||||
end
|
||||
end
|
||||
|
||||
context 'empty maker field' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { taker: 0.0015, group: 'vip-1', market_id: 'btcusd' }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.trading_fee.invalid_maker')
|
||||
end
|
||||
end
|
||||
|
||||
context 'empty taker field' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { maker: 0.0015, group: 'vip-1', market_id: 'btcusd' }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.trading_fee.invalid_taker')
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid maker/taker type' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { taker: -0.1, maker: -0.15, group: 'vip-1', market_id: 'btcusd' }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.trading_fee.invalid_maker')
|
||||
expect(response).to include_api_error('admin.trading_fee.invalid_taker')
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid maker/taker fee' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/trading_fees/new', token: token, params: { taker: 1, maker: 1, group: 'vip-1', market_id: 'btcusd' }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('Maker must be less than or equal to 0.5')
|
||||
expect(response).to include_api_error('Taker must be less than or equal to 0.5')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /trading_fees/update' do
|
||||
it 'returns updated trading fee table with new group' do
|
||||
api_post '/api/v2/admin/trading_fees/update', token: token, params: { group: 'vip-1', id: TradingFee.first.id }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['maker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['taker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['market_id']).to eq('any')
|
||||
end
|
||||
|
||||
it 'returns updated trading fee table with new group with capitalized letter' do
|
||||
api_post '/api/v2/admin/trading_fees/update', token: token, params: { group: 'Vip-1 ', id: TradingFee.first.id }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['maker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['taker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['market_id']).to eq('any')
|
||||
end
|
||||
|
||||
it 'returns updated trading fee table with new maker' do
|
||||
api_post '/api/v2/admin/trading_fees/update', token: token, params: { market_id: 'btcusd', id: TradingFee.first.id }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['maker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['taker']).to eq('0.0015')
|
||||
expect(JSON.parse(response.body)['group']).to eq('any')
|
||||
expect(JSON.parse(response.body)['market_id']).to eq('btcusd')
|
||||
end
|
||||
|
||||
it 'returns updated trading fee table with new maker, taker fields' do
|
||||
api_post '/api/v2/admin/trading_fees/update', token: token, params: { maker: 0.1, taker: 0.1, id: TradingFee.first.id }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['maker']).to eq('0.1')
|
||||
expect(JSON.parse(response.body)['taker']).to eq('0.1')
|
||||
expect(JSON.parse(response.body)['group']).to eq('any')
|
||||
expect(JSON.parse(response.body)['market_id']).to eq('any')
|
||||
end
|
||||
|
||||
context 'not found trading_fee table' do
|
||||
it 'returns status 404 and error' do
|
||||
api_post '/api/v2/admin/trading_fees/update', token: token, params: { id: TradingFee.last.id + 1 }
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'empty maker type' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/trading_fees/update', token: token, params: { maker: -1, id: TradingFee.first.id }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.trading_fee.invalid_maker')
|
||||
end
|
||||
end
|
||||
|
||||
context 'empty taker type' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/trading_fees/update', token: token, params: { taker: -1, id: TradingFee.first.id }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.trading_fee.invalid_taker')
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid maker/taker type' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/trading_fees/update', token: token, params: { market_id: 'uahusd', id: TradingFee.first.id }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.trading_fee.market_doesnt_exist')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /trading_fees/delete' do
|
||||
let!(:trading_fee) { create(:trading_fee) }
|
||||
|
||||
it 'requires id' do
|
||||
api_post '/api/v2/admin/trading_fees/delete', token: token
|
||||
expect(response).to include_api_error 'admin.tradingfee.missing_id'
|
||||
end
|
||||
|
||||
it 'deletes trading fee table' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/trading_fees/delete', token: token, params: { id: trading_fee.id }
|
||||
}.to change { TradingFee.count }.by(-1)
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
end
|
||||
|
||||
it 'returns deleted trading fee table' do
|
||||
api_post '/api/v2/admin/trading_fees/delete', token: token, params: { id: trading_fee.id }
|
||||
|
||||
expect(JSON.parse(response.body)['id']).to eq trading_fee.id
|
||||
end
|
||||
|
||||
it 'retuns 404 if record does not exist' do
|
||||
expect {
|
||||
api_post '/api/v2/admin/trading_fees/delete', token: token, params: { id: TradingFee.last.id + 42 }
|
||||
}.not_to change { TradingFee.count }
|
||||
|
||||
expect(response.status).to eq 404
|
||||
end
|
||||
end
|
||||
end
|
||||
358
spec/api/v2/admin/wallets_spec.rb
Normal file
358
spec/api/v2/admin/wallets_spec.rb
Normal file
@@ -0,0 +1,358 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Wallets, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
|
||||
describe 'GET /api/v2/admin/wallets/:id' do
|
||||
let(:wallet) { Wallet.find_by(blockchain_key: 'eth-rinkeby') }
|
||||
|
||||
it 'returns information about specified wallet' do
|
||||
api_get "/api/v2/admin/wallets/#{wallet.id}", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.fetch('id')).to eq wallet.id
|
||||
expect(result.fetch('currencies')).to eq wallet.currency_ids
|
||||
expect(result.fetch('address')).to eq wallet.address
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid id' do
|
||||
api_get '/api/v2/admin/wallets/120', token: token
|
||||
|
||||
expect(response.code).to eq '404'
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get "/api/v2/admin/wallets/#{wallet.id}", token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'returns information about specified wallet' do
|
||||
api_get "/api/v2/admin/wallets/#{wallet.id}", token: token
|
||||
expect(response).to be_successful
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result).not_to include('settings')
|
||||
end
|
||||
|
||||
it 'returns NA balance if node not accessible' do
|
||||
wallet.update(balance: wallet.current_balance)
|
||||
api_get "/api/v2/admin/wallets/#{wallet.id}", token: token
|
||||
expect(response).to be_successful
|
||||
expect(response_body['balance']).to eq(wallet.current_balance)
|
||||
end
|
||||
|
||||
it 'returns wallet balance if node accessible' do
|
||||
wallet.update(balance: { 'eth' => '1'})
|
||||
|
||||
api_get "/api/v2/admin/wallets/#{wallet.id}", token: token
|
||||
expect(response).to be_successful
|
||||
expect(response_body['balance']).to eq({ 'eth' => '1' })
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/wallets' do
|
||||
it 'lists of wallets' do
|
||||
api_get '/api/v2/admin/wallets', token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq Wallet.count
|
||||
end
|
||||
|
||||
it 'returns paginated wallets' do
|
||||
api_get '/api/v2/admin/wallets', params: { limit: 6, page: 1 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
|
||||
expect(response.headers.fetch('Total')).to eq Wallet.count.to_s
|
||||
expect(result.size).to eq 6
|
||||
expect(result.first['name']).to eq 'Ethereum Deposit Wallet'
|
||||
|
||||
api_get '/api/v2/admin/wallets', params: { limit: 6, page: 2 }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
|
||||
expect(response.headers.fetch('Total')).to eq Wallet.count.to_s
|
||||
expect(result.size).to eq 2
|
||||
expect(result.first['name']).to eq 'Bitcoin Hot Wallet'
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get "/api/v2/admin/wallets", token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
it 'filters by blockchain key' do
|
||||
api_get "/api/v2/admin/wallets", token: token, params: { blockchain_key: "eth-rinkeby" }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result.length).not_to eq 0
|
||||
expect(result.map { |r| r["blockchain_key"]}).to all eq "eth-rinkeby"
|
||||
end
|
||||
|
||||
it 'filters by kind'do
|
||||
api_get "/api/v2/admin/wallets", token: token, params: { kind: "deposit" }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result.length).not_to eq 0
|
||||
expect(result.map { |r| r["kind"]}).to all eq "deposit"
|
||||
end
|
||||
|
||||
context do
|
||||
let(:hot_wallet) { Wallet.joins(:currencies).find_by(blockchain_key: 'eth-rinkeby', kind: :hot, currencies: { id: :eth }) }
|
||||
|
||||
before do
|
||||
hot_wallet.currencies << Currency.find(:trst)
|
||||
end
|
||||
|
||||
it 'filters by currency' do
|
||||
api_get '/api/v2/admin/wallets', token: token, params: { currencies: 'eth' }
|
||||
|
||||
expect(response_body.length).not_to eq 0
|
||||
expect(response_body.pluck('currencies').map { |a| a.include?('eth') }.all?).to eq(true)
|
||||
count = Wallet.joins(:currencies).where(currencies: { id: :eth }).count
|
||||
expect(response_body.find { |c| c['id'] == hot_wallet.id }['currencies'].sort).to eq(%w[eth trst])
|
||||
expect(response_body.count).to eq(count)
|
||||
end
|
||||
|
||||
it 'filters by currency' do
|
||||
api_get '/api/v2/admin/wallets', token: token, params: { currencies: %w[eth trst] }
|
||||
|
||||
expect(response_body.length).not_to eq 0
|
||||
count = Wallet.joins(:currencies).where(currencies: { id: %i[eth trst] }).distinct.count
|
||||
expect(response_body.find { |c| c['id'] == hot_wallet.id }['currencies'].sort).to eq(%w[eth trst])
|
||||
expect(response_body.count).to eq(count)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/wallets/kinds' do
|
||||
it 'list kinds' do
|
||||
api_get '/api/v2/admin/wallets/kinds', token: token
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/wallets/gateways' do
|
||||
it 'list gateways' do
|
||||
api_get '/api/v2/admin/wallets/gateways', token: token
|
||||
expect(response).to be_successful
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/wallets/new' do
|
||||
it 'create wallet' do
|
||||
api_post '/api/v2/admin/wallets/new', params: { name: 'Test', kind: 'deposit', currencies: 'eth', address: 'blank', blockchain_key: 'btc-testnet', gateway: 'geth', settings: { uri: 'http://127.0.0.1:18332'}}, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['name']).to eq 'Test'
|
||||
end
|
||||
|
||||
it 'create wallet' do
|
||||
api_post '/api/v2/admin/wallets/new', params: { name: 'Test', kind: 'deposit', currencies: ['eth','trst'], address: 'blank', blockchain_key: 'btc-testnet', gateway: 'geth', settings: { uri: 'http://127.0.0.1:18332'}}, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['currencies']).to eq(['eth', 'trst'])
|
||||
expect(result['name']).to eq 'Test'
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_post '/api/v2/admin/wallets/new', params: { }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.wallet.missing_name')
|
||||
expect(response).to include_api_error('admin.wallet.missing_kind')
|
||||
expect(response).to include_api_error('admin.wallet.currencies_field_is_missing')
|
||||
expect(response).to include_api_error('admin.wallet.missing_blockchain_key')
|
||||
expect(response).to include_api_error('admin.wallet.missing_gateway')
|
||||
end
|
||||
|
||||
it 'validate status' do
|
||||
api_post '/api/v2/admin/wallets/new', params: { name: 'Test', kind: 'deposit', currencies: 'eth', address: 'blank', blockchain_key: 'btc-testnet', gateway: 'geth', settings: { uri: 'http://127.0.0.1:18332'}, status: 'disable' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.invalid_status')
|
||||
end
|
||||
|
||||
it 'validate gateway' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { name: 'Test', kind: 'deposit', currencies: 'eth', address: 'blank', blockchain_key: 'btc-testnet', settings: { uri: 'http://127.0.0.1:18332'}, gateway: 'test' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.gateway_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate kind' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { name: 'Test', kind: 'test', currencies: 'eth', address: 'blank', blockchain_key: 'btc-testnet', settings: { uri: 'http://127.0.0.1:18332'}, gateway: 'geth' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.invalid_kind')
|
||||
end
|
||||
|
||||
it 'validate currency_id' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: 1, name: 'Test', kind: 'deposit', address: 'blank', blockchain_key: 'btc-testnet', gateway: 'geth', settings: { uri: 'http://127.0.0.1:18332'}, currencies: 'test' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.currency_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate uri' do
|
||||
api_post '/api/v2/admin/wallets/new', params: { name: 'Test', kind: 'hot', currencies: 'eth', address: 'blank', blockchain_key: 'btc-testnet', settings: { uri: 'invalid_uri'}, gateway: 'geth' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.invalid_uri_setting')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/wallets/new', params: { name: 'Test', kind: 'deposit', currencies: 'eth', address: 'blank', blockchain_key: 'btc-testnet', gateway: 'geth', settings: { uri: 'http://127.0.0.1:18332'}}, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/wallets/update' do
|
||||
it 'update wallet' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, gateway: 'geth' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['gateway']).to eq 'geth'
|
||||
end
|
||||
|
||||
it 'update currency' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, currencies: 'btc' }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['currencies']).to eq ['btc']
|
||||
end
|
||||
|
||||
it 'update wallet with new secret' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, currencies: 'btc', settings: { secret: 'new secret'} }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['currencies']).to eq ['btc']
|
||||
expect(Wallet.first.settings['uri']).to eq nil
|
||||
expect(Wallet.first.settings['secret']).to eq 'new secret'
|
||||
end
|
||||
|
||||
it 'update wallet with settings' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, currencies: 'btc', settings: { secret: 'new secret', access_token: 'new token'} }, token: token
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['currencies']).to eq ['btc']
|
||||
expect(Wallet.first.settings['uri']).to eq nil
|
||||
expect(Wallet.first.settings['access_token']).to eq 'new token'
|
||||
expect(Wallet.first.settings['secret']).to eq 'new secret'
|
||||
end
|
||||
|
||||
it 'validate blockchain_key' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, blockchain_key: 'test' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.blockchain_key_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate status' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, status: 'disable' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.invalid_status')
|
||||
end
|
||||
|
||||
it 'validate gateway' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, gateway: 'test' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.gateway_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate kind' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, kind: 'test' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.invalid_kind')
|
||||
end
|
||||
|
||||
it 'validate currency_id' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, currencies: 'test ' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.currency_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.wallet.missing_id')
|
||||
end
|
||||
|
||||
it 'validate uri' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, name: 'Test', kind: 'hot', currencies: 'eth', address: 'blank', blockchain_key: 'btc-testnet', settings: { uri: 'invalid_uri'}, gateway: 'geth' }, token: token
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.wallet.invalid_uri_setting')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/wallets/update', params: { id: Wallet.first.id, status: 'disabled' }, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/wallets/currencies' do
|
||||
let(:wallet) { Wallet.joins(:currencies).find_by(currencies: { id: 'eth' }) }
|
||||
|
||||
it do
|
||||
api_post '/api/v2/admin/wallets/currencies', params: { id: wallet.id, currencies: 'trst' }, token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response_body['currencies'].include?('trst')).to be_truthy
|
||||
end
|
||||
|
||||
it do
|
||||
api_post '/api/v2/admin/wallets/currencies', params: { id: wallet.id, currencies: 'eth' }, token: token
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('Currency has already been taken')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/wallets/currencies' do
|
||||
let(:wallet) { Wallet.joins(:currencies).find_by(currencies: { id: 'eth' }) }
|
||||
|
||||
it do
|
||||
api_delete '/api/v2/admin/wallets/currencies', params: { id: wallet.id, currencies: 'eth' }, token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(response_body['currencies'].include?('eth')).to be_falsey
|
||||
end
|
||||
|
||||
it do
|
||||
api_delete '/api/v2/admin/wallets/currencies', params: { id: wallet.id, currencies: 'trst' }, token: token
|
||||
|
||||
expect(response).to have_http_status 404
|
||||
end
|
||||
end
|
||||
end
|
||||
201
spec/api/v2/admin/whitelisted_smart_contracts_spec.rb
Normal file
201
spec/api/v2/admin/whitelisted_smart_contracts_spec.rb
Normal file
@@ -0,0 +1,201 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::WhitelistedSmartContracts, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example15@gmail.com', uid: 'ID73BF61C8H1') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
let(:test_file) { Rack::Test::UploadedFile.new(Rails.root.join('spec', 'resources', 'whitelisted_addresses', file_name), 'text/csv') }
|
||||
let(:file_name) { '1.csv' }
|
||||
|
||||
describe 'GET /api/v2/admin/whitelisted_smart_contract/:id' do
|
||||
let!(:addresses_1) { create(:whitelisted_smart_contract, :address_1) }
|
||||
let!(:addresses_2) { create(:whitelisted_smart_contract, :address_2) }
|
||||
let!(:addresses_3) { create(:whitelisted_smart_contract, :address_3) }
|
||||
let!(:addresses_4) { create(:whitelisted_smart_contract, :address_4) }
|
||||
let!(:addresses_5) { create(:whitelisted_smart_contract, :address_5) }
|
||||
|
||||
let(:whitelisted_address) { WhitelistedSmartContract.find(1) }
|
||||
|
||||
it 'returns information about specified WhitelistedSmartContract' do
|
||||
api_get "/api/v2/admin/whitelisted_smart_contract/#{whitelisted_address.id}", token: token
|
||||
expect(response).to be_successful
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.fetch('id')).to eq whitelisted_address.id
|
||||
expect(result.fetch('address')).to eq whitelisted_address.address
|
||||
end
|
||||
|
||||
it 'returns error in case of invalid id' do
|
||||
api_get '/api/v2/admin/whitelisted_smart_contract/120', token: token
|
||||
|
||||
expect(response.code).to eq '404'
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get "/api/v2/admin/whitelisted_smart_contract/#{whitelisted_address.id}", token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/whitelisted_smart_contracts' do
|
||||
let!(:addresses_1) { create(:whitelisted_smart_contract, :address_1) }
|
||||
let!(:addresses_2) { create(:whitelisted_smart_contract, :address_2) }
|
||||
let!(:addresses_3) { create(:whitelisted_smart_contract, :address_3) }
|
||||
let!(:addresses_4) { create(:whitelisted_smart_contract, :address_4) }
|
||||
let!(:addresses_5) { create(:whitelisted_smart_contract, :address_5) }
|
||||
|
||||
it 'lists of whitelisted_smart_contracts' do
|
||||
api_get '/api/v2/admin/whitelisted_smart_contracts', token: token
|
||||
|
||||
expect(response).to be_successful
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.size).to eq WhitelistedSmartContract.count
|
||||
end
|
||||
|
||||
it 'returns paginated whitelisted_smart_contracts' do
|
||||
api_get '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { limit: 4, page: 1 }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
|
||||
expect(response.headers.fetch('Total')).to eq WhitelistedSmartContract.count.to_s
|
||||
expect(result.size).to eq 4
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_get "/api/v2/admin/whitelisted_smart_contracts", token: level_3_member_token
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
it 'filters by blockchain key' do
|
||||
api_get "/api/v2/admin/whitelisted_smart_contracts", token: token, params: { blockchain_key: "eth-rinkeby" }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(result.length).not_to eq 0
|
||||
expect(result.map { |r| r["blockchain_key"]}).to all eq "eth-rinkeby"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/whitelisted_smart_contracts/csv' do
|
||||
it 'create whitelisted_smart_contracts from csv' do
|
||||
api_post '/api/v2/admin/whitelisted_smart_contracts/csv', token: token, params: { file: test_file }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result.size).to eq 3
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/whitelisted_smart_contracts' do
|
||||
it 'create whitelisted_smart_contracts' do
|
||||
api_post '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { description: 'Test', address: 'blank', blockchain_key: 'eth-rinkeby' }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['description']).to eq 'Test'
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_post '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { }
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.whitelistedsmartcontract.missing_address')
|
||||
expect(response).to include_api_error('admin.whitelistedsmartcontract.missing_blockchain_key')
|
||||
end
|
||||
|
||||
it 'validate state' do
|
||||
api_post '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { description: 'Test', address: 'blank', blockchain_key: 'eth-rinkeby', state: 'invalid' }
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.whitelistedsmartcontract.invalid_state')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_post '/api/v2/admin/whitelisted_smart_contracts', params: { description: 'Test', address: 'blank', blockchain_key: 'eth-rinkeby'}, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /api/v2/admin/whitelisted_smart_contracts' do
|
||||
let!(:addresses_1) { create(:whitelisted_smart_contract, :address_1) }
|
||||
|
||||
it 'update WhitelistedSmartContract' do
|
||||
api_put '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { id: WhitelistedSmartContract.first.id, address: 'test' }
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(result['address']).to eq 'test'
|
||||
end
|
||||
|
||||
it 'update WhitelistedSmartContract with new description' do
|
||||
api_put '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { id: WhitelistedSmartContract.first.id, description: 'test'}
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(WhitelistedSmartContract.first.description).to eq 'test'
|
||||
end
|
||||
|
||||
it 'update WhitelistedSmartContract with new state' do
|
||||
api_put '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { id: WhitelistedSmartContract.first.id, state: 'disabled' }
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(WhitelistedSmartContract.first.state).to eq 'disabled'
|
||||
end
|
||||
|
||||
it 'validate blockchain_key' do
|
||||
api_put '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { id: WhitelistedSmartContract.first.id, blockchain_key: 'test' }
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.whitelistedsmartcontract.blockchain_key_doesnt_exist')
|
||||
end
|
||||
|
||||
it 'validate status' do
|
||||
api_put '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { id: WhitelistedSmartContract.first.id, state: 'disable' }
|
||||
|
||||
expect(response.code).to eq '422'
|
||||
expect(response).to include_api_error('admin.whitelistedsmartcontract.invalid_state')
|
||||
end
|
||||
|
||||
it 'checked required params' do
|
||||
api_put '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { }
|
||||
|
||||
expect(response).to have_http_status 422
|
||||
expect(response).to include_api_error('admin.whitelistedsmartcontract.missing_id')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_put '/api/v2/admin/whitelisted_smart_contracts', params: { id: WhitelistedSmartContract.first.id, status: 'disabled' }, token: level_3_member_token
|
||||
|
||||
expect(response.code).to eq '403'
|
||||
expect(response).to include_api_error('admin.ability.not_permitted')
|
||||
end
|
||||
|
||||
it 'return error in case of not permitted ability' do
|
||||
api_put '/api/v2/admin/whitelisted_smart_contracts', params: { id: WhitelistedSmartContract.last.id + 1, status: 'disabled' }, token: token
|
||||
|
||||
expect(response.code).to eq '404'
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
|
||||
context 'rails validations' do
|
||||
let!(:addresses_1) { create(:whitelisted_smart_contract, :address_1) }
|
||||
let!(:addresses_2) { create(:whitelisted_smart_contract, :address_2) }
|
||||
|
||||
it 'returns error' do
|
||||
api_put '/api/v2/admin/whitelisted_smart_contracts', token: token, params: { id: WhitelistedSmartContract.first.id, address: addresses_2.address }
|
||||
|
||||
expect(response).to include_api_error 'Address has already been taken'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
248
spec/api/v2/admin/withdraw_limts_spec.rb
Normal file
248
spec/api/v2/admin/withdraw_limts_spec.rb
Normal file
@@ -0,0 +1,248 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::WithdrawLimits, type: :request do
|
||||
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
|
||||
describe 'GET /withdraw_limits' do
|
||||
before do
|
||||
create(:withdraw_limit, limit_24_hour: 100, limit_1_month: 1000, kyc_level: 2, group: 'vip-0')
|
||||
create(:withdraw_limit, limit_24_hour: 50, limit_1_month: 500, kyc_level: 1, group: 'vip-0')
|
||||
create(:withdraw_limit, limit_24_hour: 50, limit_1_month: 500, kyc_level: 1, group: :any)
|
||||
end
|
||||
|
||||
it 'returns all withdraw limits' do
|
||||
api_get '/api/v2/admin/withdraw_limits', token: token
|
||||
|
||||
expect(response.status).to eq 200
|
||||
expect(JSON.parse(response.body).length).to eq WithdrawLimit.count
|
||||
end
|
||||
|
||||
it 'pagination' do
|
||||
api_get '/api/v2/admin/withdraw_limits', token: token, params: { limit: 1 }
|
||||
expect(JSON.parse(response.body).length).to eq 1
|
||||
end
|
||||
|
||||
it 'filters by group' do
|
||||
api_get '/api/v2/admin/withdraw_limits', token: token, params: { group: 'vip-0' }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.map { |r| r['group'] }).to all eq 'vip-0'
|
||||
expect(result.length).to eq WithdrawLimit.where(group: 'vip-0').count
|
||||
end
|
||||
|
||||
it 'filters by kyc_level' do
|
||||
api_get '/api/v2/admin/withdraw_limits', token: token, params: { kyc_level: '1' }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.map { |r| r['kyc_level'] }).to all eq '1'
|
||||
expect(result.length).to eq WithdrawLimit.where(kyc_level: '1').count
|
||||
end
|
||||
|
||||
it 'capitalized group' do
|
||||
api_get '/api/v2/admin/withdraw_limits', token: token, params: { group: 'Vip-0' }
|
||||
|
||||
result = JSON.parse(response.body)
|
||||
expect(result.map { |r| r['group'] }).to all eq 'vip-0'
|
||||
expect(result.length).to eq WithdrawLimit.where(group: 'vip-0').count
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /withdraw_limits' do
|
||||
it 'creates a table with default group' do
|
||||
api_post '/api/v2/admin/withdraw_limits', token: token, params: { kyc_level: 1, limit_24_hour: 100, limit_1_month: 1000 }
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('100.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('1000.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('any')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('1')
|
||||
end
|
||||
|
||||
it 'creates a table with default kyc_level' do
|
||||
api_post '/api/v2/admin/withdraw_limits', token: token, params: { group: 'vip-1', limit_24_hour: 100, limit_1_month: 1000 }
|
||||
|
||||
expect(response).to be_successful
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('100.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('1000.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('any')
|
||||
end
|
||||
|
||||
it 'returns created withdraw limit table' do
|
||||
api_post '/api/v2/admin/withdraw_limits', token: token, params: { kyc_level: 4, group: 'vip-1', limit_24_hour: 100, limit_1_month: 1000 }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('100.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('1000.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('4')
|
||||
end
|
||||
|
||||
context 'returns created withdraw limit table without group' do
|
||||
it 'returns created withdraw limit table' do
|
||||
api_post '/api/v2/admin/withdraw_limits', token: token, params: { kyc_level: 1, limit_24_hour: 100, limit_1_month: 1000 }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('100.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('1000.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('any')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('1')
|
||||
end
|
||||
end
|
||||
|
||||
context 'returns created withdraw limit table without kyc_level' do
|
||||
it 'returns created withdraw limit table' do
|
||||
api_post '/api/v2/admin/withdraw_limits', token: token, params: { limit_24_hour: 100, limit_1_month: 1000, group: 'vip-1' }
|
||||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('100.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('1000.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('any')
|
||||
end
|
||||
end
|
||||
|
||||
context 'empty limit_24_hour field' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/withdraw_limits', token: token, params: { limit_1_month: 1000, group: 'vip-1' }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.withdraw_limit.invalid_limit_24_hour')
|
||||
end
|
||||
end
|
||||
|
||||
context 'empty limit_1_month field' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/withdraw_limits', token: token, params: { limit_24_hour: 1000, group: 'vip-1' }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.withdraw_limit.invalid_limit_1_month')
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid limit_24_hour/limit_1_month value' do
|
||||
it 'returns status 422 and error' do
|
||||
api_post '/api/v2/admin/withdraw_limits', token: token, params: { limit_1_month: -1, limit_24_hour: -15, group: 'vip-1' }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.withdraw_limit.invalid_limit_24_hour')
|
||||
expect(response).to include_api_error('admin.withdraw_limit.invalid_limit_1_month')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /withdraw_limits' do
|
||||
it 'returns updated withdraw limit table with new kyc_level' do
|
||||
api_put '/api/v2/admin/withdraw_limits', token: token, params: { kyc_level: '3', id: WithdrawLimit.first.id }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('9999.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('999999.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('any')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('3')
|
||||
end
|
||||
|
||||
it 'returns updated withdraw limit table with new group' do
|
||||
api_put '/api/v2/admin/withdraw_limits', token: token, params: { group: 'vip-1', id: WithdrawLimit.first.id }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('9999.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('999999.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('any')
|
||||
end
|
||||
|
||||
it 'returns updated withdraw limit table with new group with capitalized letter' do
|
||||
api_put '/api/v2/admin/withdraw_limits', token: token, params: { group: 'Vip-1 ', id: WithdrawLimit.first.id }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('9999.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('999999.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('vip-1')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('any')
|
||||
end
|
||||
|
||||
it 'returns updated withdraw limit table with new limit_24_hour' do
|
||||
api_put '/api/v2/admin/withdraw_limits', token: token, params: { id: WithdrawLimit.first.id }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('9999.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('999999.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('any')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('any')
|
||||
end
|
||||
|
||||
it 'returns updated withdraw limit table with new limit_24_hour, limit_1_month fields' do
|
||||
api_put '/api/v2/admin/withdraw_limits', token: token, params: { limit_24_hour: 10, limit_1_month: 100, id: WithdrawLimit.first.id }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(JSON.parse(response.body)['limit_24_hour']).to eq('10.0')
|
||||
expect(JSON.parse(response.body)['limit_1_month']).to eq('100.0')
|
||||
expect(JSON.parse(response.body)['group']).to eq('any')
|
||||
expect(JSON.parse(response.body)['kyc_level']).to eq('any')
|
||||
end
|
||||
|
||||
context 'not found withdraw_limit table' do
|
||||
it 'returns status 404 and error' do
|
||||
api_put '/api/v2/admin/withdraw_limits', token: token, params: { id: WithdrawLimit.last.id + 1 }
|
||||
|
||||
expect(response).to have_http_status(404)
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'empty limit_24_hour type' do
|
||||
it 'returns status 422 and error' do
|
||||
api_put '/api/v2/admin/withdraw_limits', token: token, params: { limit_24_hour: -1, id: WithdrawLimit.first.id }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.withdraw_limit.invalid_limit_24_hour')
|
||||
end
|
||||
end
|
||||
|
||||
context 'empty limit_1_month type' do
|
||||
it 'returns status 422 and error' do
|
||||
api_put '/api/v2/admin/withdraw_limits', token: token, params: { limit_1_month: -1, id: WithdrawLimit.first.id }
|
||||
|
||||
expect(response).to have_http_status(422)
|
||||
expect(response).to include_api_error('admin.withdraw_limit.invalid_limit_1_month')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE /withdraw_limits' do
|
||||
let!(:withdraw_limit) { create(:withdraw_limit, kyc_level: 1) }
|
||||
|
||||
it 'id has invalid type' do
|
||||
api_delete '/api/v2/admin/withdraw_limits/id', token: token
|
||||
expect(response).to include_api_error 'admin.withdraw_limit.non_integer_id'
|
||||
end
|
||||
|
||||
it 'deletes withdraw limit table' do
|
||||
expect {
|
||||
api_delete "/api/v2/admin/withdraw_limits/#{withdraw_limit.id}", token: token
|
||||
}.to change { WithdrawLimit.count }.by(-1)
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'returns deleted withdraw limit table' do
|
||||
api_delete "/api/v2/admin/withdraw_limits/#{withdraw_limit.id}", token: token
|
||||
|
||||
expect(JSON.parse(response.body)['id']).to eq withdraw_limit.id
|
||||
end
|
||||
|
||||
it 'retuns 404 if record does not exist' do
|
||||
expect {
|
||||
api_delete "/api/v2/admin/withdraw_limits/#{WithdrawLimit.last.id + 42}", token: token
|
||||
}.not_to change { WithdrawLimit.count }
|
||||
|
||||
expect(response.status).to eq 404
|
||||
end
|
||||
end
|
||||
end
|
||||
323
spec/api/v2/admin/withdraws_spec.rb
Normal file
323
spec/api/v2/admin/withdraws_spec.rb
Normal file
@@ -0,0 +1,323 @@
|
||||
# encoding: UTF-8
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe API::V2::Admin::Withdraws, type: :request do
|
||||
let(:admin) { create(:member, :admin, :level_3, email: 'example@gmail.com', uid: 'ID73BF61C8H0') }
|
||||
let(:token) { jwt_for(admin) }
|
||||
let(:level_3_member) { create(:member, :level_3) }
|
||||
let(:level_3_member_token) { jwt_for(level_3_member) }
|
||||
before do
|
||||
[admin, level_3_member].each do |member|
|
||||
member.touch_accounts
|
||||
member.accounts.map { |a| a.update(balance: 500) }
|
||||
end
|
||||
|
||||
create(:usd_withdraw, amount: 10.0, sum: 10.0, member: admin)
|
||||
create(:usd_withdraw, amount: 9.0, sum: 9.0, member: admin)
|
||||
create(:usd_withdraw, amount: 100.0, sum: 100.0, member: level_3_member)
|
||||
create(:btc_withdraw, amount: 42.0, sum: 42.0, txid: 'special_txid', member: admin)
|
||||
create(:btc_withdraw, amount: 42.0, sum: 42.0, member: admin, aasm_state: :accepted)
|
||||
create(:btc_withdraw, amount: 11.0, sum: 11.0, member: level_3_member, aasm_state: :skipped)
|
||||
create(:btc_withdraw, amount: 12.0, sum: 12.0, member: level_3_member, aasm_state: :errored)
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/withdraws' do
|
||||
let(:url) { '/api/v2/admin/withdraws' }
|
||||
|
||||
it 'get all withdraws' do
|
||||
api_get url, token: token
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = Withdraw.all
|
||||
|
||||
expect(actual.length).to eq expected.length
|
||||
expect(actual.map { |a| a['state'] }).to match_array expected.map(&:aasm_state)
|
||||
expect(actual.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
expect(actual.map { |a| a['currency'] }).to match_array expected.map(&:currency_id)
|
||||
expect(actual.map { |a| a['member'] }).to match_array expected.map(&:member_id)
|
||||
expect(actual.map { |a| a['type'] }).to match_array(expected.map { |d| d.currency.coin? ? 'coin' : 'fiat' })
|
||||
expect(actual.map { |a| a['uid'] }).to match_array(expected.map { |d| d.member.uid })
|
||||
expect(actual.map { |a| a['email'] }).to match_array(expected.map { |d| d.member.email })
|
||||
end
|
||||
|
||||
context 'ordering' do
|
||||
it 'ascending by id' do
|
||||
api_get url, token: token, params: { order_by: 'id', ordering: 'asc' }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = Withdraw.order(id: 'asc')
|
||||
|
||||
expect(actual.map { |a| a['id'] }).to eq expected.map(&:id)
|
||||
end
|
||||
|
||||
it 'descending by sum' do
|
||||
api_get url, token: token, params: { order_by: 'sum', ordering: 'desc' }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = Withdraw.order(sum: 'desc')
|
||||
|
||||
expect(actual.map { |a| a['id'] }).to eq expected.map(&:id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'filtering' do
|
||||
it 'by member' do
|
||||
api_get url, token: token, params: { uid: level_3_member.uid }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = Withdraw.where(member_id: level_3_member.id)
|
||||
|
||||
expect(actual.length).to eq expected.length
|
||||
expect(actual.map { |a| a['state'] }).to match_array expected.map(&:aasm_state)
|
||||
expect(actual.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
expect(actual.map { |a| a['currency'] }).to match_array expected.map(&:currency_id)
|
||||
expect(actual.map { |a| a['member'] }).to all eq level_3_member.id
|
||||
expect(actual.map { |a| a['type'] }).to match_array(expected.map { |d| d.currency.coin? ? 'coin' : 'fiat' })
|
||||
expect(actual.map { |a| a['uid'] }).to match_array(expected.map { |d| d.member.uid })
|
||||
expect(actual.map { |a| a['email'] }).to match_array(expected.map { |d| d.member.email })
|
||||
end
|
||||
|
||||
it 'by state' do
|
||||
api_get url, token: token, params: { state: :skipped }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = Withdraw.where(aasm_state: :skipped)
|
||||
|
||||
expect(actual.map { |a| a['state'] }).to all eq 'skipped'
|
||||
expect(actual.length).to eq expected.count
|
||||
expect(actual.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
expect(actual.map { |a| a['uid'] }).to match_array(expected.map { |d| d.member.uid })
|
||||
end
|
||||
|
||||
it 'by multiple states' do
|
||||
api_get url, token: token, params: { state: [:skipped, :accepted] }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = Withdraw.where(aasm_state: [:skipped, :accepted])
|
||||
|
||||
expect(actual.map { |a| a['state'] }.uniq).to match_array %w[skipped accepted]
|
||||
expect(actual.length).to eq expected.count
|
||||
expect(actual.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
expect(actual.map { |a| a['uid'] }).to match_array(expected.map { |d| d.member.uid })
|
||||
end
|
||||
|
||||
it 'by type' do
|
||||
api_get url, token: token, params: { type: 'coin' }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = Withdraw.where(type: 'Withdraws::Coin')
|
||||
|
||||
expect(actual.length).to eq expected.length
|
||||
expect(actual.map { |a| a['state'] }).to match_array expected.map(&:aasm_state)
|
||||
expect(actual.map { |a| a['id'] }).to match_array expected.map(&:id)
|
||||
expect(actual.map { |a| a['currency'] }).to match_array expected.map(&:currency_id)
|
||||
expect(actual.map { |a| a['member'] }).to match_array expected.map(&:member_id)
|
||||
expect(actual.map { |a| a['type'] }).to all eq 'coin'
|
||||
end
|
||||
|
||||
it 'by txid' do
|
||||
api_get url, token: token, params: { txid: Withdraw.where(type: 'Withdraws::Coin').first.txid }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
expected = Withdraw.where(type: 'Withdraws::Coin').first
|
||||
|
||||
expect(actual.length).to eq 1
|
||||
expect(actual.first['state']).to eq expected.aasm_state
|
||||
expect(actual.first['id']).to eq expected.id
|
||||
expect(actual.first['currency']).to eq expected.currency_id
|
||||
expect(actual.first['member']).to eq expected.member_id
|
||||
expect(actual.first['type']).to eq 'coin'
|
||||
end
|
||||
|
||||
it 'by wallet_type' do
|
||||
wallet_type = Wallet.joins(:currencies)
|
||||
.find_by(currencies: { id: Withdraw.find_by(type: 'Withdraws::Coin').currency_id })
|
||||
.gateway
|
||||
api_get url, token: token, params: { wallet_type: wallet_type }
|
||||
|
||||
actual = JSON.parse(response.body)
|
||||
|
||||
expect(actual.length).to eq Withdraw.where(currency: Currency.joins(:wallets)
|
||||
.where(wallets: { id: Wallet.where(gateway: wallet_type) })).count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET /api/v2/admin/withdraws/:id' do
|
||||
context 'invalid params' do
|
||||
context 'non-integer id' do
|
||||
it do
|
||||
api_get '/api/v2/admin/withdraws/id', token: token
|
||||
expect(response).to include_api_error('admin.withdraw.non_integer_id')
|
||||
end
|
||||
end
|
||||
|
||||
context 'withdraw does not exist' do
|
||||
it do
|
||||
api_get "/api/v2/admin/withdraws/#{Withdraw.last.id + 1}", token: token
|
||||
expect(response).to include_api_error('record.not_found')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with beneficiary' do
|
||||
context 'has beneficiary' do
|
||||
let!(:withdraw) { create(:usd_withdraw, :with_beneficiary, :with_deposit_liability) }
|
||||
it 'includes beneficiary in withdrawal payload' do
|
||||
beneficiary_json = API::V2::Entities::Beneficiary
|
||||
.represent(withdraw.beneficiary)
|
||||
.as_json
|
||||
.deep_stringify_keys
|
||||
|
||||
api_get "/api/v2/admin/withdraws/#{withdraw.id}", token: token
|
||||
expect(response_body['beneficiary']).to_not be_nil
|
||||
expect(response_body['beneficiary']).to eq(beneficiary_json)
|
||||
end
|
||||
end
|
||||
|
||||
context 'does not have beneficiary' do
|
||||
let!(:withdraw) { create(:usd_withdraw, :with_deposit_liability) }
|
||||
|
||||
it 'includes beneficiary in withdrawal payload' do
|
||||
api_get "/api/v2/admin/withdraws/#{withdraw.id}", token: token
|
||||
expect(response_body['beneficiary']).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with error message' do
|
||||
context 'does not have error message' do
|
||||
let!(:withdraw) { create(:usd_withdraw, :with_beneficiary, :with_deposit_liability, aasm_state: :succeed) }
|
||||
|
||||
it 'without error message in withdrawal payload' do
|
||||
api_get "/api/v2/admin/withdraws/#{withdraw.id}", token: token
|
||||
expect(response_body.include?('error')).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context 'includes error message' do
|
||||
let!(:withdraw) { create(:usd_withdraw, :with_beneficiary, :with_deposit_liability, aasm_state: :skipped) }
|
||||
|
||||
it 'includes error message in withdrawal payload' do
|
||||
api_get "/api/v2/admin/withdraws/#{withdraw.id}", token: token
|
||||
expect(response_body.include?('error')).to be_truthy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT /api/v2/admin/withdraws' do
|
||||
let(:url) { '/api/v2/admin/withdraws' }
|
||||
let(:fiat) { Withdraw.where(type: 'Withdraws::Fiat').first }
|
||||
let(:coin) { Withdraw.where(type: 'Withdraws::Coin').first }
|
||||
context 'updates withdraw' do
|
||||
it 'updates empty metadata' do
|
||||
api_put url, token: token, params: { metadata: { info: :some }, id: coin.id }
|
||||
expect(response_body['metadata']).to eq({'info' => 'some'})
|
||||
end
|
||||
|
||||
it 'updates existing metadata' do
|
||||
coin.update!(metadata: { data: :data })
|
||||
api_put url, token: token, params: { metadata: { info: :some }, id: coin.id }
|
||||
expect(response_body['metadata']).to eq({'data' => 'data', 'info' => 'some'})
|
||||
end
|
||||
|
||||
it 'updates existing metadata' do
|
||||
coin.update!(metadata: { info: :some })
|
||||
api_put url, token: token, params: { metadata: { info: :some1 }, id: coin.id }
|
||||
expect(response_body['metadata']).to eq({ 'info' => 'some1' })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /api/v2/admin/withdraws/actions' do
|
||||
let(:url) { '/api/v2/admin/withdraws/actions' }
|
||||
let(:fiat) { Withdraw.where(type: 'Withdraws::Fiat').first }
|
||||
let(:coin) { Withdraw.where(type: 'Withdraws::Coin').first }
|
||||
|
||||
context 'validates params' do
|
||||
it 'does not pass unsupported action' do
|
||||
api_post url, token: token, params: { action: 'illegal', id: fiat.id }
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(response).to include_api_error('admin.withdraw.invalid_action')
|
||||
end
|
||||
|
||||
it 'passes supported action for coin' do
|
||||
api_post url, token: token, params: { action: 'process', id: coin.id }
|
||||
expect(response).not_to include_api_error('admin.withdraw.invalid_action')
|
||||
end
|
||||
|
||||
it 'passes supported action for fiat' do
|
||||
api_post url, token: token, params: { action: 'reject', id: fiat.id }
|
||||
expect(response).not_to include_api_error('admin.withdraw.invalid_action')
|
||||
end
|
||||
|
||||
it 'does not pass coin action for fiat' do
|
||||
api_post url, token: token, params: { action: 'load', id: fiat.id }
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(response).to include_api_error('admin.withdraw.cannot_load')
|
||||
end
|
||||
end
|
||||
|
||||
context 'updates withdraw' do
|
||||
before { [coin, fiat].map(&:accept!) }
|
||||
|
||||
it 'process coin' do
|
||||
api_post url, token: token, params: { action: 'process', id: coin.id }
|
||||
expect(coin.reload.aasm_state).to eq('processing')
|
||||
end
|
||||
|
||||
it 'reject fiat' do
|
||||
api_post url, token: token, params: { action: 'reject', id: fiat.id }
|
||||
expect(fiat.reload.aasm_state).to eq('rejected')
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'fail coin' do
|
||||
coin.accept!
|
||||
coin.process!
|
||||
api_post url, token: token, params: { action: 'fail', id: coin.id }
|
||||
expect(coin.reload.aasm_state).to eq('failed')
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'load coin with txid' do
|
||||
BlockchainService.any_instance.expects(:fetch_transaction).once.returns(Peatio::Transaction.new)
|
||||
coin.accept!
|
||||
api_post url, token: token, params: { action: 'load', id: coin.id, txid: 'new_txid' }
|
||||
expect(coin.reload.txid).to eq('new_txid')
|
||||
expect(coin.aasm_state).to eq('confirming')
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'load fiat with txid' do
|
||||
fiat.accept!
|
||||
expect {
|
||||
api_post url, token: token, params: { action: 'load', id: fiat.id, txid: 'new_txid' }
|
||||
}.not_to change { fiat }
|
||||
expect(response).to include_api_error('admin.withdraw.redundant_txid')
|
||||
end
|
||||
|
||||
it 'load coin without txid with txid as param' do
|
||||
BlockchainService.any_instance.expects(:fetch_transaction).once.returns(Peatio::Transaction.new)
|
||||
coin.update(txid: nil)
|
||||
coin.accept!
|
||||
api_post url, token: token, params: { action: 'load', id: coin.id, txid: 'new_txid' }
|
||||
expect(coin.reload.txid).to eq('new_txid')
|
||||
expect(coin.aasm_state).to eq('confirming')
|
||||
expect(response).to be_successful
|
||||
end
|
||||
|
||||
it 'load coin without txid' do
|
||||
coin.update(txid: nil)
|
||||
coin.accept!
|
||||
expect {
|
||||
api_post url, token: token, params: { action: 'load', id: coin.id }
|
||||
}.not_to change { coin }
|
||||
expect(response).to include_api_error('admin.withdraw.cannot_load')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user