Passed
Push — master ( 140199...ad2fe1 )
by Andreas
59s
created

test_btcde_func.TestBtcdeExceptions.tearDown()   A

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
from unittest import TestCase
2
import hashlib
3
import hmac
4
import requests_mock
5
from mock import patch
6
import json
7
import btcde
8
from decimal import Decimal
9
10
from urllib.parse import urlencode
11
12
@patch('btcde.log')
13
@requests_mock.Mocker()
14
class TestBtcdeAPIDocu(TestCase):
15
    '''Tests are as in bitcoin.de API documentation.
16
    https://www.bitcoin.de/de/api/tapi/doc'''
17
18
    def sampleData(self, file):
19
        '''Retrieve sample data from json files.'''
20
        filepath = 'tests/resources/{}.json'.format(file)
21
        data = json.load(open(filepath))
22
        return data
23
24
    def sortParams(self, url, params={}):
25
        '''To sort params for url string.'''
26
        self.encoded_string = ''
27
        if len(params) > 0:
28
            self.encoded_string = urlencode(params)
29
            self.url = url + '?' + self.encoded_string
30
        else:
31
            self.url = url
32
        return self.url, self.encoded_string
33
34
    def verifySignature(self, url, method, nonce, params):
35
        '''To verify API Signature.'''
36
        self.XAPINONCE = nonce
37
        self.url, self.encoded_string = self.sortParams(url, params)
38
        if method == 'POST':
39
            md5_encoded_query_string = hashlib.md5(self.encoded_string.encode()
40
                                                   ).hexdigest()
41
        else:
42
            md5_encoded_query_string = hashlib.md5(b'').hexdigest()
43
        hmac_data = '#'.join([method, self.url, self.XAPIKEY,
44
                             str(self.XAPINONCE), md5_encoded_query_string])
45
        hmac_signed = hmac.new(bytearray(self.XAPISECRET.encode()),
46
                               msg=hmac_data.encode(),
47
                               digestmod=hashlib.sha256).hexdigest()
48
        return hmac_signed
49
50
    def setUp(self):
51
        self.XAPIKEY = 'f00b4r'
52
        self.XAPISECRET = 'b4rf00'
53
        self.conn = btcde.Connection(self.XAPIKEY, self.XAPISECRET)
54
        self.XAPINONCE = self.conn.nonce
55
56
    def tearDown(self):
57
        del self.XAPIKEY
58
        del self.XAPISECRET
59
        del self.conn
60
61
    def test_signature_post(self, mock_logger, m):
62
        '''Test signature on a post request.'''
63
        trading_pair = 'btceur'
64
        params = {'max_amount_currency_to_trade': 10,
65
                  'price': 1337,
66
                  'type': 'buy'}
67
        response = self.sampleData('createOrder')
68
        m.post(requests_mock.ANY, json=response, status_code=201)
69
        self.conn.createOrder(params['type'], trading_pair,
70
                              params['max_amount_currency_to_trade'], params['price'])
71
        history = m.request_history
72
        request_signature = history[0].headers.get('X-API-SIGNATURE')
73
        url = f'https://api.bitcoin.de/v4/{trading_pair}/orders'
74
        verified_signature = self.verifySignature(url, 'POST',
75
                                                  self.conn.nonce, params)
76
        self.assertEqual(request_signature, verified_signature)
77
        self.assertTrue(mock_logger.debug.called)
78
79
    def test_signature_get(self, mock_logger, m):
80
        '''Test signature on a get request.'''
81
        trading_pair = 'btceur'
82
        params = { 'type': 'buy' }
83
        response = self.sampleData('showOrderbook_buy')
84
        m.get(requests_mock.ANY, json=response, status_code=200)
85
        self.conn.showOrderbook(params.get('type'), trading_pair)
86
        history = m.request_history
87
        request_signature = history[0].headers.get('X-API-SIGNATURE')
88
        url = f'https://api.bitcoin.de/v4/{trading_pair}/orderbook'
89
        verified_signature = self.verifySignature(url, 'GET',
90
                                                  self.conn.nonce, params)
91
        self.assertEqual(request_signature, verified_signature)
92
        self.assertTrue(mock_logger.debug.called)
93
94
    def test_signature_delete(self, mock_logger, m):
95
        '''Test signature on a delete request.'''
96
        order_id = 'A1234BC'
97
        trading_pair = 'btceur'
98
        m.delete(requests_mock.ANY, json={}, status_code=200)
99
        self.conn.deleteOrder(order_id, trading_pair)
100
        history = m.request_history
101
        request_signature = history[0].headers.get('X-API-SIGNATURE')
102
        url = f'https://api.bitcoin.de/v4/{trading_pair}/orders/{order_id}'
103
        verified_signature = self.verifySignature(url, 'DELETE', self.conn.nonce, {})
104
        self.assertEqual(request_signature, verified_signature)
105
        self.assertTrue(mock_logger.debug.called)
106
107
    def test_add_to_address_pool(self, mock_logger, m):
108
        '''Test function addToAddressPool.'''
109
        currency = 'dash'
110
        params = { 'address': '1337',
111
                   'amount_usages': 3,
112
                   'comment': 'foobar' }
113
        base_url = f'https://api.bitcoin.de/v4/{currency}/address'
114
        url_args = '?' + urlencode(params)
115
        response = self.sampleData('minimal')
116
        m.post(requests_mock.ANY, json=response, status_code=201)
117
        self.conn.addToAddressPool(currency, params['address'],
118
                                   amount_usages=params['amount_usages'],
119
                                   comment=params['comment'])
120
        history = m.request_history
121
        self.assertEqual(history[0].method, "POST")
122
        self.assertEqual(history[0].url, base_url + url_args)
123
        self.assertTrue(mock_logger.debug.called)
124
125
    def test_list_address_pool(self, mock_logger, m):
126
        '''Test function listAddressPool.'''
127
        currency = 'dash'
128
        params = { "comment": "foobar",
129
                   "page": 3,
130
                   "usable": 1 }
131
        base_url = f'https://api.bitcoin.de/v4/{currency}/address'
132
        url_args = '?' + urlencode(params)
133
        response = self.sampleData('listAddressPool')
134
        m.get(requests_mock.ANY, json=response, status_code=200)
135
        self.conn.listAddressPool(currency, usable=params['usable'],
136
                                  comment=params['comment'], page=params['page'])
137
        history = m.request_history
138
        self.assertEqual(history[0].method, "GET")
139
        self.assertEqual(history[0].url, base_url + url_args)
140
        self.assertTrue(mock_logger.debug.called)
141
142
    def test_remove_from_address_pool(self, mock_logger, m):
143
        '''Test function removeFromAddressPool.'''
144
        currency = 'dash'
145
        address = '1337'
146
        base_url = f'https://api.bitcoin.de/v4/{currency}/address/{address}'
147
        response = self.sampleData('minimal')
148
        m.delete(requests_mock.ANY, json=response, status_code=200)
149
        self.conn.removeFromAddressPool(currency, address)
150
        history = m.request_history
151
        self.assertEqual(history[0].method, "DELETE")
152
        self.assertEqual(history[0].url, base_url)
153
        self.assertTrue(mock_logger.debug.called)
154
155 View Code Duplication
    def test_show_orderbook(self, mock_logger, m):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
156
        '''Test function showOrderbook.'''
157
        trading_pair = 'btceur'
158
        params = {'price': 1337,
159
                  'type': 'buy'}
160
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/orderbook'
161
        url_args = '?' + urlencode(params)
162
        response = self.sampleData('showOrderbook_buy')
163
        m.get(requests_mock.ANY, json=response, status_code=200)
164
        self.conn.showOrderbook(params['type'],
165
                                trading_pair,
166
                                price=params['price'])
167
        history = m.request_history
168
        self.assertEqual(history[0].method, "GET")
169
        self.assertEqual(history[0].url, base_url + url_args)
170
        self.assertTrue(mock_logger.debug.called)
171
172
    def test_showOrderDetails(self, mock_logger, m):
173
        '''Test function showOrderDetails.'''
174
        params = {'trading_pair': 'btceur',
175
                  'order_id': '1337'}
176
        base_url = (f'https://api.bitcoin.de/v4/{params["trading_pair"]}'
177
                   f'/orders/public/details/{params["order_id"]}')
178
        response = self.sampleData('showOrderDetails')
179
        m.get(requests_mock.ANY, json=response, status_code=200)
180
        self.conn.showOrderDetails(params['trading_pair'], params['order_id'])
181
        history = m.request_history
182
        self.assertEqual(history[0].method, "GET")
183
        self.assertEqual(history[0].url, base_url)
184
        self.assertTrue(mock_logger.debug.called)
185
186 View Code Duplication
    def test_createOrder(self, mock_logger, m):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
187
        '''Test function createOrder.'''
188
        trading_pair = 'btceur'
189
        params = {'max_amount_currency_to_trade': '10',
190
                  'price': '10',
191
                  'type': 'buy'
192
                  }
193
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/orders'
194
        url_args = '?' + urlencode(params)
195
        response = self.sampleData('createOrder')
196
        m.post(requests_mock.ANY, json=response, status_code=201)
197
        self.conn.createOrder(params['type'],
198
                              trading_pair,
199
                              params['max_amount_currency_to_trade'],
200
                              params['price'])
201
        history = m.request_history
202
        self.assertEqual(history[0].method, "POST")
203
        self.assertEqual(history[0].url, base_url + url_args)
204
        self.assertTrue(mock_logger.debug.called)
205
206
    def test_deleteOrder(self, mock_logger, m):
207
        '''Test function deleteOrder.'''
208
        trading_pair = 'btceur'
209
        order_id = '1337'
210
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/orders/{order_id}'
211
        response = self.sampleData('minimal')
212
        m.delete(requests_mock.ANY, json=response, status_code=200)
213
        self.conn.deleteOrder(order_id, trading_pair)
214
        history = m.request_history
215
        self.assertEqual(history[0].method, "DELETE")
216
        self.assertEqual(history[0].url, base_url)
217
        self.assertTrue(mock_logger.debug.called)
218
219 View Code Duplication
    def test_showMyOrders(self, mock_logger, m):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
220
        '''Test function showMyOrders.'''
221
        trading_pair = 'btceur'
222
        params = { 'type': 'buy' }
223
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/orders'
224
        url_args = '?' + urlencode(params)
225
        response = self.sampleData('showMyOrders')
226
        m.get(requests_mock.ANY, json=response, status_code=200)
227
        self.conn.showMyOrders(type=params.get('type'),
228
                               trading_pair=trading_pair)
229
        history = m.request_history
230
        self.assertEqual(history[0].method, "GET")
231
        self.assertEqual(history[0].url, base_url + url_args)
232
        self.assertTrue(mock_logger.debug.called)
233
234
    def test_showMyOrderDetails(self, mock_logger, m):
235
        '''Test function showMyOrderDetails.'''
236
        trading_pair = 'btceur'
237
        order_id = '1337'
238
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/orders/{order_id}'
239
        response = self.sampleData('showMyOrderDetails')
240
        m.get(requests_mock.ANY, json=response, status_code=200)
241
        self.conn.showMyOrderDetails(trading_pair, order_id)
242
        history = m.request_history
243
        self.assertEqual(history[0].method, "GET")
244
        self.assertEqual(history[0].url, base_url)
245
        self.assertTrue(mock_logger.debug.called)
246
247 View Code Duplication
    def test_executeTrade(self, mock_logger, m):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
248
        '''Test function executeTrade.'''
249
        trading_pair = 'btceur'
250
        order_id = '1337'
251
        params = {'amount_currency_to_trade': '10',
252
                  'type': 'buy'}
253
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades/{order_id}'
254
        url_args = '?' + urlencode(params)
255
        response = self.sampleData('minimal')
256
        m.post(requests_mock.ANY, json=response, status_code=201)
257
        self.conn.executeTrade(trading_pair,
258
                               order_id,
259
                               params['type'],
260
                               params['amount_currency_to_trade'])
261
        history = m.request_history
262
        self.assertEqual(history[0].method, "POST")
263
        self.assertEqual(history[0].url, base_url + url_args)
264
        self.assertTrue(mock_logger.debug.called)
265
266
    def test_showMyTrades(self, mock_logger, m):
267
        '''Test function showMyTrades.'''
268
        base_url = 'https://api.bitcoin.de/v4/trades'
269
        response = self.sampleData('showMyTrades')
270
        m.get(requests_mock.ANY, json=response, status_code=200)
271
        history = m.request_history
272
        # Test with trading pair
273
        self.conn.showMyTrades()
274
        self.assertEqual(history[0].method, "GET")
275
        self.assertEqual(history[0].url, base_url)
276
        self.assertTrue(mock_logger.debug.called)
277
278 View Code Duplication
    def test_showMyTrades_with_params(self, mock_logger, m):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
279
        '''Test function showMyTrades with parameters.'''
280
        trading_pair = 'btceur'
281
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades'
282
        response = self.sampleData('showMyTrades')
283
        m.get(requests_mock.ANY, json=response, status_code=200)
284
        history = m.request_history
285
        # Test again without trading pair, but parameter
286
        params = {'type': 'buy'}
287
        url_args = '?' + urlencode(params)
288
        self.conn.showMyTrades(type=params['type'], trading_pair=trading_pair)
289
        self.assertEqual(history[0].method, "GET")
290
        self.assertEqual(history[0].url, base_url + url_args)
291
        self.assertTrue(mock_logger.debug.called)
292
293
    def test_showMyTradeDetails(self, mock_logger, m):
294
        '''Test function showMyTradeDetails.'''
295
        trading_pair = 'btceur'
296
        trade_id = '1337'
297
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades/{trade_id}'
298
        response = self.sampleData('showMyTradeDetails')
299
        m.get(requests_mock.ANY, json=response, status_code=200)
300
        self.conn.showMyTradeDetails(trading_pair, trade_id)
301
        history = m.request_history
302
        self.assertEqual(history[0].method, "GET")
303
        self.assertEqual(history[0].url, base_url)
304
        self.assertTrue(mock_logger.debug.called)
305
306
    def test_markCoinsAsTransferred(self, mock_logger, m):
307
        '''Test function markCoinsAsTransferred.'''
308
        trading_pair = 'btceur'
309
        trade_id = '1337'
310
        params = { 'amount_currency_to_trade_after_fee': 0.1337}
311
        url_args = '?' + urlencode(params)
312
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades/{trade_id}/mark_coins_as_transferred'
313
        response = self.sampleData('markCoinsAsTransferred')
314
        m.post(requests_mock.ANY, json=response, status_code=200)
315
        self.conn.markCoinsAsTransferred(trading_pair, trade_id, params['amount_currency_to_trade_after_fee'])
316
        history = m.request_history
317
        self.assertEqual(history[0].method, "POST")
318
        self.assertEqual(history[0].url, base_url + url_args)
319
        self.assertTrue(mock_logger.debug.called)
320
321
    def test_markTradeAsPaid(self, mock_logger, m):
322
        '''Test function markTradeAsPaid.'''
323
        trading_pair = 'btceur'
324
        trade_id = '1337'
325
        params = { 'volume_currency_to_pay_after_fee': 0.1337}
326
        url_args = '?' + urlencode(params)
327
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades/{trade_id}/mark_trade_as_paid'
328
        response = self.sampleData('markCoinsAsTransferred')
329
        m.post(requests_mock.ANY, json=response, status_code=200)
330
        self.conn.markTradeAsPaid(trading_pair, trade_id, params['volume_currency_to_pay_after_fee'])
331
        history = m.request_history
332
        self.assertEqual(history[0].method, "POST")
333
        self.assertEqual(history[0].url, base_url + url_args)
334
        self.assertTrue(mock_logger.debug.called)
335
336 View Code Duplication
    def test_markCoinsAsReceived(self, mock_logger, m):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
337
        '''Test function markCoinsAsReceived.'''
338
        trading_pair = 'btceur'
339
        trade_id = '1337'
340
        params = { 'amount_currency_to_trade_after_fee': 0.1337, 'rating': 'positive'}
341
        url_args = '?' + urlencode(params)
342
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades/{trade_id}/mark_coins_as_received'
343
        response = self.sampleData('markCoinsAsTransferred')
344
        m.post(requests_mock.ANY, json=response, status_code=200)
345
        self.conn.markCoinsAsReceived(trading_pair, trade_id,
346
                                      params['amount_currency_to_trade_after_fee'],
347
                                      params['rating'])
348
        history = m.request_history
349
        self.assertEqual(history[0].method, "POST")
350
        self.assertEqual(history[0].url, base_url + url_args)
351
        self.assertTrue(mock_logger.debug.called)
352
353
    def test_markTradeAsPaymentReceived(self, mock_logger, m):
354
        '''Test function markTradeAsPaymentReceived.'''
355
        trading_pair = 'btceur'
356
        trade_id = '1337'
357
        params = { 'is_paid_from_correct_bank_account': True, 'rating': 'positive',
358
                   'volume_currency_to_pay_after_fee': 0.1337 }
359
        url_args = '?' + urlencode(params)
360
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades/{trade_id}/mark_trade_as_payment_received'
361
        response = self.sampleData('markCoinsAsTransferred')
362
        m.post(requests_mock.ANY, json=response, status_code=200)
363
        self.conn.markTradeAsPaymentReceived(trading_pair, trade_id,
364
                                      params['volume_currency_to_pay_after_fee'],
365
                                      params['rating'],
366
                                      params['is_paid_from_correct_bank_account'])
367
        history = m.request_history
368
        self.assertEqual(history[0].method, "POST")
369
        self.assertEqual(history[0].url, base_url + url_args)
370
        self.assertTrue(mock_logger.debug.called)
371
372
    def test_addTradeRating(self, mock_logger, m):
373
        '''Test function addTradeRating.'''
374
        trading_pair = 'btceur'
375
        trade_id = '1337'
376
        params = { 'rating': 'positive' }
377
        url_args = '?' + urlencode(params)
378
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades/{trade_id}/add_trade_rating'
379
        response = self.sampleData('markCoinsAsTransferred')
380
        m.post(requests_mock.ANY, json=response, status_code=200)
381
        self.conn.addTradeRating(trading_pair, trade_id, params['rating'])
382
        history = m.request_history
383
        self.assertEqual(history[0].method, "POST")
384
        self.assertEqual(history[0].url, base_url + url_args)
385
        self.assertTrue(mock_logger.debug.called)
386
387
    def test_showAccountInfo(self, mock_logger, m):
388
        '''Test function showAccountInfo.'''
389
        base_url = 'https://api.bitcoin.de/v4/account'
390
        url_args = ''
391
        response = self.sampleData('showAccountInfo')
392
        m.get(requests_mock.ANY, json=response, status_code=200)
393
        self.conn.showAccountInfo()
394
        history = m.request_history
395
        self.assertEqual(history[0].method, "GET")
396
        self.assertEqual(history[0].url, base_url + url_args)
397
        self.assertTrue(mock_logger.debug.called)
398
399
    def test_showOrderbookCompact(self, mock_logger, m):
400
        '''Test function showOrderbookCompact.'''
401
        trading_pair = 'btceur'
402
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/orderbook/compact'
403
        response = self.sampleData('showOrderbookCompact')
404
        m.get(requests_mock.ANY, json=response, status_code=200)
405
        self.conn.showOrderbookCompact(trading_pair)
406
        history = m.request_history
407
        self.assertEqual(history[0].method, "GET")
408
        self.assertEqual(history[0].url, base_url)
409
        self.assertTrue(mock_logger.debug.called)
410
411
    def test_showPublicTradeHistory(self, mock_logger, m):
412
        '''Test function showPublicTradeHistory.'''
413
        trading_pair = 'btceur'
414
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades/history'
415
        response = self.sampleData('showPublicTradeHistory')
416
        m.get(requests_mock.ANY, json=response, status_code=200)
417
        self.conn.showPublicTradeHistory(trading_pair)
418
        history = m.request_history
419
        self.assertEqual(history[0].method, "GET")
420
        self.assertEqual(history[0].url, base_url)
421
        self.assertTrue(mock_logger.debug.called)
422
423
    def test_showPublicTradeHistory_since(self, mock_logger, m):
424
        '''Test function showPublicTradeHistory with since_tid.'''
425
        trading_pair = 'btceur'
426
        params = {'since_tid': '123'}
427
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/trades/history'
428
        url_args = '?' + urlencode(params)
429
        response = self.sampleData('showPublicTradeHistory')
430
        m.get(requests_mock.ANY, json=response, status_code=200)
431
        self.conn.showPublicTradeHistory(trading_pair, since_tid=params.get('since_tid'))
432
        history = m.request_history
433
        self.assertEqual(history[0].method, "GET")
434
        self.assertEqual(history[0].url, base_url + url_args)
435
        self.assertTrue(mock_logger.debug.called)
436
437
    def test_showRates(self, mock_logger, m):
438
        '''Test function showRates.'''
439
        trading_pair = 'btceur'
440
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/rates'
441
        response = self.sampleData('showRates')
442
        m.get(requests_mock.ANY, json=response, status_code=200)
443
        self.conn.showRates(trading_pair)
444
        history = m.request_history
445
        self.assertEqual(history[0].method, "GET")
446
        self.assertEqual(history[0].url, base_url)
447
        self.assertTrue(mock_logger.debug.called)
448
449 View Code Duplication
    def test_showAccountLedger(self, mock_logger, m):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
450
        '''Test function showAccountLedger.'''
451
        currency = 'btc'
452
        params = {'type': 'all'}
453
        url_args = '?' + urlencode(params)
454
        base_url = f'https://api.bitcoin.de/v4/{currency}/account/ledger'
455
        response = self.sampleData('showAccountLedger')
456
        m.get(requests_mock.ANY, json=response, status_code=200)
457
        self.conn.showAccountLedger(currency, type=params['type'])
458
        history = m.request_history
459
        self.assertEqual(history[0].method, "GET")
460
        self.assertEqual(history[0].url, base_url + url_args)
461
        self.assertTrue(mock_logger.debug.called)
462
463
    def test_showPermissions(self, mock_logger, m):
464
        '''Test function showPermissions.'''
465
        base_url = f'https://api.bitcoin.de/v4/permissions'
466
        response = self.sampleData('showPermissions')
467
        m.get(requests_mock.ANY, json=response, status_code=200)
468
        self.conn.showPermissions()
469
        history = m.request_history
470
        self.assertEqual(history[0].method, "GET")
471
        self.assertEqual(history[0].url, base_url)
472
        self.assertTrue(mock_logger.debug.called)
473
474 View Code Duplication
    def test_urlEncoding(self, mock_logger, m):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
475
        '''Test URL encoding on parameters.'''
476
        currency = 'btc'
477
        params = {'datetime_start': '2018-01-01T01:00:00+01:00'}
478
        base_url = f'https://api.bitcoin.de/v4/{currency}/account/ledger'
479
        url_args = '?' + urlencode(params)
480
        response = self.sampleData('showAccountLedger')
481
        m.get(requests_mock.ANY, json=response, status_code=200)
482
        r = self.conn.showAccountLedger(currency, datetime_start="2018-01-01T01:00:00+01:00")
483
        history = m.request_history
484
        self.assertEqual(history[0].method, "GET")
485
        self.assertEqual(history[0].url, base_url + url_args)
486
        self.assertTrue(mock_logger.debug.called)
487
488
    def test_allowed_pairs(self, mock_logger, m):
489
        '''Test the allowed trading pairs.'''
490
        i = 0
491
        for pair in ['btceur', 'bcheur', 'etheur', 'btgeur', 'bsveur', 'ltceur',
492
                     'iotabtc', 'dashbtc', 'gntbtc', 'ltcbtc']:
493
            params = {'trading_pair': pair}
494
            base_url = f'https://api.bitcoin.de/v4/{pair}/rates'
495
            response = self.sampleData('showRates')
496
            m.get(requests_mock.ANY, json=response, status_code=200)
497
            self.conn.showRates(params.get('trading_pair'))
498
            history = m.request_history
499
            self.assertEqual(history[i].method, "GET")
500
            self.assertEqual(history[i].url, base_url)
501
            self.assertTrue(mock_logger.debug.called)
502
            i += 1
503
504
    def test_allowed_currency(self, mock_logger, m):
505
        '''Test the allowed currencies.'''
506
        i = 0
507
        for curr in ['btc', 'bch', 'eth', 'btg', 'bsv', 'ltc',
508
                     'iota', 'dash', 'gnt']:
509
            base_url = f'https://api.bitcoin.de/v4/{curr}/account/ledger'
510
            url_args = '?currency={}'.format(curr)
511
            response = self.sampleData('showAccountLedger')
512
            m.get(requests_mock.ANY, json=response, status_code=200)
513
            self.conn.showAccountLedger(curr)
514
            history = m.request_history
515
            self.assertEqual(history[i].method, "GET")
516
            self.assertEqual(history[i].url, base_url)
517
            self.assertTrue(mock_logger.debug.called)
518
            i += 1
519
520
    def test_decimal_parsing(self, mock_logger, m):
521
        '''Test if the decimal parsing calculates correctly.'''
522
        params = {'type': 'buy',
523
                  'trading_pair': 'btceur',
524
                  'max_amount': 10,
525
                  'price': 1337}
526
        response = self.sampleData('showOrderbook_buy')
527
        m.get(requests_mock.ANY, json=response, status_code=200)
528
        data = self.conn.showOrderbook(params.get('type'),
529
                                       params.get('trading_pair'),
530
                                       price=params.get('price'))
531
        price = data.get('orders')[0].get('price')
532
        self.assertIsInstance(price, Decimal)
533
        self.assertEqual(price + Decimal('22.3'), Decimal('252.85'))
534
        self.assertNotEqual(float(price) + float('22.3'), float('252.85'))
535
536
537
class TestBtcdeExceptions(TestCase):
538
    '''Test for Exception Handling.'''
539
540
    def sampleData(self, file):
541
        '''Retrieve sample data from json files.'''
542
        filepath = 'tests/resources/{}.json'.format(file)
543
        data = json.load(open(filepath))
544
        return data
545
546
    def setUp(self):
547
        self.XAPIKEY = 'f00b4r'
548
        self.XAPISECRET = 'b4rf00'
549
        self.conn = btcde.Connection(self.XAPIKEY, self.XAPISECRET)
550
        self.XAPINONCE = self.conn.nonce
551
552
    def tearDown(self):
553
        del self.XAPIKEY
554
        del self.XAPISECRET
555
        del self.conn
556
557
    @requests_mock.Mocker()
558
    def test_dont_fail_on_non_utf8(self, m):
559
        '''Test if no exception raises with a non-utf8 response.
560
        https://github.com/peshay/btcde/issues/12'''
561
        filepath = 'tests/resources/NonUTF8'
562
        with open(filepath, 'r') as f:
563
            m.post(requests_mock.ANY, content=f.read().encode('utf-16', 'replace'), status_code=403)
564
        try:
565
            self.conn.executeTrade('btceur', 'foobar', 'buy', 42)
566
            self.assertTrue(True)
567
        except UnicodeDecodeError:
568
            self.assertTrue(False)
569
570
    @requests_mock.Mocker()
571
    def test_APIException(self, m):
572
        '''Test API Exception.'''
573
        trading_pair = 'btceur'
574
        params = {'max_amount_currency_to_trade': 10,
575
                  'price': 13,
576
                  'type': 'buy' }
577
        base_url = f'https://api.bitcoin.de/v4/{trading_pair}/orders'
578
        url_args = '?' + urlencode(params)
579
        response = self.sampleData('error')
580
        m.post(requests_mock.ANY, json=response, status_code=400)
581
        self.conn.createOrder(params['type'], trading_pair,
582
                              params['max_amount_currency_to_trade'],
583
                              price=params['price'])
584
        history = m.request_history
585
        self.assertEqual(history[0].method, "POST")
586
        self.assertEqual(history[0].url, base_url + url_args)
587
588
    @patch('btcde.log')
589
    def test_RequestException(self, mock_logger):
590
        '''Test Requests Exception.'''
591
        params = {'type': 'buy',
592
                  'trading_pair': 'btceur',
593
                  'max_amount': 10,
594
                  'price': 13}
595
        self.conn.orderuri = 'https://foo.bar'
596
        self.conn.createOrder(params.get('type'),
597
                              params.get('trading_pair'), params.get('max_amount'),
598
                              price=params.get('price'))
599
        self.assertTrue(mock_logger.warning.called)
600
601
    def test_TradingPairValueException(self):
602
        '''Test wrong traiding_pair Value Exception.'''
603
        with self.assertRaises(ValueError) as context:
604
            self.conn.deleteOrder('123', 'usdeur')
605
        self.assertTrue('usdeur is not any of' in str(context.exception))
606
607
    def test_OrderTypeValueException(self):
608
        '''Test wrong type Value Exception.'''
609
        with self.assertRaises(ValueError) as context:
610
            self.conn.createOrder('fail', 'btceur', '100', '100')
611
        self.assertTrue('fail is not any of' in str(context.exception))
612
613
    def test_CurrencyValueException(self):
614
        '''Test wrong currency Value Exception.'''
615
        with self.assertRaises(ValueError) as context:
616
            self.conn.showAccountLedger('usd')
617
        self.assertTrue('usd is not any of' in str(context.exception))
618
619
    def test_BankSeatValueException(self):
620
        '''Test wrong seat_of_bank Value Exception.'''
621
        with self.assertRaises(ValueError) as context:
622
            self.conn.showOrderbook('buy', 'btceur', seat_of_bank='SZ')
623
        self.assertTrue('SZ is not any of' in str(context.exception))
624
625
    def test_TrustLevelValueException(self):
626
        '''Test wrong trust_level Value Exception.'''
627
        with self.assertRaises(ValueError) as context:
628
            self.conn.createOrder('buy', 'btceur', '100', '100',
629
                                   min_trust_level='foo')
630
        self.assertTrue('foo is not any of' in str(context.exception))
631
632
    def test_PaymentOptionValueException(self):
633
        '''Test wrong payment_option Value Exception.'''
634
        with self.assertRaises(ValueError) as context:
635
            self.conn.createOrder('buy', 'btceur', '100', '100',
636
                                   payment_option=4)
637
        self.assertTrue('4 is not any of' in str(context.exception))
638
639
    def test_OrderStateValueException(self):
640
        '''Test wrong state Value Exception.'''
641
        with self.assertRaises(ValueError) as context:
642
            self.conn.showMyOrders(state=1)
643
        self.assertTrue('1 is not any of' in str(context.exception))
644
645
    def test_TradeStateValueException(self):
646
        '''Test wrong state Value Exception.'''
647
        with self.assertRaises(ValueError) as context:
648
            self.conn.showMyTrades(state=-2)
649
        self.assertTrue('-2 is not any of' in str(context.exception))
650
651
    def test_UnknownKeyException(self):
652
        '''Test wrong Key Exception.'''
653
        with self.assertRaises(KeyError) as context:
654
            self.conn.showMyOrders(foo=4)
655
        self.assertTrue('foo is not any of' in str(context.exception))
656