From 5608a366160d402448cfc869e554334055b0262f Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 10 Jan 2017 11:34:10 +0100 Subject: [PATCH 1/7] implement /votes endpoint --- bigchaindb/web/routes.py | 2 ++ bigchaindb/web/views/votes.py | 37 ++++++++++++++++++++ tests/web/test_votes.py | 65 +++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 bigchaindb/web/views/votes.py create mode 100644 tests/web/test_votes.py diff --git a/bigchaindb/web/routes.py b/bigchaindb/web/routes.py index dca7a518..cd947608 100644 --- a/bigchaindb/web/routes.py +++ b/bigchaindb/web/routes.py @@ -4,6 +4,7 @@ from bigchaindb.web.views import ( info, statuses, transactions as tx, unspents, + votes, ) @@ -25,6 +26,7 @@ ROUTES_API_V1 = [ r('transactions/', tx.TransactionApi), r('transactions', tx.TransactionListApi), r('unspents/', unspents.UnspentListApi), + r('votes/', votes.VotesApi), ] diff --git a/bigchaindb/web/views/votes.py b/bigchaindb/web/views/votes.py new file mode 100644 index 00000000..0e5df94f --- /dev/null +++ b/bigchaindb/web/views/votes.py @@ -0,0 +1,37 @@ +"""This module provides the blueprint for the statuses API endpoints. + +For more information please refer to the documentation on ReadTheDocs: + - https://docs.bigchaindb.com/projects/server/en/latest/drivers-clients/ + http-client-server-api.html +""" +from flask import current_app +from flask_restful import Resource, reqparse + +from bigchaindb import backend +from bigchaindb.web.views.base import make_error + + +class VotesApi(Resource): + def get(self): + """API endpoint to get details about the status of a transaction or a block. + + Return: + A ``dict`` in the format ``{'status': }``, where + ```` is one of "valid", "invalid", "undecided", "backlog". + """ + parser = reqparse.RequestParser() + parser.add_argument('block_id', type=str) + + args = parser.parse_args(strict=True) + + if sum(arg is not None for arg in args.values()) != 1: + return make_error(400, "Provide the block_id query parameter.") + + pool = current_app.config['bigchain_pool'] + votes = [] + + with pool() as bigchain: + if args['block_id']: + votes = list(backend.query.get_votes_by_block_id(bigchain.connection, args['block_id'])) + + return votes diff --git a/tests/web/test_votes.py b/tests/web/test_votes.py new file mode 100644 index 00000000..d168b109 --- /dev/null +++ b/tests/web/test_votes.py @@ -0,0 +1,65 @@ +import pytest + +from bigchaindb.models import Transaction + +VOTES_ENDPOINT = '/api/v1/votes' + + +@pytest.mark.bdb +@pytest.mark.usefixtures('inputs') +def test_get_votes_endpoint(b, client): + tx = Transaction.create([b.me], [([b.me], 1)]) + tx = tx.sign([b.me_private]) + + block = b.create_block([tx]) + b.write_block(block) + + # vote the block valid + vote = b.vote(block.id, b.get_last_voted_block().id, True) + b.write_vote(vote) + + res = client.get(VOTES_ENDPOINT + "?block_id=" + block.id) + assert vote == res.json[0] + assert len(res.json) == 1 + assert res.status_code == 200 + + +@pytest.mark.bdb +@pytest.mark.usefixtures('inputs') +def test_get_votes_multiple(b, client): + tx = Transaction.create([b.me], [([b.me], 1)]) + tx = tx.sign([b.me_private]) + + block = b.create_block([tx]) + b.write_block(block) + last_block = b.get_last_voted_block().id + # vote the block valid + vote_valid = b.vote(block.id, last_block, True) + b.write_vote(vote_valid) + + # vote the block valid + vote_invalid = b.vote(block.id, last_block, False) + b.write_vote(vote_invalid) + + res = client.get(VOTES_ENDPOINT + "?block_id=" + block.id) + assert len(res.json) == 2 + assert res.status_code == 200 + + +@pytest.mark.bdb +def test_get_votes_endpoint_returns_empty_list_not_found(client): + res = client.get(VOTES_ENDPOINT + "?block_id=123") + assert [] == res.json + assert res.status_code == 200 + + +@pytest.mark.bdb +def test_get_status_endpoint_returns_400_bad_query_params(client): + res = client.get(VOTES_ENDPOINT) + assert res.status_code == 400 + + res = client.get(VOTES_ENDPOINT + "?ts_id=123") + assert res.status_code == 400 + + res = client.get(VOTES_ENDPOINT + "?tx_id=123&block_id=123") + assert res.status_code == 400 From 3d643787d294fa92699691226c5c2700b94b02a1 Mon Sep 17 00:00:00 2001 From: diminator Date: Tue, 10 Jan 2017 11:41:04 +0100 Subject: [PATCH 2/7] update docstring --- bigchaindb/web/views/votes.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/bigchaindb/web/views/votes.py b/bigchaindb/web/views/votes.py index 0e5df94f..9fb306a1 100644 --- a/bigchaindb/web/views/votes.py +++ b/bigchaindb/web/views/votes.py @@ -1,4 +1,4 @@ -"""This module provides the blueprint for the statuses API endpoints. +"""This module provides the blueprint for the votes API endpoints. For more information please refer to the documentation on ReadTheDocs: - https://docs.bigchaindb.com/projects/server/en/latest/drivers-clients/ @@ -13,11 +13,10 @@ from bigchaindb.web.views.base import make_error class VotesApi(Resource): def get(self): - """API endpoint to get details about the status of a transaction or a block. + """API endpoint to get details about votes on a block. Return: - A ``dict`` in the format ``{'status': }``, where - ```` is one of "valid", "invalid", "undecided", "backlog". + A list of votes voting for a block with ID ``block_id``. """ parser = reqparse.RequestParser() parser.add_argument('block_id', type=str) From fa8608b2423e396a5873d97134c58f406c62343e Mon Sep 17 00:00:00 2001 From: Rodolphe Marques Date: Thu, 12 Jan 2017 10:41:55 +0100 Subject: [PATCH 3/7] small fix write_vote --- bigchaindb/backend/mongodb/query.py | 4 +++- tests/backend/mongodb/test_queries.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/bigchaindb/backend/mongodb/query.py b/bigchaindb/backend/mongodb/query.py index 745ae731..4b3ab742 100644 --- a/bigchaindb/backend/mongodb/query.py +++ b/bigchaindb/backend/mongodb/query.py @@ -208,7 +208,9 @@ def count_backlog(conn): @register_query(MongoDBConnection) def write_vote(conn, vote): - return conn.db['votes'].insert_one(vote) + conn.db['votes'].insert_one(vote) + vote.pop('_id') + return vote @register_query(MongoDBConnection) diff --git a/tests/backend/mongodb/test_queries.py b/tests/backend/mongodb/test_queries.py index 5b38e473..9f20cc9f 100644 --- a/tests/backend/mongodb/test_queries.py +++ b/tests/backend/mongodb/test_queries.py @@ -312,7 +312,8 @@ def test_write_vote(structurally_valid_vote): query.write_vote(conn, structurally_valid_vote) # retrieve the vote vote_db = conn.db.votes.find_one( - {'node_pubkey': structurally_valid_vote['node_pubkey']} + {'node_pubkey': structurally_valid_vote['node_pubkey']}, + {'_id': False} ) assert vote_db == structurally_valid_vote From 5e3bd1d54c50229bba87c305cf2826ee97fecf39 Mon Sep 17 00:00:00 2001 From: diminator Date: Thu, 12 Jan 2017 10:43:11 +0100 Subject: [PATCH 4/7] rename test functions --- tests/web/test_votes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/web/test_votes.py b/tests/web/test_votes.py index d168b109..4de50502 100644 --- a/tests/web/test_votes.py +++ b/tests/web/test_votes.py @@ -26,7 +26,7 @@ def test_get_votes_endpoint(b, client): @pytest.mark.bdb @pytest.mark.usefixtures('inputs') -def test_get_votes_multiple(b, client): +def test_get_votes_endpoint_multiple_votes(b, client): tx = Transaction.create([b.me], [([b.me], 1)]) tx = tx.sign([b.me_private]) @@ -54,7 +54,7 @@ def test_get_votes_endpoint_returns_empty_list_not_found(client): @pytest.mark.bdb -def test_get_status_endpoint_returns_400_bad_query_params(client): +def test_get_votes_endpoint_returns_400_bad_query_params(client): res = client.get(VOTES_ENDPOINT) assert res.status_code == 400 From b1d6d356cb515e5b342227dbb998c4aaa745e364 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Fri, 13 Jan 2017 18:07:00 +0100 Subject: [PATCH 5/7] Refactor votes API view to use required parser argument rather than custom logic --- bigchaindb/web/views/votes.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/bigchaindb/web/views/votes.py b/bigchaindb/web/views/votes.py index 9fb306a1..3f6000f6 100644 --- a/bigchaindb/web/views/votes.py +++ b/bigchaindb/web/views/votes.py @@ -19,18 +19,12 @@ class VotesApi(Resource): A list of votes voting for a block with ID ``block_id``. """ parser = reqparse.RequestParser() - parser.add_argument('block_id', type=str) + parser.add_argument('block_id', type=str, required=True) args = parser.parse_args(strict=True) - if sum(arg is not None for arg in args.values()) != 1: - return make_error(400, "Provide the block_id query parameter.") - pool = current_app.config['bigchain_pool'] - votes = [] - with pool() as bigchain: - if args['block_id']: - votes = list(backend.query.get_votes_by_block_id(bigchain.connection, args['block_id'])) + votes = list(backend.query.get_votes_by_block_id(bigchain.connection, args['block_id'])) return votes From 7071d471a5238bfaa9d16dc4bce07447d435af65 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Fri, 13 Jan 2017 18:07:12 +0100 Subject: [PATCH 6/7] Add test for empty block_id parameter for votes API --- tests/web/test_votes.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/web/test_votes.py b/tests/web/test_votes.py index 4de50502..0f788fc4 100644 --- a/tests/web/test_votes.py +++ b/tests/web/test_votes.py @@ -48,6 +48,10 @@ def test_get_votes_endpoint_multiple_votes(b, client): @pytest.mark.bdb def test_get_votes_endpoint_returns_empty_list_not_found(client): + res = client.get(VOTES_ENDPOINT + "?block_id=") + assert [] == res.json + assert res.status_code == 200 + res = client.get(VOTES_ENDPOINT + "?block_id=123") assert [] == res.json assert res.status_code == 200 From 9094ddac20504c8d6f8ce1661580a69b74608cd3 Mon Sep 17 00:00:00 2001 From: Brett Sun Date: Fri, 13 Jan 2017 18:27:54 +0100 Subject: [PATCH 7/7] Fix flake8 error with votes API --- bigchaindb/web/views/votes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bigchaindb/web/views/votes.py b/bigchaindb/web/views/votes.py index 3f6000f6..68265b40 100644 --- a/bigchaindb/web/views/votes.py +++ b/bigchaindb/web/views/votes.py @@ -8,7 +8,6 @@ from flask import current_app from flask_restful import Resource, reqparse from bigchaindb import backend -from bigchaindb.web.views.base import make_error class VotesApi(Resource):