From f51dc8f07cb17658c754730a3464dcf3138b5395 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Wed, 11 Jul 2018 13:35:29 -0400 Subject: [PATCH 01/11] Refactor forms so we can pass requests_client to validate --- atst/forms/financial.py | 5 +++-- atst/forms/forms.py | 7 +++++++ atst/forms/org.py | 4 ++-- atst/forms/poc.py | 4 ++-- atst/forms/request.py | 4 ++-- atst/forms/review.py | 5 +++-- atst/handlers/request_new.py | 2 +- tests/handlers/test_request_new.py | 2 +- 8 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 atst/forms/forms.py diff --git a/atst/forms/financial.py b/atst/forms/financial.py index da4915f3..9d1bf6c7 100644 --- a/atst/forms/financial.py +++ b/atst/forms/financial.py @@ -1,12 +1,13 @@ from wtforms.fields.html5 import EmailField from wtforms.fields import StringField, SelectField from wtforms.validators import Required, Email -from wtforms_tornado import Form from .fields import NewlineListField +from .forms import ValidatedForm -class FinancialForm(Form): +class FinancialForm(ValidatedForm): + task_order_id = StringField( "Task Order Number associated with this request.", validators=[Required()] ) diff --git a/atst/forms/forms.py b/atst/forms/forms.py new file mode 100644 index 00000000..064eed58 --- /dev/null +++ b/atst/forms/forms.py @@ -0,0 +1,7 @@ +from wtforms_tornado import Form + + +class ValidatedForm(Form): + + def validate(self, requests_client=None): + return super(ValidatedForm, self).validate() diff --git a/atst/forms/org.py b/atst/forms/org.py index 50d80123..80bb5722 100644 --- a/atst/forms/org.py +++ b/atst/forms/org.py @@ -1,13 +1,13 @@ from wtforms.fields.html5 import EmailField, TelField from wtforms.fields import RadioField, StringField from wtforms.validators import Required, Email -from wtforms_tornado import Form import pendulum from .fields import DateField +from .forms import ValidatedForm from .validators import DateRange, PhoneNumber, Alphabet -class OrgForm(Form): +class OrgForm(ValidatedForm): fname_request = StringField("First Name", validators=[Required(), Alphabet()]) lname_request = StringField("Last Name", validators=[Required(), Alphabet()]) diff --git a/atst/forms/poc.py b/atst/forms/poc.py index 5d64182d..cd57add1 100644 --- a/atst/forms/poc.py +++ b/atst/forms/poc.py @@ -1,10 +1,10 @@ from wtforms.fields import StringField from wtforms.validators import Required, Email, Length -from wtforms_tornado import Form +from .forms import ValidatedForm from .validators import IsNumber, Alphabet -class POCForm(Form): +class POCForm(ValidatedForm): fname_poc = StringField("POC First Name", validators=[Required(), Alphabet()]) lname_poc = StringField("POC Last Name", validators=[Required(), Alphabet()]) diff --git a/atst/forms/request.py b/atst/forms/request.py index e6af039e..6c89aeb2 100644 --- a/atst/forms/request.py +++ b/atst/forms/request.py @@ -1,13 +1,13 @@ from wtforms.fields.html5 import IntegerField from wtforms.fields import RadioField, StringField, TextAreaField from wtforms.validators import NumberRange, InputRequired -from wtforms_tornado import Form from .fields import DateField +from .forms import ValidatedForm from .validators import DateRange import pendulum -class RequestForm(Form): +class RequestForm(ValidatedForm): # Details of Use: Overall Request Details dollar_value = IntegerField( diff --git a/atst/forms/review.py b/atst/forms/review.py index b3cd2a21..68b6f198 100644 --- a/atst/forms/review.py +++ b/atst/forms/review.py @@ -1,6 +1,7 @@ from wtforms.fields import BooleanField -from wtforms_tornado import Form + +from .forms import ValidatedForm -class ReviewForm(Form): +class ReviewForm(ValidatedForm): reviewed = BooleanField("I have reviewed this data and it is correct.") diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 59092ddf..055c2729 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -105,7 +105,7 @@ class JEDIRequestFlow(object): return self.form_class()() def validate(self): - return self.form.validate() + return self.form.validate(self.requests_client) @property def current_screen(self): diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index 7cd99495..d0bd0a23 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -37,7 +37,7 @@ def test_submit_valid_request_form(monkeypatch, http_client, base_url): monkeypatch.setattr( "atst.handlers.request_new.RequestNew.check_xsrf_cookie", lambda s: True ) - monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) + monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s, c: True) # this just needs to send a known invalid form value response = yield http_client.fetch( From c86e703618232e67f0426c49275e84573eff2c38 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Wed, 11 Jul 2018 15:37:34 -0400 Subject: [PATCH 02/11] Redirect to /requests after completing final step --- atst/handlers/request_new.py | 9 ++++++--- tests/mocks.py | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 055c2729..49641fc9 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -27,9 +27,12 @@ class RequestNew(BaseHandler): if jedi_flow.validate(): response = yield jedi_flow.create_or_update_request(self.get_current_user()) if response.ok: - where = self.application.default_router.reverse_url( - "request_form_update", str(screen + 1), jedi_flow.request_id - ) + if jedi_flow.next_screen >= len(jedi_flow.screens): + where = "/requests" + else: + where = self.application.default_router.reverse_url( + "request_form_update", jedi_flow.next_screen, jedi_flow.request_id + ) self.redirect(where) else: self.set_status(response.code) diff --git a/tests/mocks.py b/tests/mocks.py index 2b91e25f..a04e40bf 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -61,6 +61,7 @@ class MockRequestsClient(MockApiClient): "id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b", "creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238", "body": {}, + "status": "incomplete", } return self._get_response("POST", path, 202, json=json) From 10d4c2b90bfa5549327771da88bff8ea454a6db2 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Mon, 16 Jul 2018 15:49:27 -0400 Subject: [PATCH 03/11] Refactor to allow validating warnings on a form --- atst/forms/forms.py | 4 +-- atst/handlers/request_new.py | 39 ++++++++++++++++++++---------- tests/handlers/test_request_new.py | 2 +- 3 files changed, 29 insertions(+), 16 deletions(-) diff --git a/atst/forms/forms.py b/atst/forms/forms.py index 064eed58..732bcc52 100644 --- a/atst/forms/forms.py +++ b/atst/forms/forms.py @@ -3,5 +3,5 @@ from wtforms_tornado import Form class ValidatedForm(Form): - def validate(self, requests_client=None): - return super(ValidatedForm, self).validate() + def validate_warnings(self, requests_client=None): + return True diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 49641fc9..29b99a75 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -24,28 +24,38 @@ class RequestNew(BaseHandler): self.requests_client, screen, post_data=post_data, request_id=request_id ) + rerender_args = dict( + f=jedi_flow.form, + data=post_data, + page=self.page, + screens=jedi_flow.screens, + current=screen, + next_screen=jedi_flow.next_screen, + request_id=jedi_flow.request_id, + ) + if jedi_flow.validate(): response = yield jedi_flow.create_or_update_request(self.get_current_user()) if response.ok: - if jedi_flow.next_screen >= len(jedi_flow.screens): - where = "/requests" + if jedi_flow.validate_warnings(): + if jedi_flow.next_screen >= len(jedi_flow.screens): + where = "/requests" + else: + where = self.application.default_router.reverse_url( + "request_form_update", jedi_flow.next_screen, jedi_flow.request_id + ) + self.redirect(where) else: - where = self.application.default_router.reverse_url( - "request_form_update", jedi_flow.next_screen, jedi_flow.request_id + self.render( + "requests/screen-%d.html.to" % int(screen), + **rerender_args ) - self.redirect(where) else: self.set_status(response.code) else: self.render( "requests/screen-%d.html.to" % int(screen), - f=jedi_flow.form, - data=post_data, - page=self.page, - screens=jedi_flow.screens, - current=screen, - next_screen=jedi_flow.next_screen, - request_id=jedi_flow.request_id, + **rerender_args ) @tornado.web.authenticated @@ -108,7 +118,10 @@ class JEDIRequestFlow(object): return self.form_class()() def validate(self): - return self.form.validate(self.requests_client) + return self.form.validate() + + def validate_warnings(self): + return self.form.validate_warnings(self.requests_client) @property def current_screen(self): diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index d0bd0a23..7cd99495 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -37,7 +37,7 @@ def test_submit_valid_request_form(monkeypatch, http_client, base_url): monkeypatch.setattr( "atst.handlers.request_new.RequestNew.check_xsrf_cookie", lambda s: True ) - monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s, c: True) + monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) # this just needs to send a known invalid form value response = yield http_client.fetch( From 760c9ee9d291823f9b4920c62741ae1817c2b09a Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Tue, 17 Jul 2018 09:45:34 -0400 Subject: [PATCH 04/11] Add fundz client dep to app --- atst/app.py | 5 +++++ config/base.ini | 1 + 2 files changed, 6 insertions(+) diff --git a/atst/app.py b/atst/app.py index 07f40411..58135096 100644 --- a/atst/app.py +++ b/atst/app.py @@ -126,6 +126,11 @@ def make_deps(config): api_version="v1", validate_cert=validate_cert, ), + "fundz_client": ApiClient( + config["default"]["FUNDZ_BASE_URL"], + api_version="v1", + validate_cert=validate_cert, + ), "requests_client": ApiClient( config["default"]["REQUESTS_QUEUE_BASE_URL"], api_version="v1", diff --git a/config/base.ini b/config/base.ini index 6a367c63..431eacf7 100644 --- a/config/base.ini +++ b/config/base.ini @@ -4,6 +4,7 @@ ENVIRONMENT = dev DEBUG = true AUTHZ_BASE_URL = http://localhost:8002 AUTHNID_BASE_URL= https://localhost:8001 +FUNDZ_BASE_URL= http://localhost:8004 COOKIE_SECRET = some-secret-please-replace SECRET = change_me_into_something_secret CAC_URL = https://localhost:8001 From db097b211fc32f440866dc999fced6f684d8c59c Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Tue, 17 Jul 2018 09:58:00 -0400 Subject: [PATCH 05/11] Pass fundz client to requests_new page handler --- atst/app.py | 18 +++++++++++++++--- atst/handlers/request_new.py | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/atst/app.py b/atst/app.py index 58135096..8577e28e 100644 --- a/atst/app.py +++ b/atst/app.py @@ -57,19 +57,31 @@ def make_app(config, deps, **kwargs): url( r"/requests/new", RequestNew, - {"page": "requests_new", "requests_client": deps["requests_client"]}, + { + "page": "requests_new", + "requests_client": deps["requests_client"], + "fundz_client": deps["fundz_client"], + }, name="request_new", ), url( r"/requests/new/([0-9])", RequestNew, - {"page": "requests_new", "requests_client": deps["requests_client"]}, + { + "page": "requests_new", + "requests_client": deps["requests_client"], + "fundz_client": deps["fundz_client"], + }, name="request_form_new", ), url( r"/requests/new/([0-9])/(\S+)", RequestNew, - {"page": "requests_new", "requests_client": deps["requests_client"]}, + { + "page": "requests_new", + "requests_client": deps["requests_client"], + "fundz_client": deps["fundz_client"], + }, name="request_form_update", ), url( diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 29b99a75..5acdb28f 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -10,7 +10,7 @@ from atst.forms.financial import FinancialForm class RequestNew(BaseHandler): - def initialize(self, page, requests_client): + def initialize(self, page, requests_client, fundz_client): self.page = page self.requests_client = requests_client From 2bca2f9ac86c252601c908008ff5805afa092137 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Tue, 17 Jul 2018 10:27:27 -0400 Subject: [PATCH 06/11] Validate form warnings with existing request and fundz client --- atst/forms/forms.py | 2 +- atst/handlers/request_new.py | 38 ++++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/atst/forms/forms.py b/atst/forms/forms.py index 732bcc52..d49c70ce 100644 --- a/atst/forms/forms.py +++ b/atst/forms/forms.py @@ -3,5 +3,5 @@ from wtforms_tornado import Form class ValidatedForm(Form): - def validate_warnings(self, requests_client=None): + def validate_warnings(self, *args, **kwargs): return True diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 5acdb28f..23315bcd 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -13,6 +13,14 @@ class RequestNew(BaseHandler): def initialize(self, page, requests_client, fundz_client): self.page = page self.requests_client = requests_client + self.fundz_client = fundz_client + + @tornado.gen.coroutine + def get_existing_request(self, current_user, request_id): + request = yield self.requests_client.get( + "/users/{}/requests/{}".format(current_user["id"], request_id), + ) + return request.json @tornado.web.authenticated @tornado.gen.coroutine @@ -20,8 +28,16 @@ class RequestNew(BaseHandler): self.check_xsrf_cookie() screen = int(screen) post_data = self.request.arguments + current_user = self.get_current_user() + existing_request = yield self.get_existing_request(current_user, request_id) jedi_flow = JEDIRequestFlow( - self.requests_client, screen, post_data=post_data, request_id=request_id + self.requests_client, + self.fundz_client, + screen, + post_data=post_data, + request_id=request_id, + current_user=current_user, + existing_request=existing_request, ) rerender_args = dict( @@ -35,7 +51,7 @@ class RequestNew(BaseHandler): ) if jedi_flow.validate(): - response = yield jedi_flow.create_or_update_request(self.get_current_user()) + response = yield jedi_flow.create_or_update_request() if response.ok: if jedi_flow.validate_warnings(): if jedi_flow.next_screen >= len(jedi_flow.screens): @@ -73,7 +89,7 @@ class RequestNew(BaseHandler): request = response.json jedi_flow = JEDIRequestFlow( - self.requests_client, screen, request, request_id=request_id + self.requests_client, self.fundz_client, screen, request, request_id=request_id ) self.render( @@ -93,12 +109,16 @@ class JEDIRequestFlow(object): def __init__( self, requests_client, + fundz_client, current_step, request=None, post_data=None, request_id=None, + current_user=None, + existing_request=None, ): self.requests_client = requests_client + self.fundz_client = fundz_client self.current_step = current_step self.request = request @@ -109,6 +129,9 @@ class JEDIRequestFlow(object): self.request_id = request_id self.form = self._form() + self.current_user = current_user + self.existing_request = existing_request + def _form(self): if self.is_post: return self.form_class()(self.post_data) @@ -121,7 +144,10 @@ class JEDIRequestFlow(object): return self.form.validate() def validate_warnings(self): - return self.form.validate_warnings(self.requests_client) + return self.form.validate_warnings( + self.existing_request.get('body', {}).get(self.form_section), + self.fundz_client, + ) @property def current_screen(self): @@ -201,9 +227,9 @@ class JEDIRequestFlow(object): ] @tornado.gen.coroutine - def create_or_update_request(self, user): + def create_or_update_request(self): request_data = { - "creator_id": user["id"], + "creator_id": self.current_user["id"], "request": {self.form_section: self.form.data}, } if self.request_id: From f1ba2bcba69e5456ed85ce20cbd52bc94ca089fa Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Tue, 17 Jul 2018 16:29:02 -0400 Subject: [PATCH 07/11] Perform extra validation on financial verification step --- atst/forms/financial.py | 27 +++++++++++++++++++++++++++ atst/forms/forms.py | 9 +++++++-- atst/handlers/request_new.py | 7 +++++-- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/atst/forms/financial.py b/atst/forms/financial.py index 9d1bf6c7..3bdb8e53 100644 --- a/atst/forms/financial.py +++ b/atst/forms/financial.py @@ -1,13 +1,40 @@ +import tornado +from tornado.gen import Return from wtforms.fields.html5 import EmailField from wtforms.fields import StringField, SelectField +from wtforms.form import Form from wtforms.validators import Required, Email from .fields import NewlineListField from .forms import ValidatedForm +@tornado.gen.coroutine +def validate_pe_id(field, existing_request, fundz_client): + response = yield fundz_client.get( + "/pe-number/{}".format(field.data), + raise_error=False, + ) + if not response.ok: + field.errors.append( + "We couldn't find that PE number, but if you have double checked " + "it you can submit anyway. Your request will need to go through a " + "manual review." + ) + return False + + return True + + class FinancialForm(ValidatedForm): + @tornado.gen.coroutine + def perform_extra_validation(self, existing_request, fundz_client): + valid = True + if existing_request['pe_id'] != self.pe_id.data: + valid = yield validate_pe_id(self.pe_id, existing_request, fundz_client) + raise Return(valid) + task_order_id = StringField( "Task Order Number associated with this request.", validators=[Required()] ) diff --git a/atst/forms/forms.py b/atst/forms/forms.py index d49c70ce..c3ea02c4 100644 --- a/atst/forms/forms.py +++ b/atst/forms/forms.py @@ -1,7 +1,12 @@ +import tornado +from tornado.gen import Return from wtforms_tornado import Form class ValidatedForm(Form): - def validate_warnings(self, *args, **kwargs): - return True + @tornado.gen.coroutine + def perform_extra_validation(self, *args, **kwargs): + """A coroutine that performs any applicable extra validation. Must + return True if the form is valid or False otherwise.""" + raise Return(True) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 23315bcd..2b31b0f6 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -53,7 +53,8 @@ class RequestNew(BaseHandler): if jedi_flow.validate(): response = yield jedi_flow.create_or_update_request() if response.ok: - if jedi_flow.validate_warnings(): + valid = yield jedi_flow.validate_warnings() + if valid: if jedi_flow.next_screen >= len(jedi_flow.screens): where = "/requests" else: @@ -143,11 +144,13 @@ class JEDIRequestFlow(object): def validate(self): return self.form.validate() + @tornado.gen.coroutine def validate_warnings(self): - return self.form.validate_warnings( + valid = yield self.form.perform_extra_validation( self.existing_request.get('body', {}).get(self.form_section), self.fundz_client, ) + return valid @property def current_screen(self): From 3f8b584ff8a79cf51fb3d317eec8a217d0710012 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 19 Jul 2018 11:29:43 -0400 Subject: [PATCH 08/11] Update url to get a request --- atst/handlers/request_new.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index 2b31b0f6..ee5e1a59 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -16,10 +16,8 @@ class RequestNew(BaseHandler): self.fundz_client = fundz_client @tornado.gen.coroutine - def get_existing_request(self, current_user, request_id): - request = yield self.requests_client.get( - "/users/{}/requests/{}".format(current_user["id"], request_id), - ) + def get_existing_request(self, request_id): + request = yield self.requests_client.get("/requests/{}".format(request_id)) return request.json @tornado.web.authenticated @@ -29,7 +27,7 @@ class RequestNew(BaseHandler): screen = int(screen) post_data = self.request.arguments current_user = self.get_current_user() - existing_request = yield self.get_existing_request(current_user, request_id) + existing_request = yield self.get_existing_request(request_id) jedi_flow = JEDIRequestFlow( self.requests_client, self.fundz_client, From 355d2ed36a9813bc9c0f3c2a9eabd16a7cae67b7 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 19 Jul 2018 11:30:03 -0400 Subject: [PATCH 09/11] Add tests for PE id validation --- atst/forms/financial.py | 2 +- tests/conftest.py | 3 +- tests/handlers/test_request_new.py | 82 ++++++++++++++++++++++++++++++ tests/mocks.py | 40 ++++++++++----- 4 files changed, 111 insertions(+), 16 deletions(-) diff --git a/atst/forms/financial.py b/atst/forms/financial.py index 3bdb8e53..77811ee1 100644 --- a/atst/forms/financial.py +++ b/atst/forms/financial.py @@ -31,7 +31,7 @@ class FinancialForm(ValidatedForm): @tornado.gen.coroutine def perform_extra_validation(self, existing_request, fundz_client): valid = True - if existing_request['pe_id'] != self.pe_id.data: + if not existing_request or existing_request.get('pe_id') != self.pe_id.data: valid = yield validate_pe_id(self.pe_id, existing_request, fundz_client) raise Return(valid) diff --git a/tests/conftest.py b/tests/conftest.py index 469a2100..c650b5f1 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,7 @@ import pytest from atst.app import make_app, make_deps, make_config -from tests.mocks import MockApiClient, MockRequestsClient, MockAuthzClient +from tests.mocks import MockApiClient, MockFundzClient, MockRequestsClient, MockAuthzClient from atst.sessions import DictSessions @@ -11,6 +11,7 @@ def app(): "authz_client": MockAuthzClient("authz"), "requests_client": MockRequestsClient("requests"), "authnid_client": MockApiClient("authnid"), + "fundz_client": MockFundzClient("fundz"), "sessions": DictSessions(), } diff --git a/tests/handlers/test_request_new.py b/tests/handlers/test_request_new.py index 7cd99495..6a8a37f6 100644 --- a/tests/handlers/test_request_new.py +++ b/tests/handlers/test_request_new.py @@ -1,5 +1,8 @@ import re import pytest +import tornado +import urllib +from tests.mocks import MOCK_REQUEST, MOCK_VALID_PE_ID ERROR_CLASS = "usa-input-error-message" MOCK_USER = { @@ -47,3 +50,82 @@ def test_submit_valid_request_form(monkeypatch, http_client, base_url): body="meaning=42", ) assert "/requests/new/2" in response.effective_url + + +class TestPENumberInForm: + + required_data = { + "pe_id": "123", + "task_order_id": "1234567899C0001", + "fname_co": "Contracting", + "lname_co": "Officer", + "email_co": "jane@mail.mil", + "office_co": "WHS", + "fname_cor": "Officer", + "lname_cor": "Representative", + "email_cor": "jane@mail.mil", + "office_cor": "WHS", + "funding_type": "RDTE", + "funding_type_other": "other", + "clin_0001": "50,000", + "clin_0003": "13,000", + "clin_1001": "30,000", + "clin_1003": "7,000", + "clin_2001": "30,000", + "clin_2003": "7,000", + } + + def _set_monkeypatches(self, monkeypatch): + monkeypatch.setattr( + "atst.handlers.request_new.RequestNew.get_current_user", lambda s: MOCK_USER + ) + monkeypatch.setattr( + "atst.handlers.request_new.RequestNew.check_xsrf_cookie", lambda s: True + ) + monkeypatch.setattr("atst.forms.request.RequestForm.validate", lambda s: True) + + @tornado.gen.coroutine + def submit_data(self, http_client, base_url, data): + response = yield http_client.fetch( + base_url + "/requests/new/5/{}".format(MOCK_REQUEST["id"]), + method="POST", + headers={"Content-Type": "application/x-www-form-urlencoded"}, + body=urllib.parse.urlencode(data), + follow_redirects=False, + raise_error=False, + ) + return response + + @pytest.mark.gen_test + def test_submit_request_form_with_invalid_pe_id(self, monkeypatch, http_client, base_url): + self._set_monkeypatches(monkeypatch) + + response = yield self.submit_data(http_client, base_url, self.required_data) + + assert "We couldn\'t find that PE number" in response.body.decode() + assert response.code == 200 + assert "/requests/new/5" in response.effective_url + + @pytest.mark.gen_test + def test_submit_request_form_with_unchanged_pe_id(self, monkeypatch, http_client, base_url): + self._set_monkeypatches(monkeypatch) + + data = dict(self.required_data) + data['pe_id'] = MOCK_REQUEST['body']['financial_verification']['pe_id'] + + response = yield self.submit_data(http_client, base_url, data) + + assert response.code == 302 + assert response.headers.get("Location") == "/requests" + + @pytest.mark.gen_test + def test_submit_request_form_with_new_valid_pe_id(self, monkeypatch, http_client, base_url): + self._set_monkeypatches(monkeypatch) + + data = dict(self.required_data) + data['pe_id'] = MOCK_VALID_PE_ID + + response = yield self.submit_data(http_client, base_url, data) + + assert response.code == 302 + assert response.headers.get("Location") == "/requests" diff --git a/tests/mocks.py b/tests/mocks.py index a04e40bf..6cd3540c 100644 --- a/tests/mocks.py +++ b/tests/mocks.py @@ -43,27 +43,39 @@ class MockApiClient(ApiClient): return response +MOCK_REQUEST = { + "id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b", + "creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238", + "body": { + "financial_verification": { + "pe_id": "0203752A", + }, + }, + "status": "incomplete" +} + class MockRequestsClient(MockApiClient): @tornado.gen.coroutine def get(self, path, **kwargs): - json = { - "id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b", - "creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238", - "body": {}, - "status": "incomplete", - } - return self._get_response("GET", path, 200, json=json) + return self._get_response("GET", path, 200, json=MOCK_REQUEST) @tornado.gen.coroutine def post(self, path, **kwargs): - json = { - "id": "66b8ef71-86d3-48ef-abc2-51bfa1732b6b", - "creator": "49903ae7-da4a-49bf-a6dc-9dff5d004238", - "body": {}, - "status": "incomplete", - } - return self._get_response("POST", path, 202, json=json) + return self._get_response("POST", path, 202, json=MOCK_REQUEST) + + +MOCK_VALID_PE_ID = "8675309U" + + +class MockFundzClient(MockApiClient): + + @tornado.gen.coroutine + def get(self, path, **kwargs): + if path.endswith(MOCK_VALID_PE_ID): + return self._get_response("GET", path, 200) + else: + return self._get_response("GET", path, 404) class MockAuthzClient(MockApiClient): From 07c85125501a152f7807d8a0c0cc35497b0cc5e5 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 19 Jul 2018 14:12:07 -0400 Subject: [PATCH 10/11] Fundz API does not have version info --- atst/app.py | 1 - 1 file changed, 1 deletion(-) diff --git a/atst/app.py b/atst/app.py index 8577e28e..e34d6701 100644 --- a/atst/app.py +++ b/atst/app.py @@ -140,7 +140,6 @@ def make_deps(config): ), "fundz_client": ApiClient( config["default"]["FUNDZ_BASE_URL"], - api_version="v1", validate_cert=validate_cert, ), "requests_client": ApiClient( From 7f972f8db05812eea9dd305ec900a1ad2b8fb387 Mon Sep 17 00:00:00 2001 From: Patrick Smith Date: Thu, 19 Jul 2018 16:59:00 -0400 Subject: [PATCH 11/11] Handle case when request is None --- atst/handlers/request_new.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atst/handlers/request_new.py b/atst/handlers/request_new.py index ee5e1a59..096572d3 100644 --- a/atst/handlers/request_new.py +++ b/atst/handlers/request_new.py @@ -17,6 +17,8 @@ class RequestNew(BaseHandler): @tornado.gen.coroutine def get_existing_request(self, request_id): + if request_id is None: + return {} request = yield self.requests_client.get("/requests/{}".format(request_id)) return request.json