Initial commit

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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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