Merge pull request #235 from grant-project/tests-tests-tests
Bolster our backend endpoint tests
This commit is contained in:
commit
489de73d9b
|
@ -10,19 +10,21 @@ from grant.extensions import bcrypt, migrate, db, ma, mail, web3
|
|||
from grant.settings import SENTRY_RELEASE, ENV
|
||||
|
||||
|
||||
def create_app(config_object="grant.settings"):
|
||||
def create_app(config_objects=["grant.settings"]):
|
||||
app = Flask(__name__.split(".")[0])
|
||||
app.config.from_object(config_object)
|
||||
for conf in config_objects:
|
||||
app.config.from_object(conf)
|
||||
app.url_map.strict_slashes = False
|
||||
register_extensions(app)
|
||||
register_blueprints(app)
|
||||
register_shellcontext(app)
|
||||
register_commands(app)
|
||||
sentry_sdk.init(
|
||||
environment=ENV,
|
||||
release=SENTRY_RELEASE,
|
||||
integrations=[FlaskIntegration()]
|
||||
)
|
||||
if not app.config.get("TESTING"):
|
||||
sentry_sdk.init(
|
||||
environment=ENV,
|
||||
release=SENTRY_RELEASE,
|
||||
integrations=[FlaskIntegration()]
|
||||
)
|
||||
return app
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from flask import render_template, Markup
|
||||
from flask import render_template, Markup, current_app
|
||||
|
||||
from grant.extensions import mail
|
||||
|
||||
|
@ -30,6 +30,9 @@ get_info_lookup = {
|
|||
|
||||
|
||||
def send_email(to, type, email_args):
|
||||
if current_app and current_app.config.get("TESTING"):
|
||||
return
|
||||
|
||||
try:
|
||||
info = get_info_lookup[type](email_args)
|
||||
body_text = render_template('emails/%s.txt' % (type), args=email_args)
|
||||
|
|
|
@ -87,7 +87,7 @@ def post_proposal_comments(proposal_id, comment, parent_comment_id, signed_messa
|
|||
# Make sure comment content matches
|
||||
typed_data = ast.literal_eval(raw_typed_data)
|
||||
if comment != typed_data['message']['comment']:
|
||||
return {"message": "Comment doesn’t match signature data"}, 404
|
||||
return {"message": "Comment doesn’t match signature data"}, 400
|
||||
|
||||
# Verify the signature
|
||||
try:
|
||||
|
|
|
@ -92,6 +92,9 @@ def requires_same_user_auth(f):
|
|||
return jsonify(message="Decorator requires_same_user_auth requires path variable <user_identity>"), 500
|
||||
|
||||
user = User.get_by_identifier(account_address=user_identity, email_address=user_identity)
|
||||
if not user:
|
||||
return jsonify(message="Could not find user with identity {}".format(user_identity)), 403
|
||||
|
||||
if user.id != g.current_user.id:
|
||||
return jsonify(message="You are not authorized to modify this user"), 403
|
||||
|
||||
|
@ -110,7 +113,7 @@ def requires_team_member_auth(f):
|
|||
|
||||
proposal = Proposal.query.filter_by(id=proposal_id).first()
|
||||
if not proposal:
|
||||
return jsonify(message="No proposal exists with id: {}".format(proposal_id)), 404
|
||||
return jsonify(message="No proposal exists with id {}".format(proposal_id)), 404
|
||||
|
||||
if not g.current_user in proposal.team:
|
||||
return jsonify(message="You are not authorized to modify this proposal"), 403
|
||||
|
|
|
@ -2,13 +2,14 @@ from flask_testing import TestCase
|
|||
|
||||
from grant.app import create_app
|
||||
from grant.user.models import User, SocialMedia, db, Avatar
|
||||
from .test_data import test_user, message
|
||||
from grant.proposal.models import Proposal
|
||||
from .test_data import test_user, test_other_user, test_proposal, message
|
||||
|
||||
|
||||
class BaseTestConfig(TestCase):
|
||||
|
||||
def create_app(self):
|
||||
app = create_app()
|
||||
app = create_app(['grant.settings', 'tests.settings'])
|
||||
app.config.from_object('tests.settings')
|
||||
return app
|
||||
|
||||
|
@ -27,7 +28,7 @@ class BaseTestConfig(TestCase):
|
|||
"""
|
||||
|
||||
message = message or 'HTTP Status %s expected but got %s. Response json: %s' \
|
||||
% (status_code, response.status_code, response.json)
|
||||
% (status_code, response.status_code, response.json or response.data)
|
||||
self.assertEqual(response.status_code, status_code, message)
|
||||
|
||||
assert_status = assertStatus
|
||||
|
@ -45,14 +46,44 @@ class BaseUserConfig(BaseTestConfig):
|
|||
email_address=test_user["emailAddress"],
|
||||
display_name=test_user["displayName"],
|
||||
title=test_user["title"],
|
||||
_send_email=False
|
||||
)
|
||||
sm = SocialMedia(social_media_link=test_user['socialMedias'][0]['link'], user_id=self.user.id)
|
||||
db.session.add(sm)
|
||||
avatar = Avatar(image_url=test_user["avatar"]["link"], user_id=self.user.id)
|
||||
db.session.add(avatar)
|
||||
|
||||
self.other_user = User.create(
|
||||
account_address=test_other_user["accountAddress"],
|
||||
email_address=test_other_user["emailAddress"],
|
||||
display_name=test_other_user["displayName"],
|
||||
title=test_other_user["title"]
|
||||
)
|
||||
|
||||
db.session.commit()
|
||||
|
||||
def remove_default_user(self):
|
||||
User.query.filter_by(id=self.user.id).delete()
|
||||
db.session.commit()
|
||||
|
||||
class BaseProposalCreatorConfig(BaseUserConfig):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.proposal = Proposal.create(
|
||||
status="DRAFT",
|
||||
title=test_proposal["title"],
|
||||
content=test_proposal["content"],
|
||||
brief=test_proposal["brief"],
|
||||
category=test_proposal["category"],
|
||||
target=test_proposal["target"],
|
||||
payout_address=test_proposal["payoutAddress"],
|
||||
trustees=test_proposal["trustees"][0],
|
||||
deadline_duration=test_proposal["deadlineDuration"],
|
||||
vote_duration=test_proposal["voteDuration"]
|
||||
)
|
||||
self.proposal.team.append(self.user)
|
||||
db.session.add(self.proposal)
|
||||
|
||||
self.other_proposal = Proposal.create(status="DRAFT")
|
||||
self.other_proposal.team.append(self.other_user)
|
||||
db.session.add(self.other_proposal)
|
||||
db.session.commit()
|
||||
|
|
|
@ -2,141 +2,90 @@ import json
|
|||
from mock import patch
|
||||
|
||||
from grant.proposal.models import Proposal
|
||||
from grant.user.models import SocialMedia, Avatar
|
||||
from ..config import BaseUserConfig
|
||||
from ..config import BaseProposalCreatorConfig
|
||||
from ..test_data import test_proposal, test_user
|
||||
|
||||
|
||||
class TestAPI(BaseUserConfig):
|
||||
class TestAPI(BaseProposalCreatorConfig):
|
||||
def test_create_new_draft(self):
|
||||
resp = self.app.post(
|
||||
"/api/v1/proposals/drafts",
|
||||
data=json.dumps({}),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertEqual(resp.status_code, 201)
|
||||
self.assertStatus(resp, 201)
|
||||
|
||||
proposal_db = Proposal.query.filter_by(id=resp.json['proposalId'])
|
||||
self.assertIsNotNone(proposal_db)
|
||||
|
||||
def test_create_new_proposal_comment(self):
|
||||
proposal = Proposal(
|
||||
status="LIVE"
|
||||
def test_no_auth_create_new_draft(self):
|
||||
resp = self.app.post(
|
||||
"/api/v1/proposals/drafts"
|
||||
)
|
||||
self.assert401(resp)
|
||||
|
||||
comment_res = self.app.post(
|
||||
"/api/v1/proposals/{}/comments".format(proposal.id),
|
||||
data=json.dumps({ "content": "What a comment" }),
|
||||
def test_update_proposal_draft(self):
|
||||
new_title = "Updated!"
|
||||
new_proposal = test_proposal.copy()
|
||||
new_proposal["title"] = new_title
|
||||
|
||||
resp = self.app.put(
|
||||
"/api/v1/proposals/{}".format(self.proposal.id),
|
||||
data=json.dumps(new_proposal),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
self.assertTrue(comment_res.json)
|
||||
self.assert200(resp)
|
||||
self.assertEqual(resp.json["title"], new_title)
|
||||
self.assertEqual(self.proposal.title, new_title)
|
||||
|
||||
@patch('grant.web3.proposal.validate_contribution_tx', return_value=True)
|
||||
def test_create_proposal_contribution(self, mock_validate_contribution_tx):
|
||||
proposal_res = self.app.post(
|
||||
"/api/v1/proposals/drafts",
|
||||
data=json.dumps(test_proposal),
|
||||
def test_no_auth_update_proposal_draft(self):
|
||||
new_title = "Updated!"
|
||||
new_proposal = test_proposal.copy()
|
||||
new_proposal["title"] = new_title
|
||||
|
||||
resp = self.app.put(
|
||||
"/api/v1/proposals/{}".format(self.proposal.id),
|
||||
data=json.dumps(new_proposal),
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assert401(resp)
|
||||
|
||||
def test_invalid_proposal_update_proposal_draft(self):
|
||||
new_title = "Updated!"
|
||||
new_proposal = test_proposal.copy()
|
||||
new_proposal["title"] = new_title
|
||||
|
||||
resp = self.app.put(
|
||||
"/api/v1/proposals/12345",
|
||||
data=json.dumps(new_proposal),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
proposal_json = proposal_res.json
|
||||
proposal_id = proposal_json["proposalId"]
|
||||
self.assert404(resp)
|
||||
|
||||
contribution = {
|
||||
"txId": "0x12345",
|
||||
"fromAddress": "0x23456",
|
||||
"amount": "1.2345"
|
||||
}
|
||||
|
||||
contribution_res = self.app.post(
|
||||
"/api/v1/proposals/{}/contributions".format(proposal_id),
|
||||
data=json.dumps(contribution),
|
||||
def test_publish_proposal_draft(self):
|
||||
resp = self.app.put(
|
||||
"/api/v1/proposals/{}/publish".format(self.proposal.id),
|
||||
data=json.dumps({ "contractAddress": "0x0" }),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
res = contribution_res.json
|
||||
exp = contribution
|
||||
self.assert200(resp)
|
||||
|
||||
def eq(k):
|
||||
self.assertEqual(exp[k], res[k])
|
||||
eq("txId")
|
||||
eq("fromAddress")
|
||||
eq("amount")
|
||||
self.assertEqual(proposal_id, res["proposalId"])
|
||||
def test_no_auth_publish_proposal_draft(self):
|
||||
resp = self.app.put(
|
||||
"/api/v1/proposals/{}/publish".format(self.proposal.id),
|
||||
data=json.dumps({ "contractAddress": "0x0" }),
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assert401(resp)
|
||||
|
||||
@patch('grant.web3.proposal.validate_contribution_tx', return_value=True)
|
||||
def test_get_proposal_contribution(self, mock_validate_contribution_tx):
|
||||
proposal_res = self.app.post(
|
||||
"/api/v1/proposals/drafts",
|
||||
data=json.dumps(test_proposal),
|
||||
def test_invalid_proposal_publish_proposal_draft(self):
|
||||
resp = self.app.put(
|
||||
"/api/v1/proposals/12345/publish",
|
||||
data=json.dumps({ "contractAddress": "0x0" }),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
proposal_json = proposal_res.json
|
||||
proposal_id = proposal_json["proposalId"]
|
||||
|
||||
contribution = {
|
||||
"txId": "0x12345",
|
||||
"fromAddress": "0x23456",
|
||||
"amount": "1.2345"
|
||||
}
|
||||
|
||||
self.app.post(
|
||||
"/api/v1/proposals/{}/contributions".format(proposal_id),
|
||||
data=json.dumps(contribution),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
contribution_res = self.app.get(
|
||||
"/api/v1/proposals/{0}/contributions/{1}".format(proposal_id, contribution["txId"])
|
||||
)
|
||||
res = contribution_res.json
|
||||
exp = contribution
|
||||
|
||||
def eq(k):
|
||||
self.assertEqual(exp[k], res[k])
|
||||
eq("txId")
|
||||
eq("fromAddress")
|
||||
eq("amount")
|
||||
self.assertEqual(proposal_id, res["proposalId"])
|
||||
|
||||
@patch('grant.web3.proposal.validate_contribution_tx', return_value=True)
|
||||
def test_get_proposal_contributions(self, mock_validate_contribution_tx):
|
||||
proposal_res = self.app.post(
|
||||
"/api/v1/proposals/drafts",
|
||||
data=json.dumps(test_proposal),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
proposal_json = proposal_res.json
|
||||
proposal_id = proposal_json["proposalId"]
|
||||
|
||||
contribution = {
|
||||
"txId": "0x12345",
|
||||
"fromAddress": "0x23456",
|
||||
"amount": "1.2345"
|
||||
}
|
||||
|
||||
self.app.post(
|
||||
"/api/v1/proposals/{}/contributions".format(proposal_id),
|
||||
data=json.dumps(contribution),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
contributions_res = self.app.get(
|
||||
"/api/v1/proposals/{0}/contributions".format(proposal_id)
|
||||
)
|
||||
res = contributions_res.json[0]
|
||||
exp = contribution
|
||||
|
||||
def eq(k):
|
||||
self.assertEqual(exp[k], res[k])
|
||||
eq("txId")
|
||||
eq("fromAddress")
|
||||
eq("amount")
|
||||
self.assertEqual(proposal_id, res["proposalId"])
|
||||
self.assert404(resp)
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
import json
|
||||
from mock import patch
|
||||
|
||||
from grant.proposal.models import Proposal, db
|
||||
from ..config import BaseUserConfig
|
||||
from ..test_data import test_comment, test_reply
|
||||
|
||||
|
||||
class TestAPI(BaseUserConfig):
|
||||
def test_create_new_proposal_comment(self):
|
||||
proposal = Proposal(
|
||||
status="LIVE"
|
||||
)
|
||||
db.session.add(proposal)
|
||||
db.session.commit()
|
||||
|
||||
comment_res = self.app.post(
|
||||
"/api/v1/proposals/{}/comments".format(proposal.id),
|
||||
data=json.dumps(test_comment),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(comment_res, 201)
|
||||
|
||||
def test_invalid_proposal_id_create_comment(self):
|
||||
comment_res = self.app.post(
|
||||
"/api/v1/proposals/12345/comments",
|
||||
data=json.dumps(test_comment),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(comment_res, 404)
|
||||
|
||||
def test_invalid_signature_create_comment(self):
|
||||
proposal = Proposal(
|
||||
status="LIVE"
|
||||
)
|
||||
db.session.add(proposal)
|
||||
db.session.commit()
|
||||
|
||||
test_comment_copy = test_comment.copy()
|
||||
test_comment_copy["comment"] = "Mismatched comment"
|
||||
comment_res = self.app.post(
|
||||
"/api/v1/proposals/{}/comments".format(proposal.id),
|
||||
data=json.dumps(test_comment_copy),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(comment_res, 400)
|
||||
|
||||
def test_create_new_proposal_comment_reply(self):
|
||||
proposal = Proposal(
|
||||
status="LIVE"
|
||||
)
|
||||
db.session.add(proposal)
|
||||
db.session.commit()
|
||||
proposal_id = proposal.id
|
||||
|
||||
comment_res = self.app.post(
|
||||
"/api/v1/proposals/{}/comments".format(proposal_id),
|
||||
data=json.dumps(test_comment),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(comment_res, 201)
|
||||
|
||||
test_reply_copy = test_reply.copy()
|
||||
test_reply_copy["parentCommentId"] = comment_res.json["id"]
|
||||
reply_res = self.app.post(
|
||||
"/api/v1/proposals/{}/comments".format(proposal_id),
|
||||
data=json.dumps(test_reply_copy),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(reply_res, 201)
|
||||
self.assertEqual(
|
||||
reply_res.json["parentCommentId"],
|
||||
comment_res.json["id"]
|
||||
)
|
||||
|
||||
def test_invalid_parent_comment_id_create_reply(self):
|
||||
proposal = Proposal(
|
||||
status="LIVE"
|
||||
)
|
||||
db.session.add(proposal)
|
||||
db.session.commit()
|
||||
proposal_id = proposal.id
|
||||
|
||||
comment_res = self.app.post(
|
||||
"/api/v1/proposals/{}/comments".format(proposal_id),
|
||||
data=json.dumps(test_comment),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(comment_res, 201)
|
||||
|
||||
test_reply_copy = test_reply.copy()
|
||||
test_reply_copy["parentCommentId"] = comment_res.json["id"] + 1
|
||||
reply_res = self.app.post(
|
||||
"/api/v1/proposals/{}/comments".format(proposal_id),
|
||||
data=json.dumps(test_reply_copy),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(reply_res, 400)
|
|
@ -0,0 +1,116 @@
|
|||
import json
|
||||
from mock import patch
|
||||
|
||||
from grant.proposal.models import Proposal
|
||||
from grant.user.models import SocialMedia, Avatar
|
||||
from ..config import BaseUserConfig
|
||||
from ..test_data import test_proposal, test_user
|
||||
|
||||
|
||||
class TestAPI(BaseUserConfig):
|
||||
@patch('grant.web3.proposal.validate_contribution_tx', return_value=True)
|
||||
def test_create_proposal_contribution(self, mock_validate_contribution_tx):
|
||||
proposal_res = self.app.post(
|
||||
"/api/v1/proposals/drafts",
|
||||
data=json.dumps(test_proposal),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
proposal_json = proposal_res.json
|
||||
proposal_id = proposal_json["proposalId"]
|
||||
|
||||
contribution = {
|
||||
"txId": "0x12345",
|
||||
"fromAddress": "0x23456",
|
||||
"amount": "1.2345"
|
||||
}
|
||||
|
||||
contribution_res = self.app.post(
|
||||
"/api/v1/proposals/{}/contributions".format(proposal_id),
|
||||
data=json.dumps(contribution),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
res = contribution_res.json
|
||||
exp = contribution
|
||||
|
||||
def eq(k):
|
||||
self.assertEqual(exp[k], res[k])
|
||||
eq("txId")
|
||||
eq("fromAddress")
|
||||
eq("amount")
|
||||
self.assertEqual(proposal_id, res["proposalId"])
|
||||
|
||||
@patch('grant.web3.proposal.validate_contribution_tx', return_value=True)
|
||||
def test_get_proposal_contribution(self, mock_validate_contribution_tx):
|
||||
proposal_res = self.app.post(
|
||||
"/api/v1/proposals/drafts",
|
||||
data=json.dumps(test_proposal),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
proposal_json = proposal_res.json
|
||||
proposal_id = proposal_json["proposalId"]
|
||||
|
||||
contribution = {
|
||||
"txId": "0x12345",
|
||||
"fromAddress": "0x23456",
|
||||
"amount": "1.2345"
|
||||
}
|
||||
|
||||
self.app.post(
|
||||
"/api/v1/proposals/{}/contributions".format(proposal_id),
|
||||
data=json.dumps(contribution),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
contribution_res = self.app.get(
|
||||
"/api/v1/proposals/{0}/contributions/{1}".format(proposal_id, contribution["txId"])
|
||||
)
|
||||
res = contribution_res.json
|
||||
exp = contribution
|
||||
|
||||
def eq(k):
|
||||
self.assertEqual(exp[k], res[k])
|
||||
eq("txId")
|
||||
eq("fromAddress")
|
||||
eq("amount")
|
||||
self.assertEqual(proposal_id, res["proposalId"])
|
||||
|
||||
@patch('grant.web3.proposal.validate_contribution_tx', return_value=True)
|
||||
def test_get_proposal_contributions(self, mock_validate_contribution_tx):
|
||||
proposal_res = self.app.post(
|
||||
"/api/v1/proposals/drafts",
|
||||
data=json.dumps(test_proposal),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
proposal_json = proposal_res.json
|
||||
proposal_id = proposal_json["proposalId"]
|
||||
|
||||
contribution = {
|
||||
"txId": "0x12345",
|
||||
"fromAddress": "0x23456",
|
||||
"amount": "1.2345"
|
||||
}
|
||||
|
||||
self.app.post(
|
||||
"/api/v1/proposals/{}/contributions".format(proposal_id),
|
||||
data=json.dumps(contribution),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
|
||||
contributions_res = self.app.get(
|
||||
"/api/v1/proposals/{0}/contributions".format(proposal_id)
|
||||
)
|
||||
res = contributions_res.json[0]
|
||||
exp = contribution
|
||||
|
||||
def eq(k):
|
||||
self.assertEqual(exp[k], res[k])
|
||||
eq("txId")
|
||||
eq("fromAddress")
|
||||
eq("amount")
|
||||
self.assertEqual(proposal_id, res["proposalId"])
|
|
@ -0,0 +1,92 @@
|
|||
import json
|
||||
from mock import patch
|
||||
|
||||
from grant.proposal.models import Proposal, ProposalTeamInvite, db
|
||||
from ..config import BaseProposalCreatorConfig
|
||||
from ..test_data import test_proposal, test_user
|
||||
|
||||
|
||||
class TestAPI(BaseProposalCreatorConfig):
|
||||
def test_create_invite_by_account_address(self):
|
||||
invite_res = self.app.post(
|
||||
"/api/v1/proposals/{}/invite".format(self.proposal.id),
|
||||
data=json.dumps({ "address": "0x8B0B72F8bDE212991135668922fD5acE557DE6aB" }),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(invite_res, 201)
|
||||
|
||||
def test_create_invite_by_email_address(self):
|
||||
invite_res = self.app.post(
|
||||
"/api/v1/proposals/{}/invite".format(self.proposal.id),
|
||||
data=json.dumps({ "address": "test@test.test" }),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(invite_res, 201)
|
||||
|
||||
# Rejects if not authorized
|
||||
def test_no_auth_create_invite_fails(self):
|
||||
invite_res = self.app.post(
|
||||
"/api/v1/proposals/{}/invite".format(self.proposal.id),
|
||||
data=json.dumps({ "address": "0x8B0B72F8bDE212991135668922fD5acE557DE6aB" }),
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(invite_res, 401)
|
||||
|
||||
# Rejects if non-existant proposal id
|
||||
def test_invalid_proposal_create_invite_fails(self):
|
||||
invite_res = self.app.post(
|
||||
"/api/v1/proposals/12345/invite",
|
||||
data=json.dumps({ "address": "0x8B0B72F8bDE212991135668922fD5acE557DE6aB" }),
|
||||
headers=self.headers,
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(invite_res, 404)
|
||||
|
||||
def test_delete_invite(self):
|
||||
address = "0x8B0B72F8bDE212991135668922fD5acE557DE6aB"
|
||||
invite = ProposalTeamInvite(
|
||||
proposal_id=self.proposal.id,
|
||||
address="0x8B0B72F8bDE212991135668922fD5acE557DE6aB"
|
||||
)
|
||||
db.session.add(invite)
|
||||
db.session.commit()
|
||||
|
||||
delete_res = self.app.delete(
|
||||
"/api/v1/proposals/{}/invite/{}".format(self.proposal.id, address),
|
||||
headers=self.headers
|
||||
)
|
||||
self.assertStatus(delete_res, 202)
|
||||
|
||||
# Rejects if unknown proposal
|
||||
def test_invalid_invite_delete_invite(self):
|
||||
delete_res = self.app.delete(
|
||||
"/api/v1/proposals/{}/invite/12345".format(self.proposal),
|
||||
headers=self.headers
|
||||
)
|
||||
self.assertStatus(delete_res, 404)
|
||||
|
||||
# Rejects if not authorized
|
||||
def test_no_auth_delete_invite_fails(self):
|
||||
delete_res = self.app.delete(
|
||||
"/api/v1/proposals/{}/invite/12345".format(self.proposal)
|
||||
)
|
||||
self.assertStatus(delete_res, 401)
|
||||
|
||||
# Rejects if the invite was already accepted
|
||||
def test_accepted_invite_delete_invite(self):
|
||||
address = "0x8B0B72F8bDE212991135668922fD5acE557DE6aB"
|
||||
invite = ProposalTeamInvite(
|
||||
proposal_id=self.proposal.id,
|
||||
address="0x8B0B72F8bDE212991135668922fD5acE557DE6aB",
|
||||
accepted=True
|
||||
)
|
||||
db.session.add(invite)
|
||||
db.session.commit()
|
||||
|
||||
delete_res = self.app.delete(
|
||||
"/api/v1/proposals/{}/invite/{}".format(self.proposal.id, address),
|
||||
headers=self.headers
|
||||
)
|
||||
self.assertStatus(delete_res, 403)
|
|
@ -64,11 +64,19 @@ test_user = {
|
|||
|
||||
test_team = [test_user]
|
||||
|
||||
test_other_user = {
|
||||
"accountAddress": "0xA65AD9c6006fe8948E75EC0861A1BAbaD8168DE0",
|
||||
"displayName": 'Faketoshi',
|
||||
"emailAddress": 'fake@toshi.com',
|
||||
"title": 'The Real Fake Satoshi'
|
||||
# TODO make signed messages for this for more tests
|
||||
}
|
||||
|
||||
milestones = [
|
||||
{
|
||||
"title": "All the money straightaway",
|
||||
"description": "cool stuff with it",
|
||||
"date": "June 2019",
|
||||
"content": "cool stuff with it",
|
||||
"dateEstimated": "Fri, 30 Nov 2018 01:42:23 GMT",
|
||||
"payoutPercent": "100",
|
||||
"immediatePayout": False
|
||||
}
|
||||
|
@ -79,16 +87,99 @@ test_proposal = {
|
|||
"crowdFundContractAddress": "0x20000",
|
||||
"content": "## My Proposal",
|
||||
"title": "Give Me Money",
|
||||
"brief": "$$$",
|
||||
"milestones": milestones,
|
||||
"category": random.choice(CATEGORIES)
|
||||
"category": random.choice(CATEGORIES),
|
||||
"target": "123.456",
|
||||
"payoutAddress": test_team[0]["accountAddress"],
|
||||
"trustees": [test_team[0]["accountAddress"]],
|
||||
"deadlineDuration": 100,
|
||||
"voteDuration": 100
|
||||
}
|
||||
|
||||
milestones = [
|
||||
{
|
||||
"title": "All the money straightaway",
|
||||
"description": "cool stuff with it",
|
||||
"date": "June 2019",
|
||||
"payoutPercent": "100",
|
||||
"immediatePayout": False
|
||||
test_comment_message = {
|
||||
"sig": "0x08d5922e48e44229a764d85000558ac9a603ee2ce6a4439a211de4c64a7c3e782efeea90d63760dafb155af53c1dadcec10dac682e1fff8df1b4f40f9fcf08891b",
|
||||
"data": {
|
||||
"domain": {
|
||||
"name": "Grant.io",
|
||||
"version": 1,
|
||||
"chainId": 1543277948575
|
||||
},
|
||||
"types": {
|
||||
"comment": [
|
||||
{
|
||||
"name": "Comment",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"EIP712Domain": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "chainId",
|
||||
"type": "uint256"
|
||||
}
|
||||
]
|
||||
},
|
||||
"message": {
|
||||
"comment": "Test comment"
|
||||
},
|
||||
"primaryType": "comment"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
test_comment = {
|
||||
"signedMessage": test_comment_message["sig"],
|
||||
"rawTypedData": json.dumps(test_comment_message["data"]),
|
||||
"comment": test_comment_message["data"]["message"]["comment"]
|
||||
}
|
||||
|
||||
test_reply_message = {
|
||||
"sig": "0x08d5922e48e44229a764d85000558ac9a603ee2ce6a4439a211de4c64a7c3e782efeea90d63760dafb155af53c1dadcec10dac682e1fff8df1b4f40f9fcf08891b",
|
||||
"data": {
|
||||
"domain": {
|
||||
"name": "Grant.io",
|
||||
"version": 1,
|
||||
"chainId": 1543277948575
|
||||
},
|
||||
"types": {
|
||||
"comment": [
|
||||
{
|
||||
"name": "Comment",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"EIP712Domain": [
|
||||
{
|
||||
"name": "name",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "chainId",
|
||||
"type": "uint256"
|
||||
}
|
||||
]
|
||||
},
|
||||
"message": {
|
||||
"comment": "Test reply"
|
||||
},
|
||||
"primaryType": "comment"
|
||||
}
|
||||
}
|
||||
|
||||
test_reply = {
|
||||
"signedMessage": test_reply_message["sig"],
|
||||
"rawTypedData": json.dumps(test_reply_message["data"]),
|
||||
"comment": test_reply_message["data"]["message"]["comment"]
|
||||
# Fill in parentCommentId in test
|
||||
}
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
import json
|
||||
from mock import patch
|
||||
|
||||
from grant.proposal.models import Proposal, ProposalTeamInvite, db
|
||||
from grant.user.models import SocialMedia, Avatar
|
||||
from ..config import BaseProposalCreatorConfig
|
||||
from ..test_data import test_proposal, test_user
|
||||
|
||||
|
||||
class TestAPI(BaseProposalCreatorConfig):
|
||||
def test_get_user_invites_by_address(self):
|
||||
invite = ProposalTeamInvite(
|
||||
proposal_id=self.proposal.id,
|
||||
address=self.user.account_address
|
||||
)
|
||||
db.session.add(invite)
|
||||
db.session.commit()
|
||||
|
||||
invites_res = self.app.get(
|
||||
"/api/v1/users/{}/invites".format(self.user.account_address),
|
||||
headers=self.headers
|
||||
)
|
||||
self.assertStatus(invites_res, 200)
|
||||
self.assertEqual(invites_res.json[0]['address'], self.user.account_address)
|
||||
self.assertEqual(invites_res.json[0]['proposal']['proposalId'], self.proposal.id)
|
||||
|
||||
def test_get_user_invites_by_email(self):
|
||||
invite = ProposalTeamInvite(
|
||||
proposal_id=self.proposal.id,
|
||||
address=self.user.email_address
|
||||
)
|
||||
db.session.add(invite)
|
||||
db.session.commit()
|
||||
|
||||
invites_res = self.app.get(
|
||||
"/api/v1/users/{}/invites".format(self.user.email_address),
|
||||
headers=self.headers
|
||||
)
|
||||
self.assertStatus(invites_res, 200)
|
||||
self.assertEqual(invites_res.json[0]['address'], self.user.email_address)
|
||||
self.assertEqual(invites_res.json[0]['proposal']['proposalId'], self.proposal.id)
|
||||
|
||||
# Should fail if not authorized
|
||||
def test_no_auth_get_user_invites(self):
|
||||
invites_res = self.app.get(
|
||||
"/api/v1/users/{}/invites".format(self.user.email_address)
|
||||
)
|
||||
self.assertStatus(invites_res, 401)
|
||||
|
||||
def test_put_user_invite_response_accept(self):
|
||||
proposal_id = self.other_proposal.id
|
||||
invite = ProposalTeamInvite(
|
||||
proposal_id=proposal_id,
|
||||
address=self.user.account_address
|
||||
)
|
||||
db.session.add(invite)
|
||||
db.session.commit()
|
||||
|
||||
invites_res = self.app.put(
|
||||
"/api/v1/users/{}/invites/{}/respond".format(self.user.account_address, invite.id),
|
||||
headers=self.headers,
|
||||
data=json.dumps({ "response": True }),
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(invites_res, 200)
|
||||
|
||||
# Make sure we made the team, coach
|
||||
proposal = Proposal.query.filter_by(id=proposal_id).first()
|
||||
self.assertTrue(len(proposal.team) == 2) #TODO: More thorough check than length
|
||||
|
||||
def test_put_user_invite_response_reject(self):
|
||||
proposal_id = self.other_proposal.id
|
||||
invite = ProposalTeamInvite(
|
||||
proposal_id=proposal_id,
|
||||
address=self.user.account_address
|
||||
)
|
||||
db.session.add(invite)
|
||||
db.session.commit()
|
||||
|
||||
invites_res = self.app.put(
|
||||
"/api/v1/users/{}/invites/{}/respond".format(self.user.account_address, invite.id),
|
||||
headers=self.headers,
|
||||
data=json.dumps({ "response": False }),
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(invites_res, 200)
|
||||
|
||||
# Make sure we made the team, coach
|
||||
proposal = Proposal.query.filter_by(id=proposal_id).first()
|
||||
self.assertTrue(len(proposal.team) == 1) #TODO: More thorough check than length
|
||||
|
||||
def test_no_auth_put_user_invite_response(self):
|
||||
proposal_id = self.other_proposal.id
|
||||
invite = ProposalTeamInvite(
|
||||
proposal_id=proposal_id,
|
||||
address=self.user.account_address
|
||||
)
|
||||
db.session.add(invite)
|
||||
db.session.commit()
|
||||
|
||||
invites_res = self.app.put(
|
||||
"/api/v1/users/{}/invites/{}/respond".format(self.user.account_address, invite.id),
|
||||
data=json.dumps({ "response": True }),
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(invites_res, 401)
|
||||
|
||||
def test_invalid_invite_put_user_invite_response(self):
|
||||
invites_res = self.app.put(
|
||||
"/api/v1/users/{}/invites/1234567890/respond".format(self.user.account_address),
|
||||
headers=self.headers,
|
||||
data=json.dumps({ "response": True }),
|
||||
content_type='application/json'
|
||||
)
|
||||
self.assertStatus(invites_res, 404)
|
Loading…
Reference in New Issue