import json import unittest import time from time import mktime from datetime import datetime from dataserv.run import app, db from btctxstore import BtcTxStore from email.utils import formatdate from dataserv.app import secs_to_mins, online_farmers # FIXME generate addresses with btctxstore fixtures = json.load(open("tests/fixtures.json")) addresses = fixtures["addresses"] class TemplateTest(unittest.TestCase): def setUp(self): app.config["SKIP_AUTHENTICATION"] = True # monkey patch app.config["DISABLE_CACHING"] = True self.app = app.test_client() db.create_all() def tearDown(self): db.session.remove() db.drop_all() class RegisterTest(TemplateTest): def test_register(self): rv = self.app.get('/api/register/{0}/{1}'.format(addresses["alpha"], addresses["beta"])) data = json.loads(rv.data.decode("utf-8")) self.assertEqual(addresses["alpha"], data["btc_addr"]) self.assertEqual(addresses["beta"], data["payout_addr"]) self.assertEqual(rv.status_code, 200) def test_register_no_payout(self): rv = self.app.get('/api/register/{0}'.format(addresses["gamma"])) # good registration return_data = json.loads(rv.data.decode("utf-8")) expected_data = { "height": 0, "btc_addr": addresses["gamma"], 'payout_addr': addresses["gamma"], "last_seen": 0 } self.assertEqual(rv.status_code, 200) self.assertEqual(return_data, expected_data) # duplicate registration rv = self.app.get('/api/register/{0}'.format(addresses["gamma"])) self.assertEqual(b"Registration Failed: Address already is registered." , rv.data) self.assertEqual(rv.status_code, 409) def test_register_w_payout(self): rv = self.app.get('/api/register/{0}/{1}'.format(addresses["delta"], addresses["epsilon"])) # good registration return_data = json.loads(rv.data.decode("utf-8")) expected_data = { "height": 0, "btc_addr": addresses["delta"], 'payout_addr': addresses["epsilon"], "last_seen": 0 } self.assertEqual(rv.status_code, 200) self.assertEqual(return_data, expected_data) # duplicate registration rv = self.app.get('/api/register/{0}/{1}'.format(addresses["delta"], addresses["epsilon"])) self.assertEqual(b"Registration Failed: Address already is registered." , rv.data) self.assertEqual(rv.status_code, 409) # duplicate payout address is ok rv = self.app.get('/api/register/{0}/{1}'.format(addresses["zeta"], addresses["epsilon"])) return_data = json.loads(rv.data.decode("utf-8")) expected_data = { "height": 0, "btc_addr": addresses["zeta"], 'payout_addr': addresses["epsilon"], "last_seen": 0 } self.assertEqual(rv.status_code, 200) self.assertEqual(return_data, expected_data) def test_register_invalid_address(self): # bad address only rv = self.app.get('/api/register/{0}'.format(addresses["omega"])) self.assertEqual(b"Registration Failed: Invalid Bitcoin address.", rv.data) self.assertEqual(rv.status_code, 400) # good address, bad address rv = self.app.get('/api/register/{0}/{1}'.format(addresses["eta"], addresses["omega"])) self.assertEqual(b"Registration Failed: Invalid Bitcoin address.", rv.data) self.assertEqual(rv.status_code, 400) # bad address, good address rv = self.app.get('/api/register/{0}/{1}'.format(addresses["omega"], addresses["theta"])) self.assertEqual(b"Registration Failed: Invalid Bitcoin address.", rv.data) self.assertEqual(rv.status_code, 400) class PingTest(TemplateTest): def test_ping_good(self): rv = self.app.get('/api/register/{0}'.format(addresses["alpha"])) self.assertEqual(rv.status_code, 200) # now test ping rv = self.app.get('/api/ping/{0}'.format(addresses["alpha"])) # good ping self.assertEqual(b"Ping accepted.", rv.data) self.assertEqual(rv.status_code, 200) def test_ping_not_found(self): # now test ping with no registration rv = self.app.get('/api/ping/{0}'.format(addresses["beta"])) # bad ping self.assertEqual(b"Ping Failed: Farmer not found.", rv.data) self.assertEqual(rv.status_code, 404) def test_ping_invalid_address(self): # now test ping with no registration and invalid address rv = self.app.get('/api/ping/{0}'.format(addresses["omega"])) # bad ping self.assertEqual(b"Ping Failed: Invalid Bitcoin address.", rv.data) self.assertEqual(rv.status_code, 400) class OnlineTest(TemplateTest): def test_online(self): rv = self.app.get('/api/register/{0}'.format(addresses["alpha"])) self.assertEqual(rv.status_code, 200) # now test ping self.app.get('/api/ping/{0}'.format(addresses["alpha"])) # get online data rv = self.app.get('/api/online') # see if that address is in the online status self.assertTrue(addresses["alpha"] in str(rv.data)) def test_farmer_json(self): # test could be better rv = self.app.get('/api/register/{0}'.format(addresses["beta"])) self.assertEqual(rv.status_code, 200) # get online json data rv = self.app.get('/api/online/json') self.assertTrue(addresses["beta"] in str(rv.data)) def test_farmer_order(self): addr1 = '191GVvAaTRxLmz3rW3nU5jAV1rF186VxQc' addr2 = '18c2qnUAfgF3UnJCjAz2rpWQph5xugEfkr' addr3 = '1NqtfdHe3X6rqHRQjsGq5CT9LYYjTFJ1qD' # register farmers self.app.get('/api/register/{0}'.format(addr1)) self.app.get('/api/register/{0}'.format(addr2)) self.app.get('/api/register/{0}'.format(addr3)) # set height self.app.get('/api/height/{0}/{1}'.format(addr1, 0)) self.app.get('/api/height/{0}/{1}'.format(addr2, 2475)) self.app.get('/api/height/{0}/{1}'.format(addr3, 2525)) # get farmers farmers = online_farmers() self.assertEqual(farmers[0].btc_addr, addr3) self.assertEqual(farmers[1].btc_addr, addr2) self.assertEqual(farmers[2].btc_addr, addr1) # set height self.app.get('/api/height/{0}/{1}'.format(addr1, 5000)) # get farmers farmers = online_farmers() self.assertEqual(farmers[0].btc_addr, addr1) class HeightTest(TemplateTest): def test_farmer_set_height(self): # not found rv = self.app.get('/api/height/{0}/1'.format(addresses["beta"])) self.assertEqual(rv.status_code, 404) # register farmer self.app.get('/api/register/{0}'.format(addresses["beta"])) # correct rv = self.app.get('/api/height/{0}/5'.format(addresses["beta"])) self.assertEqual(rv.status_code, 200) rv = self.app.get('/api/online'.format(addresses["beta"])) self.assertTrue(b"5" in rv.data) # invalid btc address rv = self.app.get('/api/height/{0}/1'.format(addresses["omega"])) self.assertEqual(rv.status_code, 400) def test_height_limit(self): self.app.get('/api/register/{0}'.format(addresses["gamma"])) # set height 50 self.app.get('/api/height/{0}/{1}'.format(addresses["gamma"], 50)) rv = self.app.get('/api/online') self.assertTrue(b"50" in rv.data) # set a crazy height rv = self.app.get('/api/height/{0}/{1}'.format(addresses["gamma"], 250000)) self.assertEqual(rv.status_code, 413) class AppAuthenticationHeadersTest(unittest.TestCase): def setUp(self): app.config["SKIP_AUTHENTICATION"] = False # monkey patch self.app = app.test_client() db.create_all() def tearDown(self): db.session.remove() db.drop_all() def test_success(self): # create header date and authorization signature blockchain = BtcTxStore() wif = blockchain.create_key() address = blockchain.get_address(wif) header_date = formatdate(timeval=mktime(datetime.now().timetuple()), localtime=True, usegmt=True) message = app.config["ADDRESS"] + " " + header_date header_authorization = blockchain.sign_unicode(wif, message) headers = {"Date": header_date, "Authorization": header_authorization} url = '/api/register/{0}'.format(address) rv = self.app.get(url, headers=headers) data = json.loads(rv.data.decode("utf-8")) self.assertEqual(address, data["btc_addr"]) self.assertEqual(rv.status_code, 200) def test_fail(self): # register without auth headres fails rv = self.app.get('/api/register/{0}'.format(addresses["eta"])) self.assertEqual(rv.status_code, 401) # register first because ping is lazy blockchain = BtcTxStore() wif = blockchain.create_key() address = blockchain.get_address(wif) header_date = formatdate(timeval=mktime(datetime.now().timetuple()), localtime=True, usegmt=True) message = app.config["ADDRESS"] + " " + header_date header_authorization = blockchain.sign_unicode(wif, message) headers = {"Date": header_date, "Authorization": header_authorization} url = '/api/register/{0}'.format(address) rv = self.app.get(url, headers=headers) self.assertEqual(rv.status_code, 200) # ping without auth headres fails time.sleep(app.config["MAX_PING"]) rv = self.app.get('/api/ping/{0}'.format(address)) self.assertEqual(rv.status_code, 401) # set height without auth headres fails rv = self.app.get('/api/height/{0}/10'.format(addresses["eta"])) self.assertEqual(rv.status_code, 401) class MiscAppTest(TemplateTest): # making sure that at least the web server works def test_hello_world(self): rv = self.app.get('/') self.assertEqual(b"Hello World.", rv.data) # time helper def test_helper_time(self): time1 = 15 time2 = 75 time3 = 4000 self.assertEqual(secs_to_mins(time1), "15 second(s)") self.assertEqual(secs_to_mins(time2), "1 minute(s)") self.assertEqual(secs_to_mins(time3), "1 hour(s)") # total bytes call def test_farmer_total_bytes(self): addr1 = '191GVvAaTRxLmz3rW3nU5jAV1rF186VxQc' addr2 = '18c2qnUAfgF3UnJCjAz2rpWQph5xugEfkr' addr3 = '1NqtfdHe3X6rqHRQjsGq5CT9LYYjTFJ1qD' addr4 = '1JnaPB29Un3FBSf3e4Jzabwi1ekeKoh1Gr' # register farmers self.app.get('/api/register/{0}'.format(addr1)) self.app.get('/api/register/{0}'.format(addr2)) self.app.get('/api/register/{0}'.format(addr3)) self.app.get('/api/register/{0}'.format(addr4)) # set height self.app.get('/api/height/{0}/{1}'.format(addr1, 0)) self.app.get('/api/height/{0}/{1}'.format(addr2, 2475)) self.app.get('/api/height/{0}/{1}'.format(addr3, 2525)) self.app.get('/api/height/{0}/{1}'.format(addr4, 5000)) # check online rv = self.app.get('/api/online') self.assertTrue(b"0" in rv.data) self.assertTrue(b"2475" in rv.data) self.assertTrue(b"2525" in rv.data) self.assertTrue(b"5000" in rv.data) # check total bytes rv = self.app.get('/api/total') self.assertTrue(b'"total_TB": 1.22' in rv.data) self.assertTrue(b'"total_farmers": 4' in rv.data) def test_get_address(self): rv = self.app.get('/api/address') self.assertEqual(rv.status_code, 200) data = json.loads(rv.data.decode("utf-8")) self.assertEqual(app.config["ADDRESS"], data["address"])