From 059cd6f83aa22cdec53be2952d3167038795d1f2 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Wed, 7 Jul 2021 15:21:00 -0700
Subject: [PATCH 01/39] create middleware logging tests (integration tests)
---
SeleniumDockerfile | 15 +
apps/integration_tests/log_event_schemas.py | 473 ++++++++++++++
apps/integration_tests/logging_tests.py | 614 ++++++++++++++++++
apps/integration_tests/selenium_tests.py | 551 ++++++++++++++++
docker-compose.selenium.yml | 162 +++++
docker-compose.yml | 2 +-
docker-compose/bluebutton_server_start.sh | 34 +-
docker-compose/readme.md | 22 +-
.../run_integration_tests_local_keybase.sh | 1 +
.../run_selenium_tests_local_keybase.sh | 220 +++++++
hhs_oauth_server/settings/test_logging.py | 70 ++
runtests.py | 18 +-
templates/design_system/authorize_v2.html | 2 +-
13 files changed, 2160 insertions(+), 24 deletions(-)
create mode 100755 SeleniumDockerfile
create mode 100755 apps/integration_tests/log_event_schemas.py
create mode 100755 apps/integration_tests/logging_tests.py
create mode 100755 apps/integration_tests/selenium_tests.py
create mode 100755 docker-compose.selenium.yml
create mode 100755 docker-compose/run_selenium_tests_local_keybase.sh
create mode 100755 hhs_oauth_server/settings/test_logging.py
diff --git a/SeleniumDockerfile b/SeleniumDockerfile
new file mode 100755
index 000000000..759971700
--- /dev/null
+++ b/SeleniumDockerfile
@@ -0,0 +1,15 @@
+FROM selenium/standalone-chrome-debug
+
+ENV PYTHONUNBUFFERED 1
+USER root
+RUN apt-get update && apt-get install -yq python3.7 python3-pip
+RUN pip3 install --upgrade pip
+RUN pip3 install selenium
+RUN pip3 install psycopg2-binary==2.8.6
+RUN pip3 install pyyaml==5.4.1
+RUN pip3 install Pillow==8.2.0
+RUN mkdir /code
+ADD . /code/
+WORKDIR /code
+RUN make reqs-install-dev
+RUN ln -s /usr/bin/python3 /usr/local/bin/python
\ No newline at end of file
diff --git a/apps/integration_tests/log_event_schemas.py b/apps/integration_tests/log_event_schemas.py
new file mode 100755
index 000000000..2ab982155
--- /dev/null
+++ b/apps/integration_tests/log_event_schemas.py
@@ -0,0 +1,473 @@
+from rest_framework import status
+
+'''
+ Log entry schemas used for integration tests
+ See the following for information about the JSON Schema vocabulary: https://json-schema.org/
+'''
+
+LOG_MIDDLEWARE_EVENT_SCHEMA = {
+ "title": "MiddlewareLogEventSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "elapsed": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "path": {"pattern": ".+"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK, status.HTTP_301_MOVED_PERMANENTLY]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "elapsed", "request_uuid",
+ "path", "request_method", "request_scheme", "response_code"]
+}
+
+LOG_MIDDLEWARE_POST_EVENT_SCHEMA = {
+ "title": "MiddlewareLogEventSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "elapsed": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "path": {"pattern": ".+"},
+ "request_method": {"pattern": "POST"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "elapsed", "request_uuid",
+ "path", "request_method", "request_scheme", "response_code"]
+}
+
+LOG_MIDDLEWARE_TESTCLIENT_AUTHLINK_EVENT_SCHEMA = {
+ "title": "MiddlewareLogEventSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "path": {"pattern": ".+"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "path", "request_method", "request_scheme", "response_code"]
+}
+
+LOG_MIDDLEWARE_AUTH_START_EVENT_SCHEMA = {
+ "title": "MiddlewareLogEventSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "location": {"pattern": ".+"},
+ "auth_uuid": {"type": "string"},
+ "auth_client_id": {"type": "string"},
+ "auth_app_id": {"type": "string"},
+ "auth_app_name": {"pattern": "TestApp"},
+ "auth_require_demographic_scopes": {"pattern": "^True$"},
+ "req_qparam_client_id": {"type": "string"},
+ "req_qparam_response_type": {"pattern": "code"},
+ "req_app_name": {"pattern": "TestApp"},
+ "req_app_id": {"type": "number"},
+ "path": {"pattern": "/v1/o/authorize/"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_302_FOUND]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "location", "auth_uuid", "auth_client_id", "auth_app_id", "auth_app_name", "auth_require_demographic_scopes",
+ "req_qparam_client_id", "req_qparam_response_type", "req_app_name", "req_app_id",
+ "path", "request_method", "request_scheme", "response_code"]
+}
+
+LOG_MIDDLEWARE_MEDICARE_LOGIN_EVENT_SCHEMA = {
+ "title": "MiddlewareLogEventSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "location": {"pattern": ".+"},
+ "auth_uuid": {"type": "string"},
+ "auth_client_id": {"type": "string"},
+ "auth_app_id": {"type": "string"},
+ "auth_app_name": {"pattern": "TestApp"},
+ "auth_require_demographic_scopes": {"pattern": "^True$"},
+ "path": {"pattern": "/mymedicare/login"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_302_FOUND]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "location", "auth_uuid", "auth_client_id", "auth_app_id", "auth_app_name", "auth_require_demographic_scopes",
+ "path", "request_method", "request_scheme", "response_code"]
+}
+
+LOG_MIDDLEWARE_MEDICARE_CALLBACK_EVENT_SCHEMA = {
+ "title": "MiddlewareLogEventSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "location": {"pattern": ".+"},
+ "auth_uuid": {"type": "string"},
+ "auth_client_id": {"type": "string"},
+ "auth_app_id": {"type": "string"},
+ "auth_app_name": {"pattern": "TestApp"},
+ "auth_crosswalk_action": {"pattern": "R"},
+ "auth_require_demographic_scopes": {"pattern": "^True$"},
+ "req_user_id": {"type": "number"},
+ "req_user_username": {"pattern": "fred"},
+ "req_fhir_id": {"type": "string"},
+ "path": {"pattern": "/mymedicare/sls-callback"},
+ "user": {"type": "string"},
+ "fhir_id": {"type": "string"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_302_FOUND]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "location", "auth_uuid", "auth_client_id", "auth_app_id", "auth_app_name", "auth_require_demographic_scopes",
+ "req_user_id", "req_user_username", "req_fhir_id",
+ "path", "user", "fhir_id", "request_method", "request_scheme", "response_code"]
+}
+
+LOG_MIDDLEWARE_AUTHORIZE_EVENT_SCHEMA = {
+ "title": "MiddlewareLogEventSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "location": {"pattern": ".*"},
+ "auth_uuid": {"type": "string"},
+ "auth_client_id": {"type": "string"},
+ "auth_app_id": {"type": "string"},
+ "auth_app_name": {"pattern": "TestApp"},
+ "auth_crosswalk_action": {"pattern": "R"},
+ "auth_require_demographic_scopes": {"pattern": "^True$"},
+ "req_qparam_client_id": {"type": "string"},
+ "req_qparam_response_type": {"pattern": "code"},
+ "req_app_name": {"pattern": "TestApp"},
+ "req_app_id": {"type": "number"},
+ "path": {"pattern": "/v1/o/authorize/.+"},
+ "user": {"type": "string"},
+ "fhir_id": {"type": "string"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "location", "auth_uuid", "auth_client_id", "auth_app_id", "auth_app_name", "auth_crosswalk_action",
+ "auth_require_demographic_scopes", "req_qparam_client_id",
+ "req_qparam_response_type", "req_app_name", "req_app_id",
+ "path", "user", "fhir_id", "request_method", "request_scheme", "response_code"]
+}
+
+LOG_MIDDLEWARE_ACCESS_GRANT_EVENT_SCHEMA = {
+ "title": "MiddlewareLogEventSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "location": {"pattern": ".+"},
+ "auth_uuid": {"type": "string"},
+ "auth_client_id": {"type": "string"},
+ "auth_app_id": {"type": "string"},
+ "auth_app_name": {"pattern": "TestApp"},
+ "auth_crosswalk_action": {"pattern": "R"},
+ "auth_require_demographic_scopes": {"pattern": "^True$"},
+ "req_redirect_uri": {"type": "string"},
+ "req_scope": {"type": "string"},
+ "req_share_demographic_scopes": {"pattern": "^True$"},
+ "req_allow": {"pattern": "Allow"},
+ "req_user_id": {"type": "integer"},
+ "req_user_username": {"pattern": "fred"},
+ "req_fhir_id": {"type": "string"},
+ "req_qparam_client_id": {"type": "string"},
+ "req_qparam_response_type": {"pattern": "code"},
+ "req_app_name": {"pattern": "TestApp"},
+ "req_app_id": {"type": "number"},
+ "path": {"pattern": "/v1/o/authorize/.+"},
+ "user": {"type": "string"},
+ "fhir_id": {"type": "string"},
+ "request_method": {"pattern": "POST"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_302_FOUND]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "location", "auth_uuid", "auth_client_id", "auth_app_id", "auth_app_name",
+ "auth_crosswalk_action", "auth_require_demographic_scopes",
+ "req_redirect_uri", "req_scope", "req_user_username", "req_fhir_id",
+ "req_qparam_client_id", "req_qparam_response_type", "req_app_name", "req_app_id",
+ "path", "user", "fhir_id", "request_method", "request_scheme", "response_code"]
+}
+
+LOG_MIDDLEWARE_TESTCLIENT_FHIR_READ_EVENT_SCHEMA = {
+ "title": "RequestResponseLogSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ "path": {"pattern": "/testclient/.+"},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "request_method", "request_scheme", "response_code", "path"]
+}
+
+LOG_MIDDLEWARE_TESTCLIENT_FHIR_SEARCH_EVENT_SCHEMA = {
+ "title": "RequestResponseLogSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ "path": {"pattern": "/testclient/.+"},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "request_method", "request_scheme", "response_code", "path"]
+}
+
+LOG_MIDDLEWARE_TESTCLIENT_FHIR_NAVIGATION_EVENT_SCHEMA = {
+ "title": "RequestResponseLogSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ "path": {"pattern": "/testclient/.+"},
+ "req_qparam__count": {"type": "string"},
+ "req_qparam_patient": {"type": "string"},
+ "req_qparam_beneficiary": {"type": "string"},
+ "req_qparam_startindex": {"type": "string"},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "request_method", "request_scheme", "response_code", "path",
+ "req_qparam__count", "req_qparam_startindex"]
+}
+
+LOG_MIDDLEWARE_FHIR_SEARCH_EVENT_SCHEMA = {
+ "title": "RequestResponseLogSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ "req_user_id": {"type": "integer"},
+ "req_user_username": {"pattern": "fred"},
+ "req_fhir_id": {"type": "string"},
+ "req_qparam_format": {"pattern": "json"},
+ "req_qparam_patient": {"type": "string"},
+ "req_qparam_beneficiary": {"type": "string"},
+ "path": {"pattern": "/v1/fhir/.+"},
+ "user": {"type": "string"},
+ "fhir_id": {"type": "string"},
+ "access_token_scopes": {"type": "string"},
+ "access_token_id": {"type": "number"},
+ "app_require_demographic_scopes": {"type": "boolean"},
+ "user_id": {"type": "integer"},
+ "user_username": {"pattern": "fred"},
+ "fhir_bundle_type": {"pattern": "searchset|null"},
+ "fhir_resource_id": {"type": "string"},
+ "fhir_resource_type": {"pattern": "Bundle|Patient|Coverage|ExplanationOfBenefit"},
+ "fhir_attribute_count": {"type": "number"},
+ "fhir_entry_count": {"type": ["number", "null"]},
+ "fhir_total": {"type": ["number", "null"]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "request_method", "request_scheme", "response_code",
+ "req_user_id", "req_user_username", "req_fhir_id", "req_qparam_format",
+ "path", "user", "fhir_id", "access_token_scopes", "access_token_id", "app_require_demographic_scopes",
+ "user_id", "user_username", "fhir_bundle_type", "fhir_resource_id", "fhir_resource_type",
+ "fhir_attribute_count", "fhir_entry_count", "fhir_total"]
+}
+
+LOG_MIDDLEWARE_FHIR_NAVIGATION_EVENT_SCHEMA = {
+ "title": "RequestResponseLogSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ "req_user_id": {"type": "integer"},
+ "req_user_username": {"pattern": "fred"},
+ "req_fhir_id": {"type": "string"},
+ "req_qparam__count": {"type": "string"},
+ "req_qparam_format": {"pattern": "json"},
+ "req_qparam_patient": {"type": "string"},
+ "req_qparam_beneficiary": {"type": "string"},
+ "req_qparam_startindex": {"type": "string"},
+ "path": {"pattern": "/v1/fhir/.+"},
+ "user": {"type": "string"},
+ "fhir_id": {"type": "string"},
+ "access_token_scopes": {"type": "string"},
+ "access_token_id": {"type": "number"},
+ "app_require_demographic_scopes": {"type": "boolean"},
+ "user_id": {"type": "integer"},
+ "user_username": {"pattern": "fred"},
+ "fhir_bundle_type": {"pattern": "searchset|null"},
+ "fhir_resource_id": {"type": "string"},
+ "fhir_resource_type": {"pattern": "Bundle|Patient|Coverage|ExplanationOfBenefit"},
+ "fhir_attribute_count": {"type": "number"},
+ "fhir_entry_count": {"type": ["number", "null"]},
+ "fhir_total": {"type": ["number", "null"]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr",
+ "request_uuid", "request_method", "request_scheme", "response_code",
+ "req_user_id", "req_user_username", "req_fhir_id",
+ "req_qparam__count", "req_qparam_format", "req_qparam_startindex",
+ "path", "user", "fhir_id", "access_token_scopes", "access_token_id", "app_require_demographic_scopes",
+ "user_id", "user_username", "fhir_bundle_type", "fhir_resource_id", "fhir_resource_type",
+ "fhir_attribute_count", "fhir_entry_count", "fhir_total"]
+}
+
+LOG_MIDDLEWARE_FHIR_READ_EVENT_SCHEMA = {
+ "title": "RequestResponseLogSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ "req_user_id": {"type": "integer"},
+ "req_user_username": {"pattern": "fred"},
+ "req_fhir_id": {"type": "string"},
+ "path": {"pattern": "/v1/fhir/.+"},
+ "user": {"type": "string"},
+ "fhir_id": {"type": "string"},
+ "access_token_scopes": {"type": "string"},
+ "access_token_id": {"type": "number"},
+ "app_require_demographic_scopes": {"type": "boolean"},
+ "user_id": {"type": "integer"},
+ "user_username": {"pattern": "fred"},
+ "fhir_bundle_type": {"pattern": "searchset|null"},
+ "fhir_resource_id": {"type": "string"},
+ "fhir_resource_type": {"pattern": "Bundle|Patient|Coverage|ExplanationOfBenefit"},
+ "fhir_attribute_count": {"type": "number"},
+ "fhir_entry_count": {"type": ["number", "null"]},
+ "fhir_total": {"type": ["number", "null"]},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr",
+ "request_uuid", "request_method", "request_scheme", "response_code",
+ "req_user_id", "req_user_username", "req_fhir_id",
+ "path", "user", "fhir_id", "access_token_scopes", "access_token_id", "app_require_demographic_scopes",
+ "user_id", "user_username", "fhir_bundle_type", "fhir_resource_id", "fhir_resource_type",
+ "fhir_attribute_count", "fhir_entry_count", "fhir_total"]
+}
+
+LOG_MIDDLEWARE_FHIR_USERINFO_EVENT_SCHEMA = {
+ "title": "RequestResponseLogSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ "req_user_id": {"type": "integer"},
+ "req_user_username": {"pattern": "fred"},
+ "req_fhir_id": {"type": "string"},
+ "path": {"pattern": "/v1/connect/userinfo"},
+ "user": {"type": "string"},
+ "fhir_id": {"type": "string"},
+ "access_token_scopes": {"type": "string"},
+ "access_token_id": {"type": "number"},
+ "app_require_demographic_scopes": {"type": "boolean"},
+ "user_id": {"type": "integer"},
+ "user_username": {"pattern": "fred"},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "request_method", "request_scheme", "response_code",
+ "req_user_id", "req_user_username", "req_fhir_id",
+ "path", "user", "fhir_id", "access_token_scopes",
+ "access_token_id", "app_require_demographic_scopes",
+ "user_id", "user_username"]
+}
+
+LOG_MIDDLEWARE_TESTCLIENT_MISCINFO_EVENT_SCHEMA = {
+ "title": "RequestResponseLogSchema",
+ "type": "object",
+ "properties": {
+ "type": {"pattern": "request_response_middleware"},
+ "size": {"type": "integer"},
+ "start_time": {"type": "number"},
+ "end_time": {"type": "number"},
+ "ip_addr": {"type": "string", "format": "ip-address"},
+ "request_uuid": {"type": "string", "format": "uuid"},
+ "request_method": {"pattern": "GET"},
+ "request_scheme": {"pattern": "http"},
+ "response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
+ "path": {"pattern": "/testclient/userinfo|/testclient/openidConfig|/testclient/metadata|/testclient/restart"},
+ },
+ "required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
+ "request_method", "request_scheme", "response_code", "path"]
+}
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
new file mode 100755
index 000000000..cedcbcc79
--- /dev/null
+++ b/apps/integration_tests/logging_tests.py
@@ -0,0 +1,614 @@
+import copy
+import json
+import jsonschema
+import os
+import re
+import time
+
+from django.conf import settings
+from django.test import TestCase
+from enum import Enum
+from json.decoder import JSONDecodeError
+from jsonschema import validate
+
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.support.wait import WebDriverWait
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+from selenium.webdriver.common.keys import Keys
+from apps.integration_tests.log_event_schemas import (
+ LOG_MIDDLEWARE_FHIR_READ_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_FHIR_SEARCH_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_FHIR_NAVIGATION_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_FHIR_USERINFO_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_POST_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_TESTCLIENT_FHIR_NAVIGATION_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_TESTCLIENT_FHIR_READ_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_TESTCLIENT_FHIR_SEARCH_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_ACCESS_GRANT_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_AUTHORIZE_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_MEDICARE_CALLBACK_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_MEDICARE_LOGIN_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_TESTCLIENT_AUTHLINK_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_AUTH_START_EVENT_SCHEMA,
+ LOG_MIDDLEWARE_TESTCLIENT_MISCINFO_EVENT_SCHEMA
+)
+
+TEST_LOGGING_FILE = "./docker-compose/tmp/bb2_logging_test.log"
+MIDDLEWARE_LOG_EVENT_TYPE = "request_response_middleware"
+
+EXPECTED_LOGGING_EVENTS = [
+ {
+ # clicked test client
+ "schema": LOG_MIDDLEWARE_EVENT_SCHEMA,
+ "path": "/testclient/",
+ },
+ {
+ # v1 auth link
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_AUTHLINK_EVENT_SCHEMA,
+ "path": "/testclient/authorize-link",
+ },
+ {
+ # authorize as a bene
+ "schema": LOG_MIDDLEWARE_AUTH_START_EVENT_SCHEMA,
+ "path": "/v1/o/authorize/",
+ },
+ {
+ "schema": LOG_MIDDLEWARE_MEDICARE_LOGIN_EVENT_SCHEMA,
+ "path": "/mymedicare/login"
+ },
+ {
+ "schema": LOG_MIDDLEWARE_MEDICARE_CALLBACK_EVENT_SCHEMA,
+ "path": "/mymedicare/sls-callback",
+ },
+ {
+ "schema": LOG_MIDDLEWARE_AUTHORIZE_EVENT_SCHEMA,
+ "path_regex": "/v1/o/authorize/.+/"
+ },
+ {
+ "schema": LOG_MIDDLEWARE_ACCESS_GRANT_EVENT_SCHEMA,
+ "path_regex": "/v1/o/authorize/.+/"
+ },
+ {
+ "schema": LOG_MIDDLEWARE_POST_EVENT_SCHEMA,
+ "path": "/v1/o/token/",
+ },
+ {
+ "schema": LOG_MIDDLEWARE_EVENT_SCHEMA,
+ "path": "/v1/connect/userinfo",
+ },
+ {
+ "schema": LOG_MIDDLEWARE_EVENT_SCHEMA,
+ "path": "/testclient/callback",
+ # "response_code": 301
+ },
+ {
+ # redirect to test client fhir links page
+ "schema": LOG_MIDDLEWARE_EVENT_SCHEMA,
+ "path": "/testclient/"
+ },
+ {
+ "schema": LOG_MIDDLEWARE_FHIR_READ_EVENT_SCHEMA,
+ "path": "/v1/fhir/Patient/-20140000008325"
+ },
+ {
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_FHIR_READ_EVENT_SCHEMA,
+ "path": "/testclient/Patient"
+ },
+ {
+ # first Coverage
+ "schema": LOG_MIDDLEWARE_FHIR_SEARCH_EVENT_SCHEMA,
+ "path": "/v1/fhir/Coverage/"
+ },
+ {
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_FHIR_SEARCH_EVENT_SCHEMA,
+ "path": "/testclient/Coverage"
+ },
+ {
+ # last Coverage
+ "schema": LOG_MIDDLEWARE_FHIR_NAVIGATION_EVENT_SCHEMA,
+ "path": "/v1/fhir/Coverage/"
+ },
+ {
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_FHIR_NAVIGATION_EVENT_SCHEMA,
+ "path": "/testclient/Coverage"
+ },
+ {
+ # test client fhir links page
+ "schema": LOG_MIDDLEWARE_EVENT_SCHEMA,
+ "path": "/testclient/"
+ },
+ {
+ # first EOB
+ "schema": LOG_MIDDLEWARE_FHIR_SEARCH_EVENT_SCHEMA,
+ "path": "/v1/fhir/ExplanationOfBenefit/"
+ },
+ {
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_FHIR_SEARCH_EVENT_SCHEMA,
+ "path": "/testclient/ExplanationOfBenefit"
+ },
+ {
+ # last EOB
+ "schema": LOG_MIDDLEWARE_FHIR_NAVIGATION_EVENT_SCHEMA,
+ "path": "/v1/fhir/ExplanationOfBenefit/"
+ },
+ {
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_FHIR_NAVIGATION_EVENT_SCHEMA,
+ "path": "/testclient/ExplanationOfBenefit"
+ },
+ {
+ # test client fhir links page
+ "schema": LOG_MIDDLEWARE_EVENT_SCHEMA,
+ "path": "/testclient/"
+ },
+ {
+ # userinfo ep
+ "schema": LOG_MIDDLEWARE_FHIR_USERINFO_EVENT_SCHEMA,
+ "path": "/v1/connect/userinfo"
+ },
+ {
+ # userinfo testclient url
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_MISCINFO_EVENT_SCHEMA,
+ "path": "/testclient/userinfo"
+ },
+ {
+ # meta data
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_MISCINFO_EVENT_SCHEMA,
+ "path": "/testclient/metadata"
+ },
+ {
+ # openid discovery
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_MISCINFO_EVENT_SCHEMA,
+ "path": "/testclient/openidConfig"
+ },
+ {
+ # restart test client - go to test client home page with v1, v2 get sample token buttons
+ "schema": LOG_MIDDLEWARE_TESTCLIENT_MISCINFO_EVENT_SCHEMA,
+ "path": "/testclient/restart"
+ },
+
+]
+
+TESTCLIENT_BUNDLE_LABEL_FMT = "Response (Bundle of {}), API version: {}"
+TESTCLIENT_RESOURCE_LABEL_FMT = "Response ({}), API version: {}"
+MESSAGE_NO_PERMISSION = "You do not have permission to perform this action."
+TESTCASE_BANNER_FMT = "** {} TEST: {}, API: {}, STEP: {}, {}"
+'''
+UI Widget text: texts on e.g. buttons, links, labels etc.
+'''
+LNK_TXT_TESTCLIENT = "Test Client"
+LNK_TXT_GET_TOKEN_V1 = "Get a Sample Authorization Token"
+LNK_TXT_GET_TOKEN_V2 = "Get a Sample Authorization Token for v2"
+LNK_TXT_AUTH_AS_BENE = "Authorize as a Beneficiary"
+LNK_TXT_RESTART_TESTCLIENT = "restart testclient"
+# FHIR search result bundle pagination
+LNK_TXT_NAV_FIRST = "first"
+LNK_TXT_NAV_NEXT = "next"
+LNK_TXT_NAV_PREV = "previous"
+LNK_TXT_NAV_LAST = "last"
+LNK_TXT_NAV_SELF = "self"
+# FHIR resources query page
+LNK_TXT_PATIENT = "Patient"
+LNK_TXT_EOB = "ExplanationOfBenefit"
+LNK_TXT_COVERAGE = "Coverage"
+LNK_TXT_PROFILE = "Profile"
+LNK_TXT_METADATA = "FHIR Metadata"
+LNK_TXT_OIDC_DISCOVERY = "OIDC Discovery"
+# FHIR result page label H2
+LAB_FHIR_RESULTPAGE_H2 = "h2"
+CONTENT_FHIR_RESULTPAGE_PRE = "pre"
+# MSLSX login form
+TXT_FLD_SUB_MSLSX = "username"
+TXT_FLD_HICN_MSLSX = "hicn"
+TXT_FLD_MBI_MSLSX = "mbi"
+TXT_FLD_VAL_SUB_MSLSX = "fred"
+MSLSX_TXT_FLD_HICN_VAL = "1000044680"
+MSLSX_TXT_FLD_MBI_VAL = "2SW4N00AA00"
+MSLSX_CSS_BUTTON = "button"
+# SLSX login form
+SLSX_TXT_FLD_USERNAME = "username-textbox"
+SLSX_TXT_FLD_PASSWORD = "password-textbox"
+SLSX_TXT_FLD_USERNAME_VAL = "BBUser00000"
+SLSX_TXT_FLD_PASSWORD_VAL = "PW00000!"
+SLSX_CSS_BUTTON = "login-button"
+# Demographic info access grant form
+BTN_ID_GRANT_DEMO_ACCESS = "approve"
+BTN_ID_DENY_DEMO_ACCESS = "deny"
+BTN_ID_RADIO_NOT_SHARE = "label:nth-child(5)"
+# API versions
+API_V2 = "v2"
+API_V1 = "v1"
+
+
+class Action(Enum):
+ LOAD_PAGE = 1
+ FIND_CLICK = 2
+ FIND = 3
+ FIND_SEND_KEY = 4
+ CHECK = 5
+ BACK = 6
+ LOGIN = 7
+ CONTAIN_TEXT = 8
+ GET_SAMPLE_TOKEN_START = 9
+ SLEEP = 10
+
+
+BROWSERBACK = {
+ "display": "Back to FHIR resource page",
+ "action": Action.BACK,
+}
+
+WAIT_SECONDS = {
+ "display": "Sleep seconds...",
+ "action": Action.SLEEP,
+ "params": [3],
+}
+
+CHECK_TESTCLIENT_START_PAGE = {
+ "display": "Check it's on 'Test Client' start page",
+ "action": Action.FIND,
+ "params": [30, By.LINK_TEXT, LNK_TXT_GET_TOKEN_V1]
+}
+
+CLICK_TESTCLIENT = {
+ "display": "Click link 'Test Client'",
+ "action": Action.FIND_CLICK,
+ "params": [30, By.LINK_TEXT, LNK_TXT_TESTCLIENT]
+}
+
+CLICK_RADIO_NOT_SHARE = {
+ "display": "Click 'Share healthcare data, but not your personal info' on DEMO info grant form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.CSS_SELECTOR, BTN_ID_RADIO_NOT_SHARE]
+}
+
+CLICK_AGREE_ACCESS = {
+ "display": "Click 'Agree' on DEMO info grant form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.ID, BTN_ID_GRANT_DEMO_ACCESS]
+}
+
+CLICK_DENY_ACCESS = {
+ "display": "Click 'Deny' on DEMO info grant form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.ID, BTN_ID_DENY_DEMO_ACCESS]
+}
+
+CALL_LOGIN = {
+ "display": "Start login ...",
+ "action": Action.LOGIN,
+}
+
+SEQ_LOGIN_MSLSX = [
+ {
+ "display": "Input SUB(username)",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.NAME, TXT_FLD_SUB_MSLSX, TXT_FLD_VAL_SUB_MSLSX]
+ },
+ {
+ "display": "Input hicn",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.NAME, TXT_FLD_HICN_MSLSX, MSLSX_TXT_FLD_HICN_VAL]
+ },
+ {
+ "display": "Input mbi",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.NAME, TXT_FLD_MBI_MSLSX, MSLSX_TXT_FLD_MBI_VAL]
+ },
+ {
+ "display": "Click 'submit' on MSLSX login form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.CSS_SELECTOR, MSLSX_CSS_BUTTON]
+ },
+]
+
+SEQ_LOGIN_SLSX = [
+ {
+ "display": "MyMedicare login username",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.ID, SLSX_TXT_FLD_USERNAME, SLSX_TXT_FLD_USERNAME_VAL]
+ },
+ {
+ "display": "MyMedicare login password",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.ID, SLSX_TXT_FLD_PASSWORD, SLSX_TXT_FLD_PASSWORD_VAL]
+ },
+ {
+ "display": "Click 'submit' on SLSX login form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.ID, SLSX_CSS_BUTTON]
+ },
+]
+
+SEQ_AUTHORIZE_START = [
+ {
+ "display": "Load BB2 Landing Page ...",
+ "action": Action.LOAD_PAGE,
+ "params": [settings.HOSTNAME_URL]
+ },
+ CLICK_TESTCLIENT,
+ {
+ "display": "Click link to get sample token v1/v2",
+ "action": Action.GET_SAMPLE_TOKEN_START,
+ },
+ {
+ "display": "Click link 'Authorize as a Beneficiary' - start authorization",
+ "action": Action.FIND_CLICK,
+ "params": [30, By.LINK_TEXT, LNK_TXT_AUTH_AS_BENE]
+ },
+]
+
+SEQ_QUERY_FHIR_RESOURCES = [
+ {
+ "display": "Click 'Patient' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PATIENT]
+ },
+ {
+ "display": "Check Patient result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_PATIENT]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'Coverage' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check Coverage result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check and click Coverage result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ CLICK_TESTCLIENT,
+ {
+ "display": "Click 'ExplanationOfBenefit' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check ExplanationOfBenefit result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check and click ExplanationOfBenefit result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ WAIT_SECONDS,
+ CLICK_TESTCLIENT,
+ WAIT_SECONDS,
+ {
+ "display": "Click 'Profile' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PROFILE]
+ },
+ WAIT_SECONDS,
+ {
+ "display": "Check Profile result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT,
+ "{} (OIDC Userinfo)".format(LNK_TXT_PROFILE)]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'FHIR Metadata' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_METADATA]
+ },
+ {
+ "display": "Check FHIR Metadata result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_METADATA]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'OIDC Discovery' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ {
+ "display": "Check OIDC Discovery result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ BROWSERBACK,
+]
+
+TESTS = {
+ "auth_fhir_flow_calls_logging": [
+ {"sequence": SEQ_AUTHORIZE_START},
+ CALL_LOGIN,
+ CLICK_AGREE_ACCESS,
+ {"sequence": SEQ_QUERY_FHIR_RESOURCES}
+ ],
+}
+
+
+class LoggingTests(TestCase):
+ '''
+ Test loggings generated from authorization and fhir flow using the built in testclient as
+ the driver (selenium)
+ '''
+ wait_completed = False
+
+ def _validateJsonSchema(self, schema, content):
+ # print("SCHEMA={}".format(schema))
+ # print("CONTENT={}".format(content))
+ try:
+ validate(instance=content, schema=schema)
+ except jsonschema.exceptions.ValidationError as e:
+ # Show error info for debugging
+ print("jsonschema.exceptions.ValidationError: ", e)
+ return False
+ return True
+
+ def setUp(self):
+ super(LoggingTests, self).setUp()
+ # a bit waiting for selenium service ready for sure
+ if not LoggingTests.wait_completed:
+ time.sleep(20)
+ LoggingTests.wait_completed = True
+ print("set wait_completed={}".format(LoggingTests.wait_completed))
+ else:
+ print("wait_completed={}".format(LoggingTests.wait_completed))
+
+ opt = webdriver.ChromeOptions()
+ opt.add_argument('--headless')
+ opt.add_argument("--disable-dev-shm-usage")
+ opt.add_argument("--disable-web-security")
+ opt.add_argument("--allow-running-insecure-content")
+ opt.add_argument("--no-sandbox")
+ opt.add_argument("--disable-setuid-sandbox")
+ opt.add_argument("--disable-webgl")
+ opt.add_argument("--disable-popup-blocking")
+ opt.add_argument("--enable-javascript")
+ opt.add_argument('--allow-insecure-localhost')
+ opt.add_argument('--window-size=1920,1080')
+ opt.add_argument("--whitelisted-ips=''")
+
+ self.driver = webdriver.Remote(
+ command_executor='http://selenium-hub:4444',
+ desired_capabilities=DesiredCapabilities.CHROME, options=opt)
+
+ self.actions = {
+ Action.LOAD_PAGE: self._load_page,
+ Action.FIND_CLICK: self._find_and_click,
+ Action.FIND: self._find_and_return,
+ Action.FIND_SEND_KEY: self._find_and_sendkey,
+ Action.CHECK: self._check_page_title,
+ Action.CONTAIN_TEXT: self._check_page_content,
+ Action.GET_SAMPLE_TOKEN_START: self._click_get_sample_token,
+ Action.BACK: self._back,
+ Action.LOGIN: self._login,
+ Action.SLEEP: self._sleep,
+ }
+ self.use_mslsx = os.environ['USE_MSLSX']
+ self.login_seq = SEQ_LOGIN_MSLSX if self.use_mslsx == 'true' else SEQ_LOGIN_SLSX
+
+ def tearDown(self):
+ self.driver.quit()
+ super(LoggingTests, self).tearDown()
+
+ def _find_and_click(self, timeout_sec, by, by_expr, **kwargs):
+ elem = WebDriverWait(self.driver, timeout_sec).until(EC.visibility_of_element_located((by, by_expr)))
+ self.assertIsNotNone(elem)
+ elem.click()
+ return elem
+
+ def _testclient_home(self, **kwargs):
+ return self._find_and_click(30, By.LINK_TEXT, LNK_TXT_RESTART_TESTCLIENT, **kwargs)
+
+ def _find_and_sendkey(self, timeout_sec, by, by_expr, txt, **kwargs):
+ elem = WebDriverWait(self.driver, timeout_sec).until(EC.visibility_of_element_located((by, by_expr)))
+ self.assertIsNotNone(elem)
+ elem.send_keys(txt)
+ return elem
+
+ def _click_get_sample_token(self, **kwargs):
+ return self._find_and_click(30, By.LINK_TEXT,
+ LNK_TXT_GET_TOKEN_V2 if kwargs.get("api_ver", API_V1) == API_V2 else LNK_TXT_GET_TOKEN_V1)
+
+ def _find_and_return(self, timeout_sec, by, by_expr, **kwargs):
+ elem = WebDriverWait(self.driver, timeout_sec).until(EC.visibility_of_element_located((by, by_expr)))
+ self.assertIsNotNone(elem)
+ return elem
+
+ def _load_page(self, url, **kwargs):
+ self.driver.get(url)
+
+ def _check_page_title(self, timeout_sec, by, by_expr, fmt, resource_type, **kwargs):
+ elem = self._find_and_return(timeout_sec, by, by_expr, **kwargs)
+ if not (elem.text == fmt.format(resource_type, kwargs.get("api_ver"))):
+ print("PAGE:{}".format(self.driver.page_source))
+ self.assertEqual(elem.text, fmt.format(resource_type, kwargs.get("api_ver")))
+
+ def _check_page_content(self, timeout_sec, by, by_expr, content_txt, **kwargs):
+ elem = self._find_and_return(timeout_sec, by, by_expr, **kwargs)
+ self.assertIn(content_txt, elem.text)
+
+ def _back(self, **kwargs):
+ self.driver.back()
+
+ def _sleep(self, sec, **kwargs):
+ time.sleep(sec)
+
+ def _login(self, step, **kwargs):
+ if self.use_mslsx == 'false':
+ # dismiss mymedicare popup if present
+ webdriver.ActionChains(self.driver).send_keys(Keys.ESCAPE).perform()
+ self._play(self.login_seq, step, **kwargs)
+
+ def _print_testcase_banner(self, test_name, api_ver, step_0, id_service, start=True):
+ print()
+ print("******************************************************************")
+ print(TESTCASE_BANNER_FMT.format("START" if start else "END", test_name, api_ver, step_0,
+ "MSLSX" if id_service == 'true' else "SLSX"))
+ print("******************************************************************")
+ print()
+
+ def _play(self, lst, step, **kwargs):
+ for s in lst:
+ seq = s.get("sequence")
+ # expects sequence of actions or action
+ if seq is not None:
+ self._play(seq, step, **kwargs)
+ else:
+ # single action
+ action = s.get('action', None)
+ step[0] = step[0] + 1
+ if action is not None:
+ print("{}:{}:".format(step[0], s.get("display", "Not available")))
+ if action == Action.LOGIN:
+ self.actions[action](*s.get("params", []), step, **kwargs)
+ else:
+ self.actions[action](*s.get("params", []), **kwargs)
+ else:
+ raise ValueError("Invalid test case, expect dict with action...")
+
+ def test_auth_fhir_flows_logging(self):
+ step = [0]
+ test_name = "auth_fhir_flow_calls_logging"
+ api_ver = API_V1
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, True)
+ self._play(TESTS[test_name], step, api_ver=api_ver)
+ self._testclient_home()
+ self._validate_events()
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, False)
+
+ def _validate_events(self):
+ # validate middleware logging records in log file ./docker-compose/tmp/bb2_logging_test.log
+ with open(TEST_LOGGING_FILE, 'r') as f:
+ log_records = f.readlines()
+ start_validation = False
+ expected_events = copy.deepcopy(EXPECTED_LOGGING_EVENTS)
+ while log_records:
+ r = log_records.pop(0)
+ try:
+ event_json = json.loads(r)
+ if event_json.get('type', 'NO TYPE INFO') == MIDDLEWARE_LOG_EVENT_TYPE:
+ p = event_json.get('path', None)
+ if not start_validation:
+ if p == "/":
+ start_validation = True
+ else:
+ event_desc = expected_events.pop(0)
+ if event_desc.get('path_regex') is not None:
+ self.assertTrue(re.match(event_desc.get('path_regex'), p))
+ else:
+ self.assertEqual(p, event_desc.get('path'))
+ self.assertTrue(self._validateJsonSchema(event_desc.get('schema'), event_json))
+ except JSONDecodeError:
+ # skip non json line
+ pass
+
+ # all log events present and validated
+ self.assertEqual(len(expected_events), 0)
diff --git a/apps/integration_tests/selenium_tests.py b/apps/integration_tests/selenium_tests.py
new file mode 100755
index 000000000..15dee6b1b
--- /dev/null
+++ b/apps/integration_tests/selenium_tests.py
@@ -0,0 +1,551 @@
+import os
+import time
+from django.conf import settings
+from django.test import TestCase
+from enum import Enum
+
+from selenium import webdriver
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.support.wait import WebDriverWait
+from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
+from selenium.webdriver.common.keys import Keys
+
+TESTCLIENT_BUNDLE_LABEL_FMT = "Response (Bundle of {}), API version: {}"
+TESTCLIENT_RESOURCE_LABEL_FMT = "Response ({}), API version: {}"
+MESSAGE_NO_PERMISSION = "You do not have permission to perform this action."
+TESTCASE_BANNER_FMT = "** {} TEST: {}, API: {}, STEP: {}, {}"
+'''
+UI Widget text: texts on e.g. buttons, links, labels etc.
+'''
+LNK_TXT_TESTCLIENT = "Test Client"
+LNK_TXT_GET_TOKEN_V1 = "Get a Sample Authorization Token"
+LNK_TXT_GET_TOKEN_V2 = "Get a Sample Authorization Token for v2"
+LNK_TXT_AUTH_AS_BENE = "Authorize as a Beneficiary"
+LNK_TXT_RESTART_TESTCLIENT = "restart testclient"
+# FHIR search result bundle pagination
+LNK_TXT_NAV_FIRST = "first"
+LNK_TXT_NAV_NEXT = "next"
+LNK_TXT_NAV_PREV = "previous"
+LNK_TXT_NAV_LAST = "last"
+LNK_TXT_NAV_SELF = "self"
+# FHIR resources query page
+LNK_TXT_PATIENT = "Patient"
+LNK_TXT_EOB = "ExplanationOfBenefit"
+LNK_TXT_COVERAGE = "Coverage"
+LNK_TXT_PROFILE = "Profile"
+LNK_TXT_METADATA = "FHIR Metadata"
+LNK_TXT_OIDC_DISCOVERY = "OIDC Discovery"
+# FHIR result page label H2
+LAB_FHIR_RESULTPAGE_H2 = "h2"
+CONTENT_FHIR_RESULTPAGE_PRE = "pre"
+# MSLSX login form
+TXT_FLD_SUB_MSLSX = "username"
+TXT_FLD_HICN_MSLSX = "hicn"
+TXT_FLD_MBI_MSLSX = "mbi"
+TXT_FLD_VAL_SUB_MSLSX = "fred"
+MSLSX_TXT_FLD_HICN_VAL = "1000044680"
+MSLSX_TXT_FLD_MBI_VAL = "2SW4N00AA00"
+MSLSX_CSS_BUTTON = "button"
+# SLSX login form
+SLSX_TXT_FLD_USERNAME = "username-textbox"
+SLSX_TXT_FLD_PASSWORD = "password-textbox"
+SLSX_TXT_FLD_USERNAME_VAL = "BBUser00000"
+SLSX_TXT_FLD_PASSWORD_VAL = "PW00000!"
+SLSX_CSS_BUTTON = "login-button"
+# Demographic info access grant form
+BTN_ID_GRANT_DEMO_ACCESS = "approve"
+BTN_ID_DENY_DEMO_ACCESS = "deny"
+BTN_ID_RADIO_NOT_SHARE = "label:nth-child(5)"
+# API versions
+API_V2 = "v2"
+API_V1 = "v1"
+
+
+class Action(Enum):
+ LOAD_PAGE = 1
+ FIND_CLICK = 2
+ FIND = 3
+ FIND_SEND_KEY = 4
+ CHECK = 5
+ BACK = 6
+ LOGIN = 7
+ CONTAIN_TEXT = 8
+ GET_SAMPLE_TOKEN_START = 9
+ SLEEP = 10
+
+
+BROWSERBACK = {
+ "display": "Back to FHIR resource page",
+ "action": Action.BACK,
+}
+
+WAIT_SECONDS = {
+ "display": "Sleep seconds...",
+ "action": Action.SLEEP,
+ "params": [3],
+}
+
+CHECK_TESTCLIENT_START_PAGE = {
+ "display": "Check it's on 'Test Client' start page",
+ "action": Action.FIND,
+ "params": [30, By.LINK_TEXT, LNK_TXT_GET_TOKEN_V1]
+}
+
+CLICK_TESTCLIENT = {
+ "display": "Click link 'Test Client'",
+ "action": Action.FIND_CLICK,
+ "params": [30, By.LINK_TEXT, LNK_TXT_TESTCLIENT]
+}
+
+CLICK_RADIO_NOT_SHARE = {
+ "display": "Click 'Share healthcare data, but not your personal info' on DEMO info grant form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.CSS_SELECTOR, BTN_ID_RADIO_NOT_SHARE]
+}
+
+CLICK_AGREE_ACCESS = {
+ "display": "Click 'Agree' on DEMO info grant form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.ID, BTN_ID_GRANT_DEMO_ACCESS]
+}
+
+CLICK_DENY_ACCESS = {
+ "display": "Click 'Deny' on DEMO info grant form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.ID, BTN_ID_DENY_DEMO_ACCESS]
+}
+
+CALL_LOGIN = {
+ "display": "Start login ...",
+ "action": Action.LOGIN,
+}
+
+SEQ_LOGIN_MSLSX = [
+ {
+ "display": "Input SUB(username)",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.NAME, TXT_FLD_SUB_MSLSX, TXT_FLD_VAL_SUB_MSLSX]
+ },
+ {
+ "display": "Input hicn",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.NAME, TXT_FLD_HICN_MSLSX, MSLSX_TXT_FLD_HICN_VAL]
+ },
+ {
+ "display": "Input mbi",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.NAME, TXT_FLD_MBI_MSLSX, MSLSX_TXT_FLD_MBI_VAL]
+ },
+ {
+ "display": "Click 'submit' on MSLSX login form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.CSS_SELECTOR, MSLSX_CSS_BUTTON]
+ },
+]
+
+SEQ_LOGIN_SLSX = [
+ {
+ "display": "MyMedicare login username",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.ID, SLSX_TXT_FLD_USERNAME, SLSX_TXT_FLD_USERNAME_VAL]
+ },
+ {
+ "display": "MyMedicare login password",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.ID, SLSX_TXT_FLD_PASSWORD, SLSX_TXT_FLD_PASSWORD_VAL]
+ },
+ {
+ "display": "Click 'submit' on SLSX login form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.ID, SLSX_CSS_BUTTON]
+ },
+]
+
+SEQ_AUTHORIZE_START = [
+ {
+ "display": "Load BB2 Landing Page ...",
+ "action": Action.LOAD_PAGE,
+ "params": [settings.HOSTNAME_URL]
+ },
+ CLICK_TESTCLIENT,
+ {
+ "display": "Click link to get sample token v1/v2",
+ "action": Action.GET_SAMPLE_TOKEN_START,
+ },
+ {
+ "display": "Click link 'Authorize as a Beneficiary' - start authorization",
+ "action": Action.FIND_CLICK,
+ "params": [30, By.LINK_TEXT, LNK_TXT_AUTH_AS_BENE]
+ },
+]
+
+SEQ_QUERY_FHIR_RESOURCES = [
+ {
+ "display": "Click 'Patient' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PATIENT]
+ },
+ {
+ "display": "Check Patient result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_PATIENT]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'Coverage' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check Coverage result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check and click Coverage result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ CLICK_TESTCLIENT,
+ {
+ "display": "Click 'ExplanationOfBenefit' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check ExplanationOfBenefit result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check and click ExplanationOfBenefit result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ WAIT_SECONDS,
+ CLICK_TESTCLIENT,
+ WAIT_SECONDS,
+ {
+ "display": "Click 'Profile' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PROFILE]
+ },
+ WAIT_SECONDS,
+ {
+ "display": "Check Profile result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT,
+ "{} (OIDC Userinfo)".format(LNK_TXT_PROFILE)]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'FHIR Metadata' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_METADATA]
+ },
+ {
+ "display": "Check FHIR Metadata result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_METADATA]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'OIDC Discovery' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ {
+ "display": "Check OIDC Discovery result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ BROWSERBACK,
+]
+
+SEQ_QUERY_FHIR_RESOURCES_NO_DEMO = [
+ {
+ "display": "Click 'Patient' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PATIENT]
+ },
+ {
+ "display": "Check Patient result page content () expect no permission message",
+ "action": Action.CONTAIN_TEXT,
+ "params": [20, By.TAG_NAME, CONTENT_FHIR_RESULTPAGE_PRE, MESSAGE_NO_PERMISSION]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'Coverage' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check Coverage result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check and click Coverage result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ CLICK_TESTCLIENT,
+ {
+ "display": "Click 'ExplanationOfBenefit' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check ExplanationOfBenefit result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check and click ExplanationOfBenefit result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ WAIT_SECONDS,
+ CLICK_TESTCLIENT,
+ WAIT_SECONDS,
+ {
+ "display": "Click 'Profile' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PROFILE]
+ },
+ WAIT_SECONDS,
+ {
+ "display": "Check Profile result page content () expect no permission message",
+ "action": Action.CONTAIN_TEXT,
+ "params": [20, By.TAG_NAME, CONTENT_FHIR_RESULTPAGE_PRE, MESSAGE_NO_PERMISSION]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'FHIR Metadata' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_METADATA]
+ },
+ {
+ "display": "Check FHIR Metadata result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_METADATA]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'OIDC Discovery' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ {
+ "display": "Check OIDC Discovery result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ BROWSERBACK,
+]
+
+TESTS = {
+ "auth_grant_fhir_calls": [
+ {"sequence": SEQ_AUTHORIZE_START},
+ CALL_LOGIN,
+ CLICK_AGREE_ACCESS,
+ {"sequence": SEQ_QUERY_FHIR_RESOURCES}
+ ],
+ "auth_deny_fhir_calls": [
+ {"sequence": SEQ_AUTHORIZE_START},
+ CALL_LOGIN,
+ CLICK_DENY_ACCESS,
+ CHECK_TESTCLIENT_START_PAGE
+ ],
+ "auth_grant_w_no_demo": [
+ {"sequence": SEQ_AUTHORIZE_START},
+ CALL_LOGIN,
+ CLICK_RADIO_NOT_SHARE,
+ CLICK_AGREE_ACCESS,
+ {"sequence": SEQ_QUERY_FHIR_RESOURCES_NO_DEMO}
+ ]
+}
+
+
+class SeleniumTests(TestCase):
+ '''
+ Test authorization and fhir flow through the built in testclient by
+ leveraging selenium web driver (chrome is used)
+ '''
+ wait_completed = False
+
+ def setUp(self):
+ super(SeleniumTests, self).setUp()
+ # a bit waiting for selenium service ready for sure
+ if not SeleniumTests.wait_completed:
+ time.sleep(20)
+ SeleniumTests.wait_completed = True
+ print("set wait_completed={}".format(SeleniumTests.wait_completed))
+ else:
+ print("wait_completed={}".format(SeleniumTests.wait_completed))
+
+ opt = webdriver.ChromeOptions()
+ # opt.add_argument('--headless')
+ opt.add_argument("--disable-dev-shm-usage")
+ opt.add_argument("--disable-web-security")
+ opt.add_argument("--allow-running-insecure-content")
+ opt.add_argument("--no-sandbox")
+ opt.add_argument("--disable-setuid-sandbox")
+ opt.add_argument("--disable-webgl")
+ opt.add_argument("--disable-popup-blocking")
+ opt.add_argument("--enable-javascript")
+ opt.add_argument('--allow-insecure-localhost')
+ opt.add_argument('--window-size=1920,1080')
+ opt.add_argument("--whitelisted-ips=''")
+
+ self.driver = webdriver.Remote(
+ command_executor='http://selenium-hub:4444',
+ desired_capabilities=DesiredCapabilities.CHROME, options=opt)
+
+ self.actions = {
+ Action.LOAD_PAGE: self._load_page,
+ Action.FIND_CLICK: self._find_and_click,
+ Action.FIND: self._find_and_return,
+ Action.FIND_SEND_KEY: self._find_and_sendkey,
+ Action.CHECK: self._check_page_title,
+ Action.CONTAIN_TEXT: self._check_page_content,
+ Action.GET_SAMPLE_TOKEN_START: self._click_get_sample_token,
+ Action.BACK: self._back,
+ Action.LOGIN: self._login,
+ Action.SLEEP: self._sleep,
+ }
+ self.use_mslsx = os.environ['USE_MSLSX']
+ self.login_seq = SEQ_LOGIN_MSLSX if self.use_mslsx == 'true' else SEQ_LOGIN_SLSX
+
+ def tearDown(self):
+ self.driver.quit()
+ super(SeleniumTests, self).tearDown()
+
+ def _find_and_click(self, timeout_sec, by, by_expr, **kwargs):
+ elem = WebDriverWait(self.driver, timeout_sec).until(EC.visibility_of_element_located((by, by_expr)))
+ self.assertIsNotNone(elem)
+ elem.click()
+ return elem
+
+ def _testclient_home(self, **kwargs):
+ return self._find_and_click(30, By.LINK_TEXT, LNK_TXT_RESTART_TESTCLIENT, **kwargs)
+
+ def _find_and_sendkey(self, timeout_sec, by, by_expr, txt, **kwargs):
+ elem = WebDriverWait(self.driver, timeout_sec).until(EC.visibility_of_element_located((by, by_expr)))
+ self.assertIsNotNone(elem)
+ elem.send_keys(txt)
+ return elem
+
+ def _click_get_sample_token(self, **kwargs):
+ return self._find_and_click(30, By.LINK_TEXT,
+ LNK_TXT_GET_TOKEN_V2 if kwargs.get("api_ver", API_V1) == API_V2 else LNK_TXT_GET_TOKEN_V1)
+
+ def _find_and_return(self, timeout_sec, by, by_expr, **kwargs):
+ elem = WebDriverWait(self.driver, timeout_sec).until(EC.visibility_of_element_located((by, by_expr)))
+ self.assertIsNotNone(elem)
+ return elem
+
+ def _load_page(self, url, **kwargs):
+ self.driver.get(url)
+
+ def _check_page_title(self, timeout_sec, by, by_expr, fmt, resource_type, **kwargs):
+ elem = self._find_and_return(timeout_sec, by, by_expr, **kwargs)
+ if not (elem.text == fmt.format(resource_type, kwargs.get("api_ver"))):
+ print("PAGE:{}".format(self.driver.page_source))
+ self.assertEqual(elem.text, fmt.format(resource_type, kwargs.get("api_ver")))
+
+ def _check_page_content(self, timeout_sec, by, by_expr, content_txt, **kwargs):
+ elem = self._find_and_return(timeout_sec, by, by_expr, **kwargs)
+ self.assertIn(content_txt, elem.text)
+
+ def _back(self, **kwargs):
+ self.driver.back()
+
+ def _sleep(self, sec, **kwargs):
+ time.sleep(sec)
+
+ def _login(self, step, **kwargs):
+ if self.use_mslsx == 'false':
+ # dismiss mymedicare popup if present
+ webdriver.ActionChains(self.driver).send_keys(Keys.ESCAPE).perform()
+ self._play(self.login_seq, step, **kwargs)
+
+ def _print_testcase_banner(self, test_name, api_ver, step_0, id_service, start=True):
+ print()
+ print("******************************************************************")
+ print(TESTCASE_BANNER_FMT.format("START" if start else "END", test_name, api_ver, step_0,
+ "MSLSX" if id_service == 'true' else "SLSX"))
+ print("******************************************************************")
+ print()
+
+ def _play(self, lst, step, **kwargs):
+ for s in lst:
+ seq = s.get("sequence")
+ # expects sequence of actions or action
+ if seq is not None:
+ self._play(seq, step, **kwargs)
+ else:
+ # single action
+ action = s.get('action', None)
+ step[0] = step[0] + 1
+ if action is not None:
+ print("{}:{}:".format(step[0], s.get("display", "Not available")))
+ if action == Action.LOGIN:
+ self.actions[action](*s.get("params", []), step, **kwargs)
+ else:
+ self.actions[action](*s.get("params", []), **kwargs)
+ else:
+ raise ValueError("Invalid test case, expect dict with action...")
+
+ def test_auth_grant_fhir_calls_v1(self):
+ step = [0]
+ test_name = "auth_grant_fhir_calls"
+ api_ver = API_V1
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, True)
+ self._play(TESTS[test_name], step, api_ver=api_ver)
+ self._testclient_home()
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, False)
+
+ def test_auth_grant_fhir_calls_v2(self):
+ step = [0]
+ test_name = "auth_grant_fhir_calls"
+ api_ver = API_V2
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, True)
+ self._play(TESTS[test_name], step, api_ver=api_ver)
+ self._testclient_home()
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, False)
+
+ def test_auth_deny_fhir_calls_v1(self):
+ step = [0]
+ test_name = "auth_deny_fhir_calls"
+ api_ver = API_V1
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, True)
+ self._play(TESTS[test_name], step, api_ver=api_ver)
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, False)
+
+ def test_auth_deny_fhir_calls_v2(self):
+ step = [0]
+ test_name = "auth_deny_fhir_calls"
+ api_ver = API_V2
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, True)
+ self._play(TESTS[test_name], step, api_ver=api_ver)
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, False)
+
+ def test_auth_grant_w_no_demo_v1(self):
+ step = [0]
+ test_name = "auth_grant_w_no_demo"
+ api_ver = API_V1
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, True)
+ self._play(TESTS[test_name], step, api_ver=api_ver)
+ self._testclient_home()
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, False)
+
+ def test_auth_grant_w_no_demo_v2(self):
+ step = [0]
+ test_name = "auth_grant_w_no_demo"
+ api_ver = API_V2
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, True)
+ self._play(TESTS[test_name], step, api_ver=api_ver)
+ self._testclient_home()
+ self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, False)
diff --git a/docker-compose.selenium.yml b/docker-compose.selenium.yml
new file mode 100755
index 000000000..e66c670a2
--- /dev/null
+++ b/docker-compose.selenium.yml
@@ -0,0 +1,162 @@
+version: '3'
+
+services:
+ tests:
+ build:
+ context: ./
+ dockerfile: SeleniumDockerfile
+ command: python runtests.py apps.integration_tests.selenium_tests.SeleniumTests
+ environment:
+ - HOSTNAME_URL=${HOSTNAME_URL}
+ - USE_MSLSX=${USE_MSLSX}
+ volumes:
+ - .:/code
+ depends_on:
+ - bb2
+ - chrome
+
+ tests_w_slsx:
+ build:
+ context: ./
+ dockerfile: SeleniumDockerfile
+ command: python runtests.py apps.integration_tests.selenium_tests.SeleniumTests
+ environment:
+ - HOSTNAME_URL=${HOSTNAME_URL}
+ - USE_MSLSX=${USE_MSLSX}
+ volumes:
+ - .:/code
+ depends_on:
+ - bb2slsx
+ - chrome
+
+ chrome:
+ image: selenium/node-chrome:4.0.0-beta-4-prerelease-20210517
+ volumes:
+ - /dev/shm:/dev/shm
+ depends_on:
+ - selenium-hub
+ environment:
+ - SE_EVENT_BUS_HOST=selenium-hub
+ - SE_EVENT_BUS_PUBLISH_PORT=4442
+ - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
+ ports:
+ - "6900:5900"
+
+ # edge:
+ # image: selenium/node-edge:4.0.0-beta-4-prerelease-20210517
+ # volumes:
+ # - /dev/shm:/dev/shm
+ # depends_on:
+ # - selenium-hub
+ # environment:
+ # - SE_EVENT_BUS_HOST=selenium-hub
+ # - SE_EVENT_BUS_PUBLISH_PORT=4442
+ # - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
+ # ports:
+ # - "6901:5900"
+
+ # firefox:
+ # image: selenium/node-firefox:4.0.0-beta-4-prerelease-20210517
+ # volumes:
+ # - /dev/shm:/dev/shm
+ # depends_on:
+ # - selenium-hub
+ # environment:
+ # - SE_EVENT_BUS_HOST=selenium-hub
+ # - SE_EVENT_BUS_PUBLISH_PORT=4442
+ # - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
+ # ports:
+ # - "6902:5900"
+
+ selenium-hub:
+ image: selenium/hub:4.0.0-beta-4-prerelease-20210517
+ container_name: selenium-hub
+ ports:
+ - "4442:4442"
+ - "4443:4443"
+ - "4444:4444"
+
+ msls:
+ build:
+ context: ./dev-local/msls
+ dockerfile: Dockerfile
+ command: msls
+ ports:
+ - "8080:8080"
+
+ db:
+ image: postgres
+ environment:
+ - POSTGRES_DB=bluebutton
+ - POSTGRES_PASSWORD=toor
+ ports:
+ - "5432:5432"
+
+ bb2:
+ build: .
+ command: ./docker-compose/bluebutton_server_start.sh '${DB_MIGRATIONS}' '${SUPER_USER_NAME}' '${SUPER_USER_EMAIL}' '${SUPER_USER_PASSWORD}' '${BB20_ENABLE_REMOTE_DEBUG}' '${BB20_REMOTE_DEBUG_WAIT_ATTACH}'
+ environment:
+ - DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE}
+ - DATABASES_CUSTOM=postgres://postgres:toor@db:5432/bluebutton
+ - OAUTHLIB_INSECURE_TRANSPORT=true
+ - DJANGO_DEFAULT_SAMPLE_FHIR_ID="-20140000008325"
+ - DJANGO_SECURE_SESSION=False
+ - FHIR_URL="https://prod-sbx.bfd.cms.gov"
+ - DJANGO_FHIR_CERTSTORE=/code/docker-compose/certstore/
+ - DJANGO_MEDICARE_SLSX_REDIRECT_URI=http://bb2:8000/mymedicare/sls-callback
+ - DJANGO_MEDICARE_SLSX_LOGIN_URI=http://msls:8080/sso/authorize?client_id=bb2api
+ - DJANGO_SLSX_HEALTH_CHECK_ENDPOINT=http://msls:8080/health
+ - DJANGO_SLSX_TOKEN_ENDPOINT=http://msls:8080/sso/session
+ - DJANGO_SLSX_SIGNOUT_ENDPOINT=http://msls:8080/sso/signout
+ - DJANGO_SLSX_USERINFO_ENDPOINT=http://msls:8080/v1/users
+ - DJANGO_SLSX_CLIENT_ID=bb2api
+ - DJANGO_SLSX_CLIENT_SECRET=${DJANGO_SLSX_CLIENT_SECRET}
+ - HOSTNAME_URL=${HOSTNAME_URL}
+ - DJANGO_SLSX_VERIFY_SSL_INTERNAL=False
+ - DJANGO_SLSX_VERIFY_SSL_EXTERNAL=True
+ - DJANGO_LOG_JSON_FORMAT_PRETTY=${DJANGO_LOG_JSON_FORMAT_PRETTY}
+ - DJANGO_USER_ID_ITERATIONS=${DJANGO_USER_ID_ITERATIONS}
+ - DJANGO_USER_ID_SALT=${DJANGO_USER_ID_SALT}
+ volumes:
+ - .:/code
+ ports:
+ - "8000:8000"
+ - "5678:5678"
+ depends_on:
+ - db
+ - msls
+
+ bb2slsx:
+ build: .
+ command: ./docker-compose/bluebutton_server_start.sh '${DB_MIGRATIONS}' '${SUPER_USER_NAME}' '${SUPER_USER_EMAIL}' '${SUPER_USER_PASSWORD}' '${BB20_ENABLE_REMOTE_DEBUG}' '${BB20_REMOTE_DEBUG_WAIT_ATTACH}'
+ environment:
+ - DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.dev
+ - DATABASES_CUSTOM=postgres://postgres:toor@db:5432/bluebutton
+ - OAUTHLIB_INSECURE_TRANSPORT=true
+ - DJANGO_DEFAULT_SAMPLE_FHIR_ID="-20140000008325"
+ - DJANGO_SECURE_SESSION=False
+ - FHIR_URL="https://prod-sbx.bfd.cms.gov"
+ - DJANGO_FHIR_CERTSTORE=/code/docker-compose/certstore/
+ - DJANGO_SLSX_CLIENT_ID=bb2api
+ - DJANGO_SLSX_CLIENT_SECRET=${DJANGO_SLSX_CLIENT_SECRET}
+ - HOSTNAME_URL=${HOSTNAME_URL}
+ - DJANGO_MEDICARE_SLSX_REDIRECT_URI=http://bb2slsx:8000/mymedicare/sls-callback
+ - DJANGO_MEDICARE_SLSX_LOGIN_URI=https://test.medicare.gov/sso/authorize?client_id=bb2api
+ - DJANGO_SLSX_HEALTH_CHECK_ENDPOINT=https://test.accounts.cms.gov/health
+ - DJANGO_SLSX_TOKEN_ENDPOINT=https://test.medicare.gov/sso/session
+ - DJANGO_SLSX_SIGNOUT_ENDPOINT=https://test.medicare.gov/sso/signout
+ - DJANGO_SLSX_USERINFO_ENDPOINT=https://test.accounts.cms.gov/v1/users
+ # SSL verify for internal endpoints can't currently use SSL verification (this may change in the future)
+ - DJANGO_SLSX_VERIFY_SSL_INTERNAL=False
+ - DJANGO_SLSX_VERIFY_SSL_EXTERNAL=True
+ - DJANGO_LOG_JSON_FORMAT_PRETTY=True
+ - DJANGO_USER_ID_ITERATIONS=${DJANGO_USER_ID_ITERATIONS}
+ - DJANGO_USER_ID_SALT=${DJANGO_USER_ID_SALT}
+ volumes:
+ - .:/code
+ ports:
+ - "8000:8000"
+ - "5678:5678"
+ depends_on:
+ - db
+
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 962614615..5d1d7f318 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -28,7 +28,7 @@ services:
- DJANGO_FHIR_CERTSTORE=/code/docker-compose/certstore/
# Commented out settings for MSLS:
# - DJANGO_MEDICARE_SLSX_REDIRECT_URI=http://localhost:8000/mymedicare/sls-callback
- # - DJANGO_MEDICARE_SLSX_LOGIN_URI=http://127.0.0.1:8080/sso/authorize?client_id=bb2api
+ # - DJANGO_MEDICARE_SLSX_LOGIN_URI=http://localhost:8080/sso/authorize?client_id=bb2api
# - DJANGO_SLSX_HEALTH_CHECK_ENDPOINT=http://msls:8080/health
# - DJANGO_SLSX_TOKEN_ENDPOINT=http://msls:8080/sso/session
# - DJANGO_SLSX_SIGNOUT_ENDPOINT=http://msls:8080/sso/signout
diff --git a/docker-compose/bluebutton_server_start.sh b/docker-compose/bluebutton_server_start.sh
index 684331d32..4b005c28e 100755
--- a/docker-compose/bluebutton_server_start.sh
+++ b/docker-compose/bluebutton_server_start.sh
@@ -13,30 +13,26 @@ echo "SUPER_USER_EMAIL =" ${SUPER_USER_EMAIL}
echo "SUPER_USER_PASSWORD =" ${SUPER_USER_PASSWORD}
echo "BB20_ENABLE_REMOTE_DEBUG =" ${BB20_ENABLE_REMOTE_DEBUG}
echo "BB20_REMOTE_DEBUG_WAIT_ATTACH =" ${BB20_REMOTE_DEBUG_WAIT_ATTACH}
+echo "DJANGO_USER_ID_ITERATIONS=" ${DJANGO_USER_ID_ITERATIONS}
+echo "DJANGO_USER_ID_SALT=" ${DJANGO_USER_ID_SALT}
+echo "DJANGO_SETTINGS_MODULE=" ${DJANGO_SETTINGS_MODULE}
-if [ -f ./migration.completed ]
- echo "DB image migrations seems performed in container, skip..."
+if [ "${DB_MIGRATIONS}" = true ]
then
- if [ "${DB_MIGRATIONS}" = true ]
- then
- echo "DB_MIGRATIONS is true, run db image migration and models initialization."
- python manage.py migrate
+ echo "run db image migration and models initialization."
+ python manage.py migrate
- echo "from django.contrib.auth.models import User; User.objects.create_superuser('${SUPER_USER_NAME}', '${SUPER_USER_EMAIL}', '${SUPER_USER_PASSWORD}')" | python manage.py shell
- python manage.py create_admin_groups
- python manage.py loaddata scopes.json
- python manage.py create_blue_button_scopes
- python manage.py create_test_user_and_application
- python manage.py create_user_identification_label_selection
- python manage.py create_test_feature_switches
- else
- echo "DB_MIGRATIONS is false, no db image migration and models initialization will run here, you might need to manually run DB image migrations ..."
- fi
- # this is to prevent restart doing migration again
- touch migration.completed
+ echo "from django.contrib.auth.models import User; User.objects.create_superuser('${SUPERUSER_NAME}', '${SUPERUSER_EMAIL}', '${SUPERUSER_PASSWORD}')" | python manage.py shell
+ python manage.py create_admin_groups
+ python manage.py loaddata scopes.json
+ python manage.py create_blue_button_scopes
+ python manage.py create_test_user_and_application
+ python manage.py create_user_identification_label_selection
+ python manage.py create_test_feature_switches
+else
+ echo "restarting blue button server, no db image migration and models initialization will run here, you might need to manually run DB image migrations."
fi
-
if [ ! -d 'bluebutton-css' ]
then
git clone https://github.com/CMSgov/bluebutton-css.git
diff --git a/docker-compose/readme.md b/docker-compose/readme.md
index 62ac6529f..5d31a0294 100644
--- a/docker-compose/readme.md
+++ b/docker-compose/readme.md
@@ -279,5 +279,25 @@ NOTES:
* For the CBC related setup see these files for more details:
* `Jenkinsfiles/Jenkinsfile.cbc-run-integration-tests` - Jenkinsfile for running the tests in a CBC project/job.
* `Jenkinsfiles/cbc-run-integration-tests.yaml` - Kubernetes docker container specification. These settings will also need to be updated when there are CBC image naming changes.
-
+## Developing and Running Selenium tests in Local Development
+You can run selenium tests by following below steps:
+
+ 1. Make sure there is no blue button server and its dependent services running
+ 2. Go to the base directory of the local repo and run:
+
+ use MSLSX (default)
+ ```
+ ./docker-compose/run_selenium_tests_local_keybase.sh
+ ```
+
+ ```
+ ./docker-compose/run_selenium_tests_local_keybase.sh mslsx
+ ```
+
+ use SLSX
+ ```
+ ./docker-compose/run_selenium_tests_local_keybase.sh slsx
+ ```
+
+ 3. To trouble shoot tests: point VNC client to localhost:6900
\ No newline at end of file
diff --git a/docker-compose/run_integration_tests_local_keybase.sh b/docker-compose/run_integration_tests_local_keybase.sh
index a262645b8..1e1882e41 100755
--- a/docker-compose/run_integration_tests_local_keybase.sh
+++ b/docker-compose/run_integration_tests_local_keybase.sh
@@ -160,6 +160,7 @@ else
# Source ENVs
source "${keybase_env}"
+
# Check ENV vars have been sourced
if [ -z "${DJANGO_USER_ID_SALT}" ]
then
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
new file mode 100755
index 000000000..4c18c2251
--- /dev/null
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -0,0 +1,220 @@
+#!/bin/bash
+
+# Run the selenium tests in docker
+#
+# NOTE:
+#
+# 1. You must be logged in to Keybase and have the BB2 team file system mounted.
+#
+# 2. You must also be connected to the VPN.
+#
+# SETTINGS: You may need to customize these for your local setup.
+
+KEYBASE_ENV_FILE="team/bb20/infrastructure/creds/ENV_secrets_for_local_integration_tests.env"
+KEYBASE_CERTFILES_SUBPATH="team/bb20/infrastructure/certs/local_integration_tests/fhir_client/certstore/"
+
+DJANGO_FHIR_CERTSTORE="/certstore"
+CERTSTORE_TEMPORARY_MOUNT_PATH="/tmp/certstore"
+CERT_FILENAME="client_data_server_bluebutton_local_integration_tests_certificate.pem"
+KEY_FILENAME="client_data_server_bluebutton_local_integration_tests_private_key.pem"
+
+# BB2 service end point default
+HOSTNAME_URL="http://bb2:8000"
+
+# Backend FHIR server to use for selenium tests with FHIR requests:
+FHIR_URL="https://prod-sbx.bfd.cms.gov"
+
+# List of tests to run. To be passed in to runtests.py.
+TESTS_LIST="apps.integration_tests.selenium_tests.SeleniumTests"
+
+
+# Echo function that includes script name on each line for console log readability
+echo_msg () {
+ echo "$(basename $0): $*"
+}
+
+# main
+echo_msg
+echo_msg RUNNING SCRIPT: ${0}
+echo_msg
+
+# Set bash builtins for safety
+set -e -u -o pipefail
+
+USE_MSLSX=true
+DOCKER_COMPOSE_SERVICE="tests"
+
+TEST_TYPE="--selenium"
+export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.dev"
+
+# Parse command line option
+if [ $# -eq 0 ]
+then
+ echo "Use MSLSX for identity service."
+else
+ if [[ $1 != "slsx" && $1 != "mslsx" && $1 != "loggingit" ]]
+ then
+ echo
+ echo "COMMAND USAGE HELP"
+ echo "------------------"
+ echo
+ echo " Use one of the following command line options for the type of test to run:"
+ echo
+ echo " loggingit = run integration tests for bb2 loggings, MSLSX used as identity service."
+ echo
+ echo " slsx = use SLSX for identity service."
+ echo
+ echo " mslsx (default) = use MSLSX for identity service."
+ echo
+ exit 1
+ else
+ if [ $1 == "slsx" ]
+ then
+ USE_MSLSX=false
+ DOCKER_COMPOSE_SERVICE="tests_w_slsx"
+ HOSTNAME_URL="http://bb2slsx:8000"
+ fi
+ if [ $1 == "loggingit" ]
+ then
+ TEST_TYPE="--loggingit"
+ TESTS_LIST="apps.integration_tests.logging_tests.LoggingTests"
+ export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.test_logging"
+ export DJANGO_LOG_JSON_FORMAT_PRETTY=False
+ mkdir -p docker-compose/tmp
+ if [ -f docker-compose/tmp/bb2_logging_test.log ]
+ then
+ rm -f docker-compose/tmp/bb2_logging_test.log
+ fi
+ fi
+ fi
+fi
+
+echo "DJANGO_SETTINGS_MODULE: " ${DJANGO_SETTINGS_MODULE}
+echo "DOCKER_COMPOSE_SERVICE: " ${DOCKER_COMPOSE_SERVICE}
+echo "HOSTNAME_URL: " ${HOSTNAME_URL}
+echo "TEST_TYPE: " ${TEST_TYPE}
+echo "TESTS: " ${TESTS_LIST}
+
+# Set KeyBase ENV path based on your type of system
+SYSTEM=$(uname -s)
+
+echo_msg " - Setting Keybase location based on SYSTEM type: ${SYSTEM}"
+echo_msg
+
+if [[ ${SYSTEM} == "Linux" ]]
+then
+ keybase_env_path="/keybase"
+elif [[ ${SYSTEM} == "Darwin" ]]
+then
+ keybase_env_path="/Volumes/keybase"
+else
+ # support cygwin
+ keybase_env_path="/cygdrive/k"
+ CERTSTORE_TEMPORARY_MOUNT_PATH="./docker-compose/certstore"
+ DJANGO_FHIR_CERTSTORE="/code/docker-compose/certstore"
+fi
+
+# Keybase ENV file
+keybase_env="${keybase_env_path}/${KEYBASE_ENV_FILE}"
+
+echo_msg " - Sourcing ENV secrets from: ${keybase_env}"
+echo_msg
+
+# Check that ENV file exists in correct location
+if [ ! -f "${keybase_env}" ]
+then
+ echo_msg
+ echo_msg "ERROR: The ENV secrets could NOT be found at: ${keybase_env}"
+ echo_msg
+ exit 1
+fi
+
+# Source ENVs
+source "${keybase_env}"
+
+# Check ENV vars have been sourced
+if [ -z "${DJANGO_USER_ID_SALT}" ]
+then
+ echo_msg "ERROR: The DJANGO_USER_ID_SALT variable was not sourced!"
+ exit 1
+fi
+if [ -z "${DJANGO_USER_ID_ITERATIONS}" ]
+then
+ echo_msg "ERROR: The DJANGO_USER_ID_ITERATIONS variable was not sourced!"
+ exit 1
+fi
+
+# Check temp certstore dir and create if not existing
+if [ -d "${CERTSTORE_TEMPORARY_MOUNT_PATH}" ]
+then
+ echo_msg
+ echo_msg " - OK: The temporary certstore mount path is found at: ${CERTSTORE_TEMPORARY_MOUNT_PATH}"
+else
+ mkdir ${CERTSTORE_TEMPORARY_MOUNT_PATH}
+ echo_msg
+ echo_msg " - OK: Created the temporary certstore mount path at: ${CERTSTORE_TEMPORARY_MOUNT_PATH}"
+fi
+
+# Keybase cert files
+keybase_certfiles="${keybase_env_path}/${KEYBASE_CERTFILES_SUBPATH}"
+keybase_cert_file="${keybase_certfiles}/${CERT_FILENAME}"
+keybase_key_file="${keybase_certfiles}/${KEY_FILENAME}"
+
+# Check that certfiles in keybase dir exist
+if [ -f "${keybase_cert_file}" ]
+then
+ echo_msg
+ echo_msg " - OK: The cert file was found at: ${keybase_cert_file}"
+else
+ echo_msg
+ echo_msg "ERROR: The cert file could NOT be found at: ${keybase_cert_file}"
+ exit 1
+fi
+
+if [ -f ${keybase_key_file} ]
+then
+ echo_msg
+ echo_msg " - OK: The key file was found at: ${keybase_key_file}"
+else
+ echo_msg
+ echo_msg "ERROR: The key file could NOT be found at: ${keybase_key_file}"
+ exit 1
+fi
+
+# Copy certfiles from KeyBase to local for container mount
+echo_msg " - COPY certfiles from KeyBase to local temp for container mount..."
+echo_msg
+cp ${keybase_cert_file} "${CERTSTORE_TEMPORARY_MOUNT_PATH}/ca.cert.pem"
+cp ${keybase_key_file} "${CERTSTORE_TEMPORARY_MOUNT_PATH}/ca.key.nocrypt.pem"
+
+# stop all before run selenium tests
+docker-compose -f docker-compose.selenium.yml stop
+
+export DJANGO_PASSWORD_HASH_ITERATIONS=${DJANGO_PASSWORD_HASH_ITERATIONS}
+export DJANGO_USER_ID_SALT=${DJANGO_USER_ID_SALT}
+export DJANGO_USER_ID_ITERATIONS=${DJANGO_USER_ID_ITERATIONS}
+export DJANGO_SLSX_CLIENT_ID=${DJANGO_SLSX_CLIENT_ID}
+export DJANGO_SLSX_CLIENT_SECRET=${DJANGO_SLSX_CLIENT_SECRET}
+export HOSTNAME_URL=${HOSTNAME_URL}
+export USE_MSLSX=${USE_MSLSX}
+
+echo "Selenium tests ..."
+
+docker-compose -f docker-compose.selenium.yml run \
+${DOCKER_COMPOSE_SERVICE} bash -c "python runtests.py ${TEST_TYPE} ${TESTS_LIST}"
+
+# Remove certfiles from local directory
+echo_msg
+echo_msg Shred and Remove certfiles from CERTSTORE_TEMPORARY_MOUNT_PATH=${CERTSTORE_TEMPORARY_MOUNT_PATH}
+echo_msg
+
+if which shred
+then
+ echo_msg " - Shredding files"
+ shred "${CERTSTORE_TEMPORARY_MOUNT_PATH}/ca.cert.pem"
+ shred "${CERTSTORE_TEMPORARY_MOUNT_PATH}/ca.key.nocrypt.pem"
+fi
+
+echo_msg " - Removing files"
+rm "${CERTSTORE_TEMPORARY_MOUNT_PATH}/ca.cert.pem"
+rm "${CERTSTORE_TEMPORARY_MOUNT_PATH}/ca.key.nocrypt.pem"
diff --git a/hhs_oauth_server/settings/test_logging.py b/hhs_oauth_server/settings/test_logging.py
new file mode 100755
index 000000000..da344474a
--- /dev/null
+++ b/hhs_oauth_server/settings/test_logging.py
@@ -0,0 +1,70 @@
+from .test import *
+
+# Use env-specific logging config if present
+LOGGING = env("DJANGO_LOGGING", {
+ 'version': 1,
+ 'disable_existing_loggers': False,
+ 'formatters': {
+ 'verbose': {
+ 'format': '%(asctime)s %(levelname)s '
+ '[%(process)d] %(name)s line:%(lineno)d %(message)s'
+ },
+ 'simple': {
+ 'format': '%(asctime)s %(levelname)s %(name)s %(message)s'
+ },
+ 'jsonout': {
+ 'format': '{"env": "' + env('TARGET_ENV', 'DEV') + '", "time": "%(asctime)s", "level": "%(levelname)s", '
+ '"name": "%(name)s", "message": "%(message)s"}',
+ 'datefmt': '%Y-%m-%d %H:%M:%S'
+
+ }
+ },
+ 'handlers': {
+ 'console': {
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'verbose',
+ },
+ 'file': {
+ 'class': 'logging.FileHandler',
+ 'filename': '/code/docker-compose/tmp/bb2_logging_test.log',
+ },
+ },
+ 'loggers': {
+ 'hhs_server': {
+ 'handlers': ['console', 'file'],
+ 'level': 'INFO',
+ },
+ 'hhs_oauth_server.accounts': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+ 'oauth2_provider': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+ 'oauthlib': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+ 'unsuccessful_logins': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+ 'admin_interface': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ },
+ 'tests': {
+ 'handlers': ['console'],
+ 'level': 'DEBUG',
+ },
+ 'audit': {
+ 'handlers': ['console', 'file'],
+ 'level': 'INFO',
+ },
+ 'performance': {
+ 'handlers': ['console'],
+ 'level': 'INFO',
+ }
+ },
+})
diff --git a/runtests.py b/runtests.py
index 5222fc6f3..f08ee411e 100644
--- a/runtests.py
+++ b/runtests.py
@@ -12,10 +12,18 @@
Reference: https://docs.djangoproject.com/en/3.0/topics/testing/advanced/#defining-a-test-runner
Command line arguments:
+
--integration This optional flag indicates tests are to run in integration test mode.
Space separated list of Django tests to run.
+ --selenium This optional flag indicates tests are to run in selenium test mode.
+ Space separated list of Django tests to run.
+
+ --loggingit This optional flag indicates tests are to run in logging integration test mode.
+ Space separated list of Django tests to run.
+
For example:
+
$ docker-compose exec web python runtests.py apps.dot_ext.tests
For more specific use:
@@ -34,6 +42,8 @@
# Parse command line arguments
parser = argparse.ArgumentParser()
parser.add_argument('--integration', help='Integration tests mode', action='store_true')
+parser.add_argument('--selenium', help='Selenium tests mode', action='store_true')
+parser.add_argument('--loggingit', help='Logging tests mode (use selenium as driver)', action='store_true')
parser.add_argument('test', nargs='*')
args = parser.parse_args()
@@ -45,7 +55,8 @@
'DATABASES_CUSTOM', 'DJANGO_LOG_JSON_FORMAT_PRETTY']:
if env_var in os.environ:
del os.environ[env_var]
-else:
+elif not args.selenium and not args.loggingit:
+ # For tests using selenium, inherit SLSX config from context;
# Unset ENV variables for Django unit type tests so default values get set.
for env_var in ['FHIR_URL', 'DJANGO_MEDICARE_SLSX_LOGIN_URI', 'DJANGO_MEDICARE_SLSX_REDIRECT_URI',
'DJANGO_SLSX_USERINFO_ENDPOINT', 'DJANGO_SLSX_TOKEN_ENDPOINT',
@@ -56,7 +67,10 @@
del os.environ[env_var]
if __name__ == '__main__':
- os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.test'
+ if not args.loggingit:
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.test'
+ else:
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.test_logging'
django.setup()
TestRunner = get_runner(settings)
test_runner = TestRunner()
diff --git a/templates/design_system/authorize_v2.html b/templates/design_system/authorize_v2.html
index b61980a50..b6b6d9097 100644
--- a/templates/design_system/authorize_v2.html
+++ b/templates/design_system/authorize_v2.html
@@ -70,7 +70,7 @@ Understand how your data is being used
-
+
From e831bced19b9f1d4d267298a1b1a0799dff2709c Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Thu, 8 Jul 2021 11:30:50 -0700
Subject: [PATCH 02/39] adjust command line option name from --loggingit to
--logit, meaning log integration tests.
---
docker-compose/run_selenium_tests_local_keybase.sh | 8 ++++----
runtests.py | 8 ++++----
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
index 4c18c2251..3a5efbcbf 100755
--- a/docker-compose/run_selenium_tests_local_keybase.sh
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -52,7 +52,7 @@ if [ $# -eq 0 ]
then
echo "Use MSLSX for identity service."
else
- if [[ $1 != "slsx" && $1 != "mslsx" && $1 != "loggingit" ]]
+ if [[ $1 != "slsx" && $1 != "mslsx" && $1 != "logit" ]]
then
echo
echo "COMMAND USAGE HELP"
@@ -60,7 +60,7 @@ else
echo
echo " Use one of the following command line options for the type of test to run:"
echo
- echo " loggingit = run integration tests for bb2 loggings, MSLSX used as identity service."
+ echo " logit = run integration tests for bb2 loggings, MSLSX used as identity service."
echo
echo " slsx = use SLSX for identity service."
echo
@@ -74,9 +74,9 @@ else
DOCKER_COMPOSE_SERVICE="tests_w_slsx"
HOSTNAME_URL="http://bb2slsx:8000"
fi
- if [ $1 == "loggingit" ]
+ if [ $1 == "logit" ]
then
- TEST_TYPE="--loggingit"
+ TEST_TYPE="--logit"
TESTS_LIST="apps.integration_tests.logging_tests.LoggingTests"
export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.test_logging"
export DJANGO_LOG_JSON_FORMAT_PRETTY=False
diff --git a/runtests.py b/runtests.py
index f08ee411e..39e4a8122 100644
--- a/runtests.py
+++ b/runtests.py
@@ -19,7 +19,7 @@
--selenium This optional flag indicates tests are to run in selenium test mode.
Space separated list of Django tests to run.
- --loggingit This optional flag indicates tests are to run in logging integration test mode.
+ --logit This optional flag indicates tests are to run in logging integration test mode.
Space separated list of Django tests to run.
For example:
@@ -43,7 +43,7 @@
parser = argparse.ArgumentParser()
parser.add_argument('--integration', help='Integration tests mode', action='store_true')
parser.add_argument('--selenium', help='Selenium tests mode', action='store_true')
-parser.add_argument('--loggingit', help='Logging tests mode (use selenium as driver)', action='store_true')
+parser.add_argument('--logit', help='Logging tests mode (use selenium as driver)', action='store_true')
parser.add_argument('test', nargs='*')
args = parser.parse_args()
@@ -55,7 +55,7 @@
'DATABASES_CUSTOM', 'DJANGO_LOG_JSON_FORMAT_PRETTY']:
if env_var in os.environ:
del os.environ[env_var]
-elif not args.selenium and not args.loggingit:
+elif not args.selenium and not args.logit:
# For tests using selenium, inherit SLSX config from context;
# Unset ENV variables for Django unit type tests so default values get set.
for env_var in ['FHIR_URL', 'DJANGO_MEDICARE_SLSX_LOGIN_URI', 'DJANGO_MEDICARE_SLSX_REDIRECT_URI',
@@ -67,7 +67,7 @@
del os.environ[env_var]
if __name__ == '__main__':
- if not args.loggingit:
+ if not args.logit:
os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.test'
else:
os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.test_logging'
From e10a888a78cac76abc07c8abb79e74428e40110d Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Thu, 8 Jul 2021 16:30:54 -0700
Subject: [PATCH 03/39] no echo for sensitive info.
---
docker-compose/bluebutton_server_start.sh | 2 --
1 file changed, 2 deletions(-)
diff --git a/docker-compose/bluebutton_server_start.sh b/docker-compose/bluebutton_server_start.sh
index 4b005c28e..6196d8616 100755
--- a/docker-compose/bluebutton_server_start.sh
+++ b/docker-compose/bluebutton_server_start.sh
@@ -13,8 +13,6 @@ echo "SUPER_USER_EMAIL =" ${SUPER_USER_EMAIL}
echo "SUPER_USER_PASSWORD =" ${SUPER_USER_PASSWORD}
echo "BB20_ENABLE_REMOTE_DEBUG =" ${BB20_ENABLE_REMOTE_DEBUG}
echo "BB20_REMOTE_DEBUG_WAIT_ATTACH =" ${BB20_REMOTE_DEBUG_WAIT_ATTACH}
-echo "DJANGO_USER_ID_ITERATIONS=" ${DJANGO_USER_ID_ITERATIONS}
-echo "DJANGO_USER_ID_SALT=" ${DJANGO_USER_ID_SALT}
echo "DJANGO_SETTINGS_MODULE=" ${DJANGO_SETTINGS_MODULE}
if [ "${DB_MIGRATIONS}" = true ]
From 751987cf2e52e79ddb12d5d9f9d4b4cfe3fcca08 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Mon, 12 Jul 2021 11:53:45 -0700
Subject: [PATCH 04/39] code refactor.
---
apps/integration_tests/common_utils.py | 13 +
.../integration_test_fhir_resources.py | 49 +-
apps/integration_tests/logging_tests.py | 431 +-----------------
apps/integration_tests/selenium_cases.py | 359 +++++++++++++++
apps/integration_tests/selenium_tests.py | 369 +--------------
docker-compose/readme.md | 13 +-
.../run_selenium_tests_local_keybase.sh | 2 +-
7 files changed, 425 insertions(+), 811 deletions(-)
create mode 100755 apps/integration_tests/common_utils.py
create mode 100755 apps/integration_tests/selenium_cases.py
diff --git a/apps/integration_tests/common_utils.py b/apps/integration_tests/common_utils.py
new file mode 100755
index 000000000..d23cc8a44
--- /dev/null
+++ b/apps/integration_tests/common_utils.py
@@ -0,0 +1,13 @@
+import jsonschema
+
+from jsonschema import validate
+
+
+def validate_json_schema(schema, content):
+ try:
+ validate(instance=content, schema=schema)
+ except jsonschema.exceptions.ValidationError as e:
+ # Show error info for debugging
+ print("jsonschema.exceptions.ValidationError: ", e)
+ return False
+ return True
diff --git a/apps/integration_tests/integration_test_fhir_resources.py b/apps/integration_tests/integration_test_fhir_resources.py
index d87f0d122..733d320d2 100644
--- a/apps/integration_tests/integration_test_fhir_resources.py
+++ b/apps/integration_tests/integration_test_fhir_resources.py
@@ -1,15 +1,14 @@
import json
-import jsonschema
from django.conf import settings
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
-from jsonschema import validate
from oauth2_provider.models import AccessToken
from rest_framework.test import APIClient
from waffle.testutils import override_switch, override_flag
from apps.test import BaseApiTest
+from .common_utils import validate_json_schema
from .endpoint_schemas import (COVERAGE_READ_SCHEMA_V2,
EOB_READ_INPT_SCHEMA,
FHIR_META_SCHEMA,
@@ -89,15 +88,6 @@ def _setup_apiclient(self, client, fn=None, ln=None, fhir_id=None, hicn_hash=Non
# Setup Bearer token:
client.credentials(HTTP_AUTHORIZATION="Bearer " + at.token)
- def _validateJsonSchema(self, schema, content):
- try:
- validate(instance=content, schema=schema)
- except jsonschema.exceptions.ValidationError as e:
- # Show error info for debugging
- print("jsonschema.exceptions.ValidationError: ", e)
- return False
- return True
-
def _assertHasC4BBProfile(self, resource, c4bb_profile, v2=False):
meta_profile = None
try:
@@ -161,7 +151,7 @@ def _stats_resource_by_type(self, bundle_json, cur_stats_dict, schema=None):
if schema is not None:
eob_profile = rs['meta']['profile'][0]
self.assertIsNotNone(eob_profile)
- self.assertTrue(self._validateJsonSchema(schema, rs))
+ self.assertTrue(validate_json_schema(schema, rs))
is_matched = False
@@ -235,7 +225,7 @@ def _call_userinfo_endpoint(self, v2=False):
# Validate JSON Schema
content = json.loads(response.content)
# dump_content(json.dumps(content), "userinfo_{}.json".format('v2' if v2 else 'v1'))
- self.assertEqual(self._validateJsonSchema(USERINFO_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(USERINFO_SCHEMA, content), True)
@override_switch('require-scopes', active=True)
def test_fhir_meta_endpoint(self):
@@ -268,7 +258,7 @@ def _call_fhir_meta_endpoint(self, v2=False):
self.assertIsNotNone(fhir_ver)
self.assertEqual(fhir_ver, '4.0.0' if v2 else '3.0.2')
# dump_content(json.dumps(content), "fhir_meta_{}.json".format('v2' if v2 else 'v1'))
- self.assertEqual(self._validateJsonSchema(FHIR_META_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(FHIR_META_SCHEMA, content), True)
@override_switch('require-scopes', active=True)
def test_patient_endpoint(self):
@@ -300,7 +290,7 @@ def _call_patient_endpoint(self, v2=False):
content = json.loads(response.content)
# dump_content(json.dumps(content), "patient_search_{}.json".format('v2' if v2 else 'v1'))
# Validate JSON Schema
- self.assertEqual(self._validateJsonSchema(PATIENT_SEARCH_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(PATIENT_SEARCH_SCHEMA, content), True)
for r in content['entry']:
resource = r['resource']
@@ -317,7 +307,7 @@ def _call_patient_endpoint(self, v2=False):
# now v2 returns patient without identifier - think it's a bug, by-pass v2 assert to BB2 IT temporarily
# until BFD resolve this.
if not v2:
- self.assertEqual(self._validateJsonSchema(PATIENT_READ_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(PATIENT_READ_SCHEMA, content), True)
self._assertHasC4BBProfile(content, C4BB_PROFILE_URLS['PATIENT'], v2)
# Assert there is no address lines and city in patient.address (BFD-379)
@@ -357,7 +347,7 @@ def _call_coverage_endpoint(self, v2=False):
content = json.loads(response.content)
# dump_content(json.dumps(content), "coverage_search_{}.json".format('v2' if v2 else 'v1'))
# Validate JSON Schema
- self.assertEqual(self._validateJsonSchema(COVERAGE_SEARCH_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(COVERAGE_SEARCH_SCHEMA, content), True)
# 3. Test READ VIEW endpoint
response = client.get(self._get_fhir_url(FHIR_RES_TYPE_COVERAGE, "part-a-" + settings.DEFAULT_SAMPLE_FHIR_ID, v2))
@@ -366,7 +356,7 @@ def _call_coverage_endpoint(self, v2=False):
# dump_content(json.dumps(content), "coverage_read_{}.json".format('v2' if v2 else 'v1'))
# Validate JSON Schema
self._assertHasC4BBProfile(content, C4BB_PROFILE_URLS['COVERAGE'], v2)
- self.assertEqual(self._validateJsonSchema(COVERAGE_READ_SCHEMA_V2 if v2 else COVERAGE_READ_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(COVERAGE_READ_SCHEMA_V2 if v2 else COVERAGE_READ_SCHEMA, content), True)
# 4. Test unauthorized READ request
response = client.get(self._get_fhir_url(FHIR_RES_TYPE_COVERAGE, "part-a-99999999999999", v2))
@@ -401,7 +391,7 @@ def _call_coverage_search_endpoint(self, v2=False):
# dump_content(json.dumps(content), "coverage_search_nav_p{}_{}.json".format(0, 'v2' if v2 else 'v1'))
# Validate JSON Schema: bundle with entries and link section with page navigation: first, next, previous, last, self
- self.assertEqual(self._validateJsonSchema(COVERAGE_SEARCH_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(COVERAGE_SEARCH_SCHEMA, content), True)
total = content['total']
count = 10
@@ -472,7 +462,7 @@ def _call_eob_search_endpoint(self, v2=False):
# dump_content(json.dumps(content), "eob_search_nav_p{}_{}.json".format(0, 'v2' if v2 else 'v1'))
# Validate JSON Schema: bundle with entries and link section with page navigation: first, next, previous, last, self
- self.assertEqual(self._validateJsonSchema(EOB_SEARCH_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(EOB_SEARCH_SCHEMA, content), True)
total = content['total']
count = 10
@@ -483,9 +473,8 @@ def _call_eob_search_endpoint(self, v2=False):
for i in range(page_total):
lnk = content.get('link', None)
- self.assertIsNotNone(lnk,
- ("Field 'link' expected, "
- "containing page navigation urls e.g. 'first', 'next', 'self', 'previous', 'last' "))
+ self.assertIsNotNone(lnk, ("Field 'link' expected, "
+ "containing page navigation urls e.g. 'first', 'next', 'self', 'previous', 'last' "))
nav_info = self._extract_urls(lnk)
if nav_info.get('next', None) is not None:
response = client.get(nav_info['next'])
@@ -524,7 +513,7 @@ def test_eob_profiles_endpoint(self):
# Validate JSON Schema: bundle with entries and link section with page navigation: first, next, previous, last, self
# comment out since the C4BB EOB resources do not validate with FHIR R4 json schema
- self.assertEqual(self._validateJsonSchema(EOB_SEARCH_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(EOB_SEARCH_SCHEMA, content), True)
total = content['total']
count = 10
@@ -587,7 +576,7 @@ def _call_eob_endpoint(self, v2=False):
response = client.get(self._get_fhir_url(FHIR_RES_TYPE_EOB, None, v2))
self.assertEqual(response.status_code, 200)
content = json.loads(response.content)
- self.assertEqual(self._validateJsonSchema(EOB_SEARCH_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(EOB_SEARCH_SCHEMA, content), True)
# dump_content(json.dumps(content), "eob_search_{}.json".format('v2' if v2 else 'v1'))
# Validate JSON Schema
for r in content['entry']:
@@ -602,7 +591,7 @@ def _call_eob_endpoint(self, v2=False):
self.assertEqual(response.status_code, 200)
if not v2:
# Validate JSON Schema
- self.assertEqual(self._validateJsonSchema(EOB_READ_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(EOB_READ_SCHEMA, content), True)
self._assertHasC4BBProfile(content, C4BB_PROFILE_URLS['NONCLINICIAN'], v2)
# 4. Test SEARCH VIEW endpoint v1 and v2 (BB2-418 EOB V2 PDE profile)
@@ -611,7 +600,7 @@ def _call_eob_endpoint(self, v2=False):
# Validate JSON Schema
content = json.loads(response.content)
# dump_content(json.dumps(content), "eob_search_pt_{}.json".format('v2' if v2 else 'v1'))
- self.assertEqual(self._validateJsonSchema(EOB_SEARCH_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(EOB_SEARCH_SCHEMA, content), True)
for r in content['entry']:
self._assertHasC4BBProfile(r['resource'], C4BB_PROFILE_URLS['NONCLINICIAN'], v2)
@@ -646,7 +635,7 @@ def _call_eob_endpoint_pde(self, v2=False):
self.assertEqual(response.status_code, 200)
if not v2:
# Validate JSON Schema for v1
- self.assertEqual(self._validateJsonSchema(EOB_READ_INPT_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(EOB_READ_INPT_SCHEMA, content), True)
self._assertHasC4BBProfile(content, C4BB_PROFILE_URLS['PHARMACY'], v2)
@override_switch('require-scopes', active=True)
@@ -669,7 +658,7 @@ def _call_eob_endpoint_inpatient(self, v2=False):
self.assertEqual(response.status_code, 200)
if not v2:
# Validate JSON Schema v1
- self.assertEqual(self._validateJsonSchema(EOB_READ_INPT_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(EOB_READ_INPT_SCHEMA, content), True)
self._assertHasC4BBProfile(content, C4BB_PROFILE_URLS['INPATIENT'], v2)
@override_switch('require-scopes', active=True)
@@ -692,7 +681,7 @@ def _call_eob_endpoint_outpatient(self, v2=False):
self.assertEqual(response.status_code, 200)
if not v2:
# Validate JSON Schema v1
- self.assertEqual(self._validateJsonSchema(EOB_READ_INPT_SCHEMA, content), True)
+ self.assertEqual(validate_json_schema(EOB_READ_INPT_SCHEMA, content), True)
else:
self.assertEqual(response.status_code, 200)
self._assertHasC4BBProfile(content, C4BB_PROFILE_URLS['OUTPATIENT'], v2)
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index cedcbcc79..65d662af7 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -1,22 +1,11 @@
import copy
import json
-import jsonschema
-import os
import re
-import time
-from django.conf import settings
-from django.test import TestCase
-from enum import Enum
from json.decoder import JSONDecodeError
-from jsonschema import validate
-from selenium import webdriver
-from selenium.webdriver.common.by import By
-from selenium.webdriver.support import expected_conditions as EC
-from selenium.webdriver.support.wait import WebDriverWait
-from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
-from selenium.webdriver.common.keys import Keys
+from apps.integration_tests.common_utils import validate_json_schema
+from apps.integration_tests.selenium_tests import SeleniumTests
from apps.integration_tests.log_event_schemas import (
LOG_MIDDLEWARE_FHIR_READ_EVENT_SCHEMA,
LOG_MIDDLEWARE_FHIR_SEARCH_EVENT_SCHEMA,
@@ -171,419 +160,12 @@
]
-TESTCLIENT_BUNDLE_LABEL_FMT = "Response (Bundle of {}), API version: {}"
-TESTCLIENT_RESOURCE_LABEL_FMT = "Response ({}), API version: {}"
-MESSAGE_NO_PERMISSION = "You do not have permission to perform this action."
-TESTCASE_BANNER_FMT = "** {} TEST: {}, API: {}, STEP: {}, {}"
-'''
-UI Widget text: texts on e.g. buttons, links, labels etc.
-'''
-LNK_TXT_TESTCLIENT = "Test Client"
-LNK_TXT_GET_TOKEN_V1 = "Get a Sample Authorization Token"
-LNK_TXT_GET_TOKEN_V2 = "Get a Sample Authorization Token for v2"
-LNK_TXT_AUTH_AS_BENE = "Authorize as a Beneficiary"
-LNK_TXT_RESTART_TESTCLIENT = "restart testclient"
-# FHIR search result bundle pagination
-LNK_TXT_NAV_FIRST = "first"
-LNK_TXT_NAV_NEXT = "next"
-LNK_TXT_NAV_PREV = "previous"
-LNK_TXT_NAV_LAST = "last"
-LNK_TXT_NAV_SELF = "self"
-# FHIR resources query page
-LNK_TXT_PATIENT = "Patient"
-LNK_TXT_EOB = "ExplanationOfBenefit"
-LNK_TXT_COVERAGE = "Coverage"
-LNK_TXT_PROFILE = "Profile"
-LNK_TXT_METADATA = "FHIR Metadata"
-LNK_TXT_OIDC_DISCOVERY = "OIDC Discovery"
-# FHIR result page label H2
-LAB_FHIR_RESULTPAGE_H2 = "h2"
-CONTENT_FHIR_RESULTPAGE_PRE = "pre"
-# MSLSX login form
-TXT_FLD_SUB_MSLSX = "username"
-TXT_FLD_HICN_MSLSX = "hicn"
-TXT_FLD_MBI_MSLSX = "mbi"
-TXT_FLD_VAL_SUB_MSLSX = "fred"
-MSLSX_TXT_FLD_HICN_VAL = "1000044680"
-MSLSX_TXT_FLD_MBI_VAL = "2SW4N00AA00"
-MSLSX_CSS_BUTTON = "button"
-# SLSX login form
-SLSX_TXT_FLD_USERNAME = "username-textbox"
-SLSX_TXT_FLD_PASSWORD = "password-textbox"
-SLSX_TXT_FLD_USERNAME_VAL = "BBUser00000"
-SLSX_TXT_FLD_PASSWORD_VAL = "PW00000!"
-SLSX_CSS_BUTTON = "login-button"
-# Demographic info access grant form
-BTN_ID_GRANT_DEMO_ACCESS = "approve"
-BTN_ID_DENY_DEMO_ACCESS = "deny"
-BTN_ID_RADIO_NOT_SHARE = "label:nth-child(5)"
-# API versions
-API_V2 = "v2"
-API_V1 = "v1"
-
-class Action(Enum):
- LOAD_PAGE = 1
- FIND_CLICK = 2
- FIND = 3
- FIND_SEND_KEY = 4
- CHECK = 5
- BACK = 6
- LOGIN = 7
- CONTAIN_TEXT = 8
- GET_SAMPLE_TOKEN_START = 9
- SLEEP = 10
-
-
-BROWSERBACK = {
- "display": "Back to FHIR resource page",
- "action": Action.BACK,
-}
-
-WAIT_SECONDS = {
- "display": "Sleep seconds...",
- "action": Action.SLEEP,
- "params": [3],
-}
-
-CHECK_TESTCLIENT_START_PAGE = {
- "display": "Check it's on 'Test Client' start page",
- "action": Action.FIND,
- "params": [30, By.LINK_TEXT, LNK_TXT_GET_TOKEN_V1]
-}
-
-CLICK_TESTCLIENT = {
- "display": "Click link 'Test Client'",
- "action": Action.FIND_CLICK,
- "params": [30, By.LINK_TEXT, LNK_TXT_TESTCLIENT]
-}
-
-CLICK_RADIO_NOT_SHARE = {
- "display": "Click 'Share healthcare data, but not your personal info' on DEMO info grant form",
- "action": Action.FIND_CLICK,
- "params": [20, By.CSS_SELECTOR, BTN_ID_RADIO_NOT_SHARE]
-}
-
-CLICK_AGREE_ACCESS = {
- "display": "Click 'Agree' on DEMO info grant form",
- "action": Action.FIND_CLICK,
- "params": [20, By.ID, BTN_ID_GRANT_DEMO_ACCESS]
-}
-
-CLICK_DENY_ACCESS = {
- "display": "Click 'Deny' on DEMO info grant form",
- "action": Action.FIND_CLICK,
- "params": [20, By.ID, BTN_ID_DENY_DEMO_ACCESS]
-}
-
-CALL_LOGIN = {
- "display": "Start login ...",
- "action": Action.LOGIN,
-}
-
-SEQ_LOGIN_MSLSX = [
- {
- "display": "Input SUB(username)",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.NAME, TXT_FLD_SUB_MSLSX, TXT_FLD_VAL_SUB_MSLSX]
- },
- {
- "display": "Input hicn",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.NAME, TXT_FLD_HICN_MSLSX, MSLSX_TXT_FLD_HICN_VAL]
- },
- {
- "display": "Input mbi",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.NAME, TXT_FLD_MBI_MSLSX, MSLSX_TXT_FLD_MBI_VAL]
- },
- {
- "display": "Click 'submit' on MSLSX login form",
- "action": Action.FIND_CLICK,
- "params": [20, By.CSS_SELECTOR, MSLSX_CSS_BUTTON]
- },
-]
-
-SEQ_LOGIN_SLSX = [
- {
- "display": "MyMedicare login username",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.ID, SLSX_TXT_FLD_USERNAME, SLSX_TXT_FLD_USERNAME_VAL]
- },
- {
- "display": "MyMedicare login password",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.ID, SLSX_TXT_FLD_PASSWORD, SLSX_TXT_FLD_PASSWORD_VAL]
- },
- {
- "display": "Click 'submit' on SLSX login form",
- "action": Action.FIND_CLICK,
- "params": [20, By.ID, SLSX_CSS_BUTTON]
- },
-]
-
-SEQ_AUTHORIZE_START = [
- {
- "display": "Load BB2 Landing Page ...",
- "action": Action.LOAD_PAGE,
- "params": [settings.HOSTNAME_URL]
- },
- CLICK_TESTCLIENT,
- {
- "display": "Click link to get sample token v1/v2",
- "action": Action.GET_SAMPLE_TOKEN_START,
- },
- {
- "display": "Click link 'Authorize as a Beneficiary' - start authorization",
- "action": Action.FIND_CLICK,
- "params": [30, By.LINK_TEXT, LNK_TXT_AUTH_AS_BENE]
- },
-]
-
-SEQ_QUERY_FHIR_RESOURCES = [
- {
- "display": "Click 'Patient' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_PATIENT]
- },
- {
- "display": "Check Patient result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_PATIENT]
- },
- BROWSERBACK,
- {
- "display": "Click 'Coverage' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_COVERAGE]
- },
- {
- "display": "Check Coverage result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_COVERAGE]
- },
- {
- "display": "Check and click Coverage result page navigation links 'last'",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
- },
- CLICK_TESTCLIENT,
- {
- "display": "Click 'ExplanationOfBenefit' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_EOB]
- },
- {
- "display": "Check ExplanationOfBenefit result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_EOB]
- },
- {
- "display": "Check and click ExplanationOfBenefit result page navigation links 'last'",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
- },
- WAIT_SECONDS,
- CLICK_TESTCLIENT,
- WAIT_SECONDS,
- {
- "display": "Click 'Profile' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_PROFILE]
- },
- WAIT_SECONDS,
- {
- "display": "Check Profile result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT,
- "{} (OIDC Userinfo)".format(LNK_TXT_PROFILE)]
- },
- BROWSERBACK,
- {
- "display": "Click 'FHIR Metadata' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_METADATA]
- },
- {
- "display": "Check FHIR Metadata result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_METADATA]
- },
- BROWSERBACK,
- {
- "display": "Click 'OIDC Discovery' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_OIDC_DISCOVERY]
- },
- {
- "display": "Check OIDC Discovery result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_OIDC_DISCOVERY]
- },
- BROWSERBACK,
-]
-
-TESTS = {
- "auth_fhir_flow_calls_logging": [
- {"sequence": SEQ_AUTHORIZE_START},
- CALL_LOGIN,
- CLICK_AGREE_ACCESS,
- {"sequence": SEQ_QUERY_FHIR_RESOURCES}
- ],
-}
-
-
-class LoggingTests(TestCase):
+class LoggingTests(SeleniumTests):
'''
Test loggings generated from authorization and fhir flow using the built in testclient as
the driver (selenium)
'''
- wait_completed = False
-
- def _validateJsonSchema(self, schema, content):
- # print("SCHEMA={}".format(schema))
- # print("CONTENT={}".format(content))
- try:
- validate(instance=content, schema=schema)
- except jsonschema.exceptions.ValidationError as e:
- # Show error info for debugging
- print("jsonschema.exceptions.ValidationError: ", e)
- return False
- return True
-
- def setUp(self):
- super(LoggingTests, self).setUp()
- # a bit waiting for selenium service ready for sure
- if not LoggingTests.wait_completed:
- time.sleep(20)
- LoggingTests.wait_completed = True
- print("set wait_completed={}".format(LoggingTests.wait_completed))
- else:
- print("wait_completed={}".format(LoggingTests.wait_completed))
-
- opt = webdriver.ChromeOptions()
- opt.add_argument('--headless')
- opt.add_argument("--disable-dev-shm-usage")
- opt.add_argument("--disable-web-security")
- opt.add_argument("--allow-running-insecure-content")
- opt.add_argument("--no-sandbox")
- opt.add_argument("--disable-setuid-sandbox")
- opt.add_argument("--disable-webgl")
- opt.add_argument("--disable-popup-blocking")
- opt.add_argument("--enable-javascript")
- opt.add_argument('--allow-insecure-localhost')
- opt.add_argument('--window-size=1920,1080')
- opt.add_argument("--whitelisted-ips=''")
-
- self.driver = webdriver.Remote(
- command_executor='http://selenium-hub:4444',
- desired_capabilities=DesiredCapabilities.CHROME, options=opt)
-
- self.actions = {
- Action.LOAD_PAGE: self._load_page,
- Action.FIND_CLICK: self._find_and_click,
- Action.FIND: self._find_and_return,
- Action.FIND_SEND_KEY: self._find_and_sendkey,
- Action.CHECK: self._check_page_title,
- Action.CONTAIN_TEXT: self._check_page_content,
- Action.GET_SAMPLE_TOKEN_START: self._click_get_sample_token,
- Action.BACK: self._back,
- Action.LOGIN: self._login,
- Action.SLEEP: self._sleep,
- }
- self.use_mslsx = os.environ['USE_MSLSX']
- self.login_seq = SEQ_LOGIN_MSLSX if self.use_mslsx == 'true' else SEQ_LOGIN_SLSX
-
- def tearDown(self):
- self.driver.quit()
- super(LoggingTests, self).tearDown()
-
- def _find_and_click(self, timeout_sec, by, by_expr, **kwargs):
- elem = WebDriverWait(self.driver, timeout_sec).until(EC.visibility_of_element_located((by, by_expr)))
- self.assertIsNotNone(elem)
- elem.click()
- return elem
-
- def _testclient_home(self, **kwargs):
- return self._find_and_click(30, By.LINK_TEXT, LNK_TXT_RESTART_TESTCLIENT, **kwargs)
-
- def _find_and_sendkey(self, timeout_sec, by, by_expr, txt, **kwargs):
- elem = WebDriverWait(self.driver, timeout_sec).until(EC.visibility_of_element_located((by, by_expr)))
- self.assertIsNotNone(elem)
- elem.send_keys(txt)
- return elem
-
- def _click_get_sample_token(self, **kwargs):
- return self._find_and_click(30, By.LINK_TEXT,
- LNK_TXT_GET_TOKEN_V2 if kwargs.get("api_ver", API_V1) == API_V2 else LNK_TXT_GET_TOKEN_V1)
-
- def _find_and_return(self, timeout_sec, by, by_expr, **kwargs):
- elem = WebDriverWait(self.driver, timeout_sec).until(EC.visibility_of_element_located((by, by_expr)))
- self.assertIsNotNone(elem)
- return elem
-
- def _load_page(self, url, **kwargs):
- self.driver.get(url)
-
- def _check_page_title(self, timeout_sec, by, by_expr, fmt, resource_type, **kwargs):
- elem = self._find_and_return(timeout_sec, by, by_expr, **kwargs)
- if not (elem.text == fmt.format(resource_type, kwargs.get("api_ver"))):
- print("PAGE:{}".format(self.driver.page_source))
- self.assertEqual(elem.text, fmt.format(resource_type, kwargs.get("api_ver")))
-
- def _check_page_content(self, timeout_sec, by, by_expr, content_txt, **kwargs):
- elem = self._find_and_return(timeout_sec, by, by_expr, **kwargs)
- self.assertIn(content_txt, elem.text)
-
- def _back(self, **kwargs):
- self.driver.back()
-
- def _sleep(self, sec, **kwargs):
- time.sleep(sec)
-
- def _login(self, step, **kwargs):
- if self.use_mslsx == 'false':
- # dismiss mymedicare popup if present
- webdriver.ActionChains(self.driver).send_keys(Keys.ESCAPE).perform()
- self._play(self.login_seq, step, **kwargs)
-
- def _print_testcase_banner(self, test_name, api_ver, step_0, id_service, start=True):
- print()
- print("******************************************************************")
- print(TESTCASE_BANNER_FMT.format("START" if start else "END", test_name, api_ver, step_0,
- "MSLSX" if id_service == 'true' else "SLSX"))
- print("******************************************************************")
- print()
-
- def _play(self, lst, step, **kwargs):
- for s in lst:
- seq = s.get("sequence")
- # expects sequence of actions or action
- if seq is not None:
- self._play(seq, step, **kwargs)
- else:
- # single action
- action = s.get('action', None)
- step[0] = step[0] + 1
- if action is not None:
- print("{}:{}:".format(step[0], s.get("display", "Not available")))
- if action == Action.LOGIN:
- self.actions[action](*s.get("params", []), step, **kwargs)
- else:
- self.actions[action](*s.get("params", []), **kwargs)
- else:
- raise ValueError("Invalid test case, expect dict with action...")
-
- def test_auth_fhir_flows_logging(self):
- step = [0]
- test_name = "auth_fhir_flow_calls_logging"
- api_ver = API_V1
- self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, True)
- self._play(TESTS[test_name], step, api_ver=api_ver)
- self._testclient_home()
- self._validate_events()
- self._print_testcase_banner(test_name, api_ver, step[0], self.use_mslsx, False)
-
def _validate_events(self):
# validate middleware logging records in log file ./docker-compose/tmp/bb2_logging_test.log
with open(TEST_LOGGING_FILE, 'r') as f:
@@ -605,10 +187,15 @@ def _validate_events(self):
self.assertTrue(re.match(event_desc.get('path_regex'), p))
else:
self.assertEqual(p, event_desc.get('path'))
- self.assertTrue(self._validateJsonSchema(event_desc.get('schema'), event_json))
+ self.assertTrue(validate_json_schema(event_desc.get('schema'), event_json))
except JSONDecodeError:
# skip non json line
pass
# all log events present and validated
self.assertEqual(len(expected_events), 0)
+
+ def test_auth_fhir_flows_logging(self):
+ self.test_auth_grant_fhir_calls_v1()
+ print("validating logging events in log...")
+ self._validate_events()
diff --git a/apps/integration_tests/selenium_cases.py b/apps/integration_tests/selenium_cases.py
new file mode 100755
index 000000000..34fc68773
--- /dev/null
+++ b/apps/integration_tests/selenium_cases.py
@@ -0,0 +1,359 @@
+from django.conf import settings
+from enum import Enum
+from selenium.webdriver.common.by import By
+
+
+class Action(Enum):
+ LOAD_PAGE = 1
+ FIND_CLICK = 2
+ FIND = 3
+ FIND_SEND_KEY = 4
+ CHECK = 5
+ BACK = 6
+ LOGIN = 7
+ CONTAIN_TEXT = 8
+ GET_SAMPLE_TOKEN_START = 9
+ SLEEP = 10
+
+
+TESTCLIENT_BUNDLE_LABEL_FMT = "Response (Bundle of {}), API version: {}"
+TESTCLIENT_RESOURCE_LABEL_FMT = "Response ({}), API version: {}"
+MESSAGE_NO_PERMISSION = "You do not have permission to perform this action."
+TESTCASE_BANNER_FMT = "** {} TEST: {}, API: {}, STEP: {}, {}"
+'''
+UI Widget text: texts on e.g. buttons, links, labels etc.
+'''
+LNK_TXT_TESTCLIENT = "Test Client"
+LNK_TXT_GET_TOKEN_V1 = "Get a Sample Authorization Token"
+LNK_TXT_GET_TOKEN_V2 = "Get a Sample Authorization Token for v2"
+LNK_TXT_AUTH_AS_BENE = "Authorize as a Beneficiary"
+LNK_TXT_RESTART_TESTCLIENT = "restart testclient"
+# FHIR search result bundle pagination
+LNK_TXT_NAV_FIRST = "first"
+LNK_TXT_NAV_NEXT = "next"
+LNK_TXT_NAV_PREV = "previous"
+LNK_TXT_NAV_LAST = "last"
+LNK_TXT_NAV_SELF = "self"
+# FHIR resources query page
+LNK_TXT_PATIENT = "Patient"
+LNK_TXT_EOB = "ExplanationOfBenefit"
+LNK_TXT_COVERAGE = "Coverage"
+LNK_TXT_PROFILE = "Profile"
+LNK_TXT_METADATA = "FHIR Metadata"
+LNK_TXT_OIDC_DISCOVERY = "OIDC Discovery"
+# FHIR result page label H2
+LAB_FHIR_RESULTPAGE_H2 = "h2"
+CONTENT_FHIR_RESULTPAGE_PRE = "pre"
+# MSLSX login form
+TXT_FLD_SUB_MSLSX = "username"
+TXT_FLD_HICN_MSLSX = "hicn"
+TXT_FLD_MBI_MSLSX = "mbi"
+TXT_FLD_VAL_SUB_MSLSX = "fred"
+MSLSX_TXT_FLD_HICN_VAL = "1000044680"
+MSLSX_TXT_FLD_MBI_VAL = "2SW4N00AA00"
+MSLSX_CSS_BUTTON = "button"
+# SLSX login form
+SLSX_TXT_FLD_USERNAME = "username-textbox"
+SLSX_TXT_FLD_PASSWORD = "password-textbox"
+SLSX_TXT_FLD_USERNAME_VAL = "BBUser00000"
+SLSX_TXT_FLD_PASSWORD_VAL = "PW00000!"
+SLSX_CSS_BUTTON = "login-button"
+# Demographic info access grant form
+BTN_ID_GRANT_DEMO_ACCESS = "approve"
+BTN_ID_DENY_DEMO_ACCESS = "deny"
+BTN_ID_RADIO_NOT_SHARE = "label:nth-child(5)"
+# API versions
+API_V2 = "v2"
+API_V1 = "v1"
+
+BROWSERBACK = {
+ "display": "Back to FHIR resource page",
+ "action": Action.BACK,
+}
+
+WAIT_SECONDS = {
+ "display": "Sleep seconds...",
+ "action": Action.SLEEP,
+ "params": [3],
+}
+
+CHECK_TESTCLIENT_START_PAGE = {
+ "display": "Check it's on 'Test Client' start page",
+ "action": Action.FIND,
+ "params": [30, By.LINK_TEXT, LNK_TXT_GET_TOKEN_V1]
+}
+
+CLICK_TESTCLIENT = {
+ "display": "Click link 'Test Client'",
+ "action": Action.FIND_CLICK,
+ "params": [30, By.LINK_TEXT, LNK_TXT_TESTCLIENT]
+}
+
+CLICK_RADIO_NOT_SHARE = {
+ "display": "Click 'Share healthcare data, but not your personal info' on DEMO info grant form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.CSS_SELECTOR, BTN_ID_RADIO_NOT_SHARE]
+}
+
+CLICK_AGREE_ACCESS = {
+ "display": "Click 'Agree' on DEMO info grant form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.ID, BTN_ID_GRANT_DEMO_ACCESS]
+}
+
+CLICK_DENY_ACCESS = {
+ "display": "Click 'Deny' on DEMO info grant form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.ID, BTN_ID_DENY_DEMO_ACCESS]
+}
+
+CALL_LOGIN = {
+ "display": "Start login ...",
+ "action": Action.LOGIN,
+}
+
+SEQ_LOGIN_MSLSX = [
+ {
+ "display": "Input SUB(username)",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.NAME, TXT_FLD_SUB_MSLSX, TXT_FLD_VAL_SUB_MSLSX]
+ },
+ {
+ "display": "Input hicn",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.NAME, TXT_FLD_HICN_MSLSX, MSLSX_TXT_FLD_HICN_VAL]
+ },
+ {
+ "display": "Input mbi",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.NAME, TXT_FLD_MBI_MSLSX, MSLSX_TXT_FLD_MBI_VAL]
+ },
+ {
+ "display": "Click 'submit' on MSLSX login form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.CSS_SELECTOR, MSLSX_CSS_BUTTON]
+ },
+]
+
+SEQ_LOGIN_SLSX = [
+ {
+ "display": "MyMedicare login username",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.ID, SLSX_TXT_FLD_USERNAME, SLSX_TXT_FLD_USERNAME_VAL]
+ },
+ {
+ "display": "MyMedicare login password",
+ "action": Action.FIND_SEND_KEY,
+ "params": [20, By.ID, SLSX_TXT_FLD_PASSWORD, SLSX_TXT_FLD_PASSWORD_VAL]
+ },
+ {
+ "display": "Click 'submit' on SLSX login form",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.ID, SLSX_CSS_BUTTON]
+ },
+]
+
+SEQ_AUTHORIZE_START = [
+ {
+ "display": "Load BB2 Landing Page ...",
+ "action": Action.LOAD_PAGE,
+ "params": [settings.HOSTNAME_URL]
+ },
+ CLICK_TESTCLIENT,
+ {
+ "display": "Click link to get sample token v1/v2",
+ "action": Action.GET_SAMPLE_TOKEN_START,
+ },
+ {
+ "display": "Click link 'Authorize as a Beneficiary' - start authorization",
+ "action": Action.FIND_CLICK,
+ "params": [30, By.LINK_TEXT, LNK_TXT_AUTH_AS_BENE]
+ },
+]
+
+SEQ_QUERY_FHIR_RESOURCES = [
+ {
+ "display": "Click 'Patient' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PATIENT]
+ },
+ {
+ "display": "Check Patient result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_PATIENT]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'Coverage' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check Coverage result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check and click Coverage result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ CLICK_TESTCLIENT,
+ {
+ "display": "Click 'ExplanationOfBenefit' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check ExplanationOfBenefit result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check and click ExplanationOfBenefit result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ WAIT_SECONDS,
+ CLICK_TESTCLIENT,
+ WAIT_SECONDS,
+ {
+ "display": "Click 'Profile' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PROFILE]
+ },
+ WAIT_SECONDS,
+ {
+ "display": "Check Profile result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT,
+ "{} (OIDC Userinfo)".format(LNK_TXT_PROFILE)]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'FHIR Metadata' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_METADATA]
+ },
+ {
+ "display": "Check FHIR Metadata result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_METADATA]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'OIDC Discovery' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ {
+ "display": "Check OIDC Discovery result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ BROWSERBACK,
+]
+
+SEQ_QUERY_FHIR_RESOURCES_NO_DEMO = [
+ {
+ "display": "Click 'Patient' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PATIENT]
+ },
+ {
+ "display": "Check Patient result page content () expect no permission message",
+ "action": Action.CONTAIN_TEXT,
+ "params": [20, By.TAG_NAME, CONTENT_FHIR_RESULTPAGE_PRE, MESSAGE_NO_PERMISSION]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'Coverage' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check Coverage result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_COVERAGE]
+ },
+ {
+ "display": "Check and click Coverage result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ CLICK_TESTCLIENT,
+ {
+ "display": "Click 'ExplanationOfBenefit' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check ExplanationOfBenefit result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_EOB]
+ },
+ {
+ "display": "Check and click ExplanationOfBenefit result page navigation links 'last'",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
+ },
+ WAIT_SECONDS,
+ CLICK_TESTCLIENT,
+ WAIT_SECONDS,
+ {
+ "display": "Click 'Profile' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_PROFILE]
+ },
+ WAIT_SECONDS,
+ {
+ "display": "Check Profile result page content () expect no permission message",
+ "action": Action.CONTAIN_TEXT,
+ "params": [20, By.TAG_NAME, CONTENT_FHIR_RESULTPAGE_PRE, MESSAGE_NO_PERMISSION]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'FHIR Metadata' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_METADATA]
+ },
+ {
+ "display": "Check FHIR Metadata result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_METADATA]
+ },
+ BROWSERBACK,
+ {
+ "display": "Click 'OIDC Discovery' on FHIR resources page",
+ "action": Action.FIND_CLICK,
+ "params": [20, By.LINK_TEXT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ {
+ "display": "Check OIDC Discovery result page title",
+ "action": Action.CHECK,
+ "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_OIDC_DISCOVERY]
+ },
+ BROWSERBACK,
+]
+
+TESTS = {
+ "auth_grant_fhir_calls": [
+ {"sequence": SEQ_AUTHORIZE_START},
+ CALL_LOGIN,
+ CLICK_AGREE_ACCESS,
+ {"sequence": SEQ_QUERY_FHIR_RESOURCES}
+ ],
+ "auth_deny_fhir_calls": [
+ {"sequence": SEQ_AUTHORIZE_START},
+ CALL_LOGIN,
+ CLICK_DENY_ACCESS,
+ CHECK_TESTCLIENT_START_PAGE
+ ],
+ "auth_grant_w_no_demo": [
+ {"sequence": SEQ_AUTHORIZE_START},
+ CALL_LOGIN,
+ CLICK_RADIO_NOT_SHARE,
+ CLICK_AGREE_ACCESS,
+ {"sequence": SEQ_QUERY_FHIR_RESOURCES_NO_DEMO}
+ ]
+}
diff --git a/apps/integration_tests/selenium_tests.py b/apps/integration_tests/selenium_tests.py
index 15dee6b1b..aec162e7c 100755
--- a/apps/integration_tests/selenium_tests.py
+++ b/apps/integration_tests/selenium_tests.py
@@ -1,8 +1,6 @@
import os
import time
-from django.conf import settings
from django.test import TestCase
-from enum import Enum
from selenium import webdriver
from selenium.webdriver.common.by import By
@@ -11,361 +9,18 @@
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.common.keys import Keys
-TESTCLIENT_BUNDLE_LABEL_FMT = "Response (Bundle of {}), API version: {}"
-TESTCLIENT_RESOURCE_LABEL_FMT = "Response ({}), API version: {}"
-MESSAGE_NO_PERMISSION = "You do not have permission to perform this action."
-TESTCASE_BANNER_FMT = "** {} TEST: {}, API: {}, STEP: {}, {}"
-'''
-UI Widget text: texts on e.g. buttons, links, labels etc.
-'''
-LNK_TXT_TESTCLIENT = "Test Client"
-LNK_TXT_GET_TOKEN_V1 = "Get a Sample Authorization Token"
-LNK_TXT_GET_TOKEN_V2 = "Get a Sample Authorization Token for v2"
-LNK_TXT_AUTH_AS_BENE = "Authorize as a Beneficiary"
-LNK_TXT_RESTART_TESTCLIENT = "restart testclient"
-# FHIR search result bundle pagination
-LNK_TXT_NAV_FIRST = "first"
-LNK_TXT_NAV_NEXT = "next"
-LNK_TXT_NAV_PREV = "previous"
-LNK_TXT_NAV_LAST = "last"
-LNK_TXT_NAV_SELF = "self"
-# FHIR resources query page
-LNK_TXT_PATIENT = "Patient"
-LNK_TXT_EOB = "ExplanationOfBenefit"
-LNK_TXT_COVERAGE = "Coverage"
-LNK_TXT_PROFILE = "Profile"
-LNK_TXT_METADATA = "FHIR Metadata"
-LNK_TXT_OIDC_DISCOVERY = "OIDC Discovery"
-# FHIR result page label H2
-LAB_FHIR_RESULTPAGE_H2 = "h2"
-CONTENT_FHIR_RESULTPAGE_PRE = "pre"
-# MSLSX login form
-TXT_FLD_SUB_MSLSX = "username"
-TXT_FLD_HICN_MSLSX = "hicn"
-TXT_FLD_MBI_MSLSX = "mbi"
-TXT_FLD_VAL_SUB_MSLSX = "fred"
-MSLSX_TXT_FLD_HICN_VAL = "1000044680"
-MSLSX_TXT_FLD_MBI_VAL = "2SW4N00AA00"
-MSLSX_CSS_BUTTON = "button"
-# SLSX login form
-SLSX_TXT_FLD_USERNAME = "username-textbox"
-SLSX_TXT_FLD_PASSWORD = "password-textbox"
-SLSX_TXT_FLD_USERNAME_VAL = "BBUser00000"
-SLSX_TXT_FLD_PASSWORD_VAL = "PW00000!"
-SLSX_CSS_BUTTON = "login-button"
-# Demographic info access grant form
-BTN_ID_GRANT_DEMO_ACCESS = "approve"
-BTN_ID_DENY_DEMO_ACCESS = "deny"
-BTN_ID_RADIO_NOT_SHARE = "label:nth-child(5)"
-# API versions
-API_V2 = "v2"
-API_V1 = "v1"
-
-
-class Action(Enum):
- LOAD_PAGE = 1
- FIND_CLICK = 2
- FIND = 3
- FIND_SEND_KEY = 4
- CHECK = 5
- BACK = 6
- LOGIN = 7
- CONTAIN_TEXT = 8
- GET_SAMPLE_TOKEN_START = 9
- SLEEP = 10
-
-
-BROWSERBACK = {
- "display": "Back to FHIR resource page",
- "action": Action.BACK,
-}
-
-WAIT_SECONDS = {
- "display": "Sleep seconds...",
- "action": Action.SLEEP,
- "params": [3],
-}
-
-CHECK_TESTCLIENT_START_PAGE = {
- "display": "Check it's on 'Test Client' start page",
- "action": Action.FIND,
- "params": [30, By.LINK_TEXT, LNK_TXT_GET_TOKEN_V1]
-}
-
-CLICK_TESTCLIENT = {
- "display": "Click link 'Test Client'",
- "action": Action.FIND_CLICK,
- "params": [30, By.LINK_TEXT, LNK_TXT_TESTCLIENT]
-}
-
-CLICK_RADIO_NOT_SHARE = {
- "display": "Click 'Share healthcare data, but not your personal info' on DEMO info grant form",
- "action": Action.FIND_CLICK,
- "params": [20, By.CSS_SELECTOR, BTN_ID_RADIO_NOT_SHARE]
-}
-
-CLICK_AGREE_ACCESS = {
- "display": "Click 'Agree' on DEMO info grant form",
- "action": Action.FIND_CLICK,
- "params": [20, By.ID, BTN_ID_GRANT_DEMO_ACCESS]
-}
-
-CLICK_DENY_ACCESS = {
- "display": "Click 'Deny' on DEMO info grant form",
- "action": Action.FIND_CLICK,
- "params": [20, By.ID, BTN_ID_DENY_DEMO_ACCESS]
-}
-
-CALL_LOGIN = {
- "display": "Start login ...",
- "action": Action.LOGIN,
-}
-
-SEQ_LOGIN_MSLSX = [
- {
- "display": "Input SUB(username)",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.NAME, TXT_FLD_SUB_MSLSX, TXT_FLD_VAL_SUB_MSLSX]
- },
- {
- "display": "Input hicn",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.NAME, TXT_FLD_HICN_MSLSX, MSLSX_TXT_FLD_HICN_VAL]
- },
- {
- "display": "Input mbi",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.NAME, TXT_FLD_MBI_MSLSX, MSLSX_TXT_FLD_MBI_VAL]
- },
- {
- "display": "Click 'submit' on MSLSX login form",
- "action": Action.FIND_CLICK,
- "params": [20, By.CSS_SELECTOR, MSLSX_CSS_BUTTON]
- },
-]
-
-SEQ_LOGIN_SLSX = [
- {
- "display": "MyMedicare login username",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.ID, SLSX_TXT_FLD_USERNAME, SLSX_TXT_FLD_USERNAME_VAL]
- },
- {
- "display": "MyMedicare login password",
- "action": Action.FIND_SEND_KEY,
- "params": [20, By.ID, SLSX_TXT_FLD_PASSWORD, SLSX_TXT_FLD_PASSWORD_VAL]
- },
- {
- "display": "Click 'submit' on SLSX login form",
- "action": Action.FIND_CLICK,
- "params": [20, By.ID, SLSX_CSS_BUTTON]
- },
-]
-
-SEQ_AUTHORIZE_START = [
- {
- "display": "Load BB2 Landing Page ...",
- "action": Action.LOAD_PAGE,
- "params": [settings.HOSTNAME_URL]
- },
- CLICK_TESTCLIENT,
- {
- "display": "Click link to get sample token v1/v2",
- "action": Action.GET_SAMPLE_TOKEN_START,
- },
- {
- "display": "Click link 'Authorize as a Beneficiary' - start authorization",
- "action": Action.FIND_CLICK,
- "params": [30, By.LINK_TEXT, LNK_TXT_AUTH_AS_BENE]
- },
-]
-
-SEQ_QUERY_FHIR_RESOURCES = [
- {
- "display": "Click 'Patient' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_PATIENT]
- },
- {
- "display": "Check Patient result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_PATIENT]
- },
- BROWSERBACK,
- {
- "display": "Click 'Coverage' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_COVERAGE]
- },
- {
- "display": "Check Coverage result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_COVERAGE]
- },
- {
- "display": "Check and click Coverage result page navigation links 'last'",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
- },
- CLICK_TESTCLIENT,
- {
- "display": "Click 'ExplanationOfBenefit' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_EOB]
- },
- {
- "display": "Check ExplanationOfBenefit result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_EOB]
- },
- {
- "display": "Check and click ExplanationOfBenefit result page navigation links 'last'",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
- },
- WAIT_SECONDS,
- CLICK_TESTCLIENT,
- WAIT_SECONDS,
- {
- "display": "Click 'Profile' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_PROFILE]
- },
- WAIT_SECONDS,
- {
- "display": "Check Profile result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT,
- "{} (OIDC Userinfo)".format(LNK_TXT_PROFILE)]
- },
- BROWSERBACK,
- {
- "display": "Click 'FHIR Metadata' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_METADATA]
- },
- {
- "display": "Check FHIR Metadata result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_METADATA]
- },
- BROWSERBACK,
- {
- "display": "Click 'OIDC Discovery' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_OIDC_DISCOVERY]
- },
- {
- "display": "Check OIDC Discovery result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_OIDC_DISCOVERY]
- },
- BROWSERBACK,
-]
-
-SEQ_QUERY_FHIR_RESOURCES_NO_DEMO = [
- {
- "display": "Click 'Patient' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_PATIENT]
- },
- {
- "display": "Check Patient result page content () expect no permission message",
- "action": Action.CONTAIN_TEXT,
- "params": [20, By.TAG_NAME, CONTENT_FHIR_RESULTPAGE_PRE, MESSAGE_NO_PERMISSION]
- },
- BROWSERBACK,
- {
- "display": "Click 'Coverage' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_COVERAGE]
- },
- {
- "display": "Check Coverage result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_COVERAGE]
- },
- {
- "display": "Check and click Coverage result page navigation links 'last'",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
- },
- CLICK_TESTCLIENT,
- {
- "display": "Click 'ExplanationOfBenefit' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_EOB]
- },
- {
- "display": "Check ExplanationOfBenefit result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_BUNDLE_LABEL_FMT, LNK_TXT_EOB]
- },
- {
- "display": "Check and click ExplanationOfBenefit result page navigation links 'last'",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_NAV_LAST]
- },
- WAIT_SECONDS,
- CLICK_TESTCLIENT,
- WAIT_SECONDS,
- {
- "display": "Click 'Profile' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_PROFILE]
- },
- WAIT_SECONDS,
- {
- "display": "Check Profile result page content () expect no permission message",
- "action": Action.CONTAIN_TEXT,
- "params": [20, By.TAG_NAME, CONTENT_FHIR_RESULTPAGE_PRE, MESSAGE_NO_PERMISSION]
- },
- BROWSERBACK,
- {
- "display": "Click 'FHIR Metadata' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_METADATA]
- },
- {
- "display": "Check FHIR Metadata result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_METADATA]
- },
- BROWSERBACK,
- {
- "display": "Click 'OIDC Discovery' on FHIR resources page",
- "action": Action.FIND_CLICK,
- "params": [20, By.LINK_TEXT, LNK_TXT_OIDC_DISCOVERY]
- },
- {
- "display": "Check OIDC Discovery result page title",
- "action": Action.CHECK,
- "params": [20, By.TAG_NAME, LAB_FHIR_RESULTPAGE_H2, TESTCLIENT_RESOURCE_LABEL_FMT, LNK_TXT_OIDC_DISCOVERY]
- },
- BROWSERBACK,
-]
-
-TESTS = {
- "auth_grant_fhir_calls": [
- {"sequence": SEQ_AUTHORIZE_START},
- CALL_LOGIN,
- CLICK_AGREE_ACCESS,
- {"sequence": SEQ_QUERY_FHIR_RESOURCES}
- ],
- "auth_deny_fhir_calls": [
- {"sequence": SEQ_AUTHORIZE_START},
- CALL_LOGIN,
- CLICK_DENY_ACCESS,
- CHECK_TESTCLIENT_START_PAGE
- ],
- "auth_grant_w_no_demo": [
- {"sequence": SEQ_AUTHORIZE_START},
- CALL_LOGIN,
- CLICK_RADIO_NOT_SHARE,
- CLICK_AGREE_ACCESS,
- {"sequence": SEQ_QUERY_FHIR_RESOURCES_NO_DEMO}
- ]
-}
+from .selenium_cases import (
+ Action,
+ TESTCASE_BANNER_FMT,
+ LNK_TXT_GET_TOKEN_V1,
+ LNK_TXT_GET_TOKEN_V2,
+ LNK_TXT_RESTART_TESTCLIENT,
+ API_V2,
+ API_V1,
+ SEQ_LOGIN_MSLSX,
+ SEQ_LOGIN_SLSX,
+ TESTS,
+)
class SeleniumTests(TestCase):
diff --git a/docker-compose/readme.md b/docker-compose/readme.md
index 5d31a0294..e9070eb5b 100644
--- a/docker-compose/readme.md
+++ b/docker-compose/readme.md
@@ -300,4 +300,15 @@ You can run selenium tests by following below steps:
./docker-compose/run_selenium_tests_local_keybase.sh slsx
```
- 3. To trouble shoot tests: point VNC client to localhost:6900
\ No newline at end of file
+ 3. To trouble shoot tests (visualize webUI interaction): point VNC client to localhost:6900
+ 1. requires installation of vnc viewer, password (secret)
+ 2. also need to comment out webdriver headless option, as shown below:
+ ```
+ ./apps/integration_tests/selenium_tests.py: setUp():
+ ...
+ opt = webdriver.ChromeOptions()
+ opt.add_argument('--headless')
+ opt.add_argument("--disable-dev-shm-usage")
+ ...
+ ```
+
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
index 3a5efbcbf..19f215f7f 100755
--- a/docker-compose/run_selenium_tests_local_keybase.sh
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -77,7 +77,7 @@ else
if [ $1 == "logit" ]
then
TEST_TYPE="--logit"
- TESTS_LIST="apps.integration_tests.logging_tests.LoggingTests"
+ TESTS_LIST="apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging"
export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.test_logging"
export DJANGO_LOG_JSON_FORMAT_PRETTY=False
mkdir -p docker-compose/tmp
From 55b1dfca3e00d83f8fd839c24cb1fa41e5527a0e Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Thu, 15 Jul 2021 11:08:44 -0700
Subject: [PATCH 05/39] pick up changes from BB2-545
---
apps/integration_tests/selenium_tests.py | 2 +-
docker-compose.selenium.yml | 67 +++----------------
.../run_selenium_tests_local_keybase.sh | 31 ++++++---
3 files changed, 32 insertions(+), 68 deletions(-)
diff --git a/apps/integration_tests/selenium_tests.py b/apps/integration_tests/selenium_tests.py
index aec162e7c..95a9c7856 100755
--- a/apps/integration_tests/selenium_tests.py
+++ b/apps/integration_tests/selenium_tests.py
@@ -41,7 +41,7 @@ def setUp(self):
print("wait_completed={}".format(SeleniumTests.wait_completed))
opt = webdriver.ChromeOptions()
- # opt.add_argument('--headless')
+ opt.add_argument('--headless')
opt.add_argument("--disable-dev-shm-usage")
opt.add_argument("--disable-web-security")
opt.add_argument("--allow-running-insecure-content")
diff --git a/docker-compose.selenium.yml b/docker-compose.selenium.yml
index e66c670a2..4cf1a0bf6 100755
--- a/docker-compose.selenium.yml
+++ b/docker-compose.selenium.yml
@@ -2,20 +2,6 @@ version: '3'
services:
tests:
- build:
- context: ./
- dockerfile: SeleniumDockerfile
- command: python runtests.py apps.integration_tests.selenium_tests.SeleniumTests
- environment:
- - HOSTNAME_URL=${HOSTNAME_URL}
- - USE_MSLSX=${USE_MSLSX}
- volumes:
- - .:/code
- depends_on:
- - bb2
- - chrome
-
- tests_w_slsx:
build:
context: ./
dockerfile: SeleniumDockerfile
@@ -28,7 +14,7 @@ services:
depends_on:
- bb2slsx
- chrome
-
+
chrome:
image: selenium/node-chrome:4.0.0-beta-4-prerelease-20210517
volumes:
@@ -83,7 +69,7 @@ services:
command: msls
ports:
- "8080:8080"
-
+
db:
image: postgres
environment:
@@ -92,7 +78,7 @@ services:
ports:
- "5432:5432"
- bb2:
+ bb2slsx:
build: .
command: ./docker-compose/bluebutton_server_start.sh '${DB_MIGRATIONS}' '${SUPER_USER_NAME}' '${SUPER_USER_EMAIL}' '${SUPER_USER_PASSWORD}' '${BB20_ENABLE_REMOTE_DEBUG}' '${BB20_REMOTE_DEBUG_WAIT_ATTACH}'
environment:
@@ -103,12 +89,12 @@ services:
- DJANGO_SECURE_SESSION=False
- FHIR_URL="https://prod-sbx.bfd.cms.gov"
- DJANGO_FHIR_CERTSTORE=/code/docker-compose/certstore/
- - DJANGO_MEDICARE_SLSX_REDIRECT_URI=http://bb2:8000/mymedicare/sls-callback
- - DJANGO_MEDICARE_SLSX_LOGIN_URI=http://msls:8080/sso/authorize?client_id=bb2api
- - DJANGO_SLSX_HEALTH_CHECK_ENDPOINT=http://msls:8080/health
- - DJANGO_SLSX_TOKEN_ENDPOINT=http://msls:8080/sso/session
- - DJANGO_SLSX_SIGNOUT_ENDPOINT=http://msls:8080/sso/signout
- - DJANGO_SLSX_USERINFO_ENDPOINT=http://msls:8080/v1/users
+ - DJANGO_MEDICARE_SLSX_REDIRECT_URI=${DJANGO_MEDICARE_SLSX_REDIRECT_URI}
+ - DJANGO_MEDICARE_SLSX_LOGIN_URI=${DJANGO_MEDICARE_SLSX_LOGIN_URI}
+ - DJANGO_SLSX_HEALTH_CHECK_ENDPOINT=${DJANGO_SLSX_HEALTH_CHECK_ENDPOINT}
+ - DJANGO_SLSX_TOKEN_ENDPOINT=${DJANGO_SLSX_TOKEN_ENDPOINT}
+ - DJANGO_SLSX_SIGNOUT_ENDPOINT=${DJANGO_SLSX_SIGNOUT_ENDPOINT}
+ - DJANGO_SLSX_USERINFO_ENDPOINT=${DJANGO_SLSX_USERINFO_ENDPOINT}
- DJANGO_SLSX_CLIENT_ID=bb2api
- DJANGO_SLSX_CLIENT_SECRET=${DJANGO_SLSX_CLIENT_SECRET}
- HOSTNAME_URL=${HOSTNAME_URL}
@@ -125,38 +111,3 @@ services:
depends_on:
- db
- msls
-
- bb2slsx:
- build: .
- command: ./docker-compose/bluebutton_server_start.sh '${DB_MIGRATIONS}' '${SUPER_USER_NAME}' '${SUPER_USER_EMAIL}' '${SUPER_USER_PASSWORD}' '${BB20_ENABLE_REMOTE_DEBUG}' '${BB20_REMOTE_DEBUG_WAIT_ATTACH}'
- environment:
- - DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.dev
- - DATABASES_CUSTOM=postgres://postgres:toor@db:5432/bluebutton
- - OAUTHLIB_INSECURE_TRANSPORT=true
- - DJANGO_DEFAULT_SAMPLE_FHIR_ID="-20140000008325"
- - DJANGO_SECURE_SESSION=False
- - FHIR_URL="https://prod-sbx.bfd.cms.gov"
- - DJANGO_FHIR_CERTSTORE=/code/docker-compose/certstore/
- - DJANGO_SLSX_CLIENT_ID=bb2api
- - DJANGO_SLSX_CLIENT_SECRET=${DJANGO_SLSX_CLIENT_SECRET}
- - HOSTNAME_URL=${HOSTNAME_URL}
- - DJANGO_MEDICARE_SLSX_REDIRECT_URI=http://bb2slsx:8000/mymedicare/sls-callback
- - DJANGO_MEDICARE_SLSX_LOGIN_URI=https://test.medicare.gov/sso/authorize?client_id=bb2api
- - DJANGO_SLSX_HEALTH_CHECK_ENDPOINT=https://test.accounts.cms.gov/health
- - DJANGO_SLSX_TOKEN_ENDPOINT=https://test.medicare.gov/sso/session
- - DJANGO_SLSX_SIGNOUT_ENDPOINT=https://test.medicare.gov/sso/signout
- - DJANGO_SLSX_USERINFO_ENDPOINT=https://test.accounts.cms.gov/v1/users
- # SSL verify for internal endpoints can't currently use SSL verification (this may change in the future)
- - DJANGO_SLSX_VERIFY_SSL_INTERNAL=False
- - DJANGO_SLSX_VERIFY_SSL_EXTERNAL=True
- - DJANGO_LOG_JSON_FORMAT_PRETTY=True
- - DJANGO_USER_ID_ITERATIONS=${DJANGO_USER_ID_ITERATIONS}
- - DJANGO_USER_ID_SALT=${DJANGO_USER_ID_SALT}
- volumes:
- - .:/code
- ports:
- - "8000:8000"
- - "5678:5678"
- depends_on:
- - db
-
\ No newline at end of file
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
index 19f215f7f..876715b51 100755
--- a/docker-compose/run_selenium_tests_local_keybase.sh
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -19,7 +19,7 @@ CERT_FILENAME="client_data_server_bluebutton_local_integration_tests_certificate
KEY_FILENAME="client_data_server_bluebutton_local_integration_tests_private_key.pem"
# BB2 service end point default
-HOSTNAME_URL="http://bb2:8000"
+HOSTNAME_URL="http://bb2slsx:8000"
# Backend FHIR server to use for selenium tests with FHIR requests:
FHIR_URL="https://prod-sbx.bfd.cms.gov"
@@ -42,11 +42,16 @@ echo_msg
set -e -u -o pipefail
USE_MSLSX=true
-DOCKER_COMPOSE_SERVICE="tests"
-
TEST_TYPE="--selenium"
export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.dev"
+DJANGO_MEDICARE_SLSX_REDIRECT_URI="http://bb2slsx:8000/mymedicare/sls-callback"
+DJANGO_MEDICARE_SLSX_LOGIN_URI="http://msls:8080/sso/authorize?client_id=bb2api"
+DJANGO_SLSX_HEALTH_CHECK_ENDPOINT="http://msls:8080/health"
+DJANGO_SLSX_TOKEN_ENDPOINT="http://msls:8080/sso/session"
+DJANGO_SLSX_SIGNOUT_ENDPOINT="http://msls:8080/sso/signout"
+DJANGO_SLSX_USERINFO_ENDPOINT="http://msls:8080/v1/users"
+
# Parse command line option
if [ $# -eq 0 ]
then
@@ -71,8 +76,12 @@ else
if [ $1 == "slsx" ]
then
USE_MSLSX=false
- DOCKER_COMPOSE_SERVICE="tests_w_slsx"
- HOSTNAME_URL="http://bb2slsx:8000"
+ DJANGO_MEDICARE_SLSX_REDIRECT_URI="http://bb2slsx:8000/mymedicare/sls-callback"
+ DJANGO_MEDICARE_SLSX_LOGIN_URI="https://test.medicare.gov/sso/authorize?client_id=bb2api"
+ DJANGO_SLSX_HEALTH_CHECK_ENDPOINT="https://test.accounts.cms.gov/health"
+ DJANGO_SLSX_TOKEN_ENDPOINT="https://test.medicare.gov/sso/session"
+ DJANGO_SLSX_SIGNOUT_ENDPOINT="https://test.medicare.gov/sso/signout"
+ DJANGO_SLSX_USERINFO_ENDPOINT="https://test.accounts.cms.gov/v1/users"
fi
if [ $1 == "logit" ]
then
@@ -90,7 +99,6 @@ else
fi
echo "DJANGO_SETTINGS_MODULE: " ${DJANGO_SETTINGS_MODULE}
-echo "DOCKER_COMPOSE_SERVICE: " ${DOCKER_COMPOSE_SERVICE}
echo "HOSTNAME_URL: " ${HOSTNAME_URL}
echo "TEST_TYPE: " ${TEST_TYPE}
echo "TESTS: " ${TESTS_LIST}
@@ -188,7 +196,7 @@ cp ${keybase_cert_file} "${CERTSTORE_TEMPORARY_MOUNT_PATH}/ca.cert.pem"
cp ${keybase_key_file} "${CERTSTORE_TEMPORARY_MOUNT_PATH}/ca.key.nocrypt.pem"
# stop all before run selenium tests
-docker-compose -f docker-compose.selenium.yml stop
+docker-compose -f docker-compose.selenium.yml down
export DJANGO_PASSWORD_HASH_ITERATIONS=${DJANGO_PASSWORD_HASH_ITERATIONS}
export DJANGO_USER_ID_SALT=${DJANGO_USER_ID_SALT}
@@ -197,11 +205,16 @@ export DJANGO_SLSX_CLIENT_ID=${DJANGO_SLSX_CLIENT_ID}
export DJANGO_SLSX_CLIENT_SECRET=${DJANGO_SLSX_CLIENT_SECRET}
export HOSTNAME_URL=${HOSTNAME_URL}
export USE_MSLSX=${USE_MSLSX}
+export DJANGO_MEDICARE_SLSX_REDIRECT_URI=${DJANGO_MEDICARE_SLSX_REDIRECT_URI}
+export DJANGO_MEDICARE_SLSX_LOGIN_URI=${DJANGO_MEDICARE_SLSX_LOGIN_URI}
+export DJANGO_SLSX_HEALTH_CHECK_ENDPOINT=${DJANGO_SLSX_HEALTH_CHECK_ENDPOINT}
+export DJANGO_SLSX_TOKEN_ENDPOINT=${DJANGO_SLSX_TOKEN_ENDPOINT}
+export DJANGO_SLSX_SIGNOUT_ENDPOINT=${DJANGO_SLSX_SIGNOUT_ENDPOINT}
+export DJANGO_SLSX_USERINFO_ENDPOINT=${DJANGO_SLSX_USERINFO_ENDPOINT}
echo "Selenium tests ..."
-docker-compose -f docker-compose.selenium.yml run \
-${DOCKER_COMPOSE_SERVICE} bash -c "python runtests.py ${TEST_TYPE} ${TESTS_LIST}"
+docker-compose -f docker-compose.selenium.yml run tests bash -c "python runtests.py ${TEST_TYPE} ${TESTS_LIST}"
# Remove certfiles from local directory
echo_msg
From eab261fdf59d28a378a4b24e883d4de85777a60f Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Tue, 20 Jul 2021 10:54:34 -0700
Subject: [PATCH 06/39] pick bb2 545 changes and rebase.
---
SeleniumDockerfile => Dockerfile.selenium | 25 +++++-----
apps/integration_tests/selenium_tests.py | 2 +-
apps/mymedicare_cb/authorization.py | 1 -
docker-compose.selenium.yml | 2 +-
.../run_selenium_tests_local_keybase.sh | 49 +++++++++----------
5 files changed, 37 insertions(+), 42 deletions(-)
rename SeleniumDockerfile => Dockerfile.selenium (68%)
diff --git a/SeleniumDockerfile b/Dockerfile.selenium
similarity index 68%
rename from SeleniumDockerfile
rename to Dockerfile.selenium
index 759971700..c02274e76 100755
--- a/SeleniumDockerfile
+++ b/Dockerfile.selenium
@@ -1,15 +1,12 @@
-FROM selenium/standalone-chrome-debug
-
-ENV PYTHONUNBUFFERED 1
-USER root
-RUN apt-get update && apt-get install -yq python3.7 python3-pip
-RUN pip3 install --upgrade pip
-RUN pip3 install selenium
-RUN pip3 install psycopg2-binary==2.8.6
-RUN pip3 install pyyaml==5.4.1
-RUN pip3 install Pillow==8.2.0
-RUN mkdir /code
-ADD . /code/
-WORKDIR /code
-RUN make reqs-install-dev
+FROM selenium/standalone-chrome-debug
+
+ENV PYTHONUNBUFFERED 1
+USER root
+RUN apt-get update && apt-get install -yq python3.7 python3-pip
+RUN pip3 install --upgrade pip
+RUN pip3 install selenium psycopg2-binary==2.8.6 pyyaml==5.4.1 Pillow==8.2.0
+RUN mkdir /code
+ADD . /code/
+WORKDIR /code
+RUN make reqs-install-dev
RUN ln -s /usr/bin/python3 /usr/local/bin/python
\ No newline at end of file
diff --git a/apps/integration_tests/selenium_tests.py b/apps/integration_tests/selenium_tests.py
index 95a9c7856..aec162e7c 100755
--- a/apps/integration_tests/selenium_tests.py
+++ b/apps/integration_tests/selenium_tests.py
@@ -41,7 +41,7 @@ def setUp(self):
print("wait_completed={}".format(SeleniumTests.wait_completed))
opt = webdriver.ChromeOptions()
- opt.add_argument('--headless')
+ # opt.add_argument('--headless')
opt.add_argument("--disable-dev-shm-usage")
opt.add_argument("--disable-web-security")
opt.add_argument("--allow-running-insecure-content")
diff --git a/apps/mymedicare_cb/authorization.py b/apps/mymedicare_cb/authorization.py
index b391a076b..88c40094a 100644
--- a/apps/mymedicare_cb/authorization.py
+++ b/apps/mymedicare_cb/authorization.py
@@ -197,7 +197,6 @@ def service_health_check(self, request):
the BB2 /health/external check.
"""
headers = self.slsx_common_headers(request)
-
response = requests.get(self.healthcheck_endpoint,
headers=headers,
allow_redirects=False,
diff --git a/docker-compose.selenium.yml b/docker-compose.selenium.yml
index 4cf1a0bf6..e6511767f 100755
--- a/docker-compose.selenium.yml
+++ b/docker-compose.selenium.yml
@@ -4,7 +4,7 @@ services:
tests:
build:
context: ./
- dockerfile: SeleniumDockerfile
+ dockerfile: Dockerfile.selenium
command: python runtests.py apps.integration_tests.selenium_tests.SeleniumTests
environment:
- HOSTNAME_URL=${HOSTNAME_URL}
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
index 876715b51..e94de2fc9 100755
--- a/docker-compose/run_selenium_tests_local_keybase.sh
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -1,7 +1,7 @@
#!/bin/bash
# Run the selenium tests in docker
-#
+#
# NOTE:
#
# 1. You must be logged in to Keybase and have the BB2 team file system mounted.
@@ -19,7 +19,7 @@ CERT_FILENAME="client_data_server_bluebutton_local_integration_tests_certificate
KEY_FILENAME="client_data_server_bluebutton_local_integration_tests_private_key.pem"
# BB2 service end point default
-HOSTNAME_URL="http://bb2slsx:8000"
+export HOSTNAME_URL="http://bb2slsx:8000"
# Backend FHIR server to use for selenium tests with FHIR requests:
FHIR_URL="https://prod-sbx.bfd.cms.gov"
@@ -41,16 +41,17 @@ echo_msg
# Set bash builtins for safety
set -e -u -o pipefail
-USE_MSLSX=true
TEST_TYPE="--selenium"
+
+export USE_MSLSX=true
export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.dev"
-DJANGO_MEDICARE_SLSX_REDIRECT_URI="http://bb2slsx:8000/mymedicare/sls-callback"
-DJANGO_MEDICARE_SLSX_LOGIN_URI="http://msls:8080/sso/authorize?client_id=bb2api"
-DJANGO_SLSX_HEALTH_CHECK_ENDPOINT="http://msls:8080/health"
-DJANGO_SLSX_TOKEN_ENDPOINT="http://msls:8080/sso/session"
-DJANGO_SLSX_SIGNOUT_ENDPOINT="http://msls:8080/sso/signout"
-DJANGO_SLSX_USERINFO_ENDPOINT="http://msls:8080/v1/users"
+export DJANGO_MEDICARE_SLSX_REDIRECT_URI="http://bb2slsx:8000/mymedicare/sls-callback"
+export DJANGO_MEDICARE_SLSX_LOGIN_URI="http://msls:8080/sso/authorize?client_id=bb2api"
+export DJANGO_SLSX_HEALTH_CHECK_ENDPOINT="http://msls:8080/health"
+export DJANGO_SLSX_TOKEN_ENDPOINT="http://msls:8080/sso/session"
+export DJANGO_SLSX_SIGNOUT_ENDPOINT="http://msls:8080/sso/signout"
+export DJANGO_SLSX_USERINFO_ENDPOINT="http://msls:8080/v1/users"
# Parse command line option
if [ $# -eq 0 ]
@@ -75,13 +76,13 @@ else
else
if [ $1 == "slsx" ]
then
- USE_MSLSX=false
- DJANGO_MEDICARE_SLSX_REDIRECT_URI="http://bb2slsx:8000/mymedicare/sls-callback"
- DJANGO_MEDICARE_SLSX_LOGIN_URI="https://test.medicare.gov/sso/authorize?client_id=bb2api"
- DJANGO_SLSX_HEALTH_CHECK_ENDPOINT="https://test.accounts.cms.gov/health"
- DJANGO_SLSX_TOKEN_ENDPOINT="https://test.medicare.gov/sso/session"
- DJANGO_SLSX_SIGNOUT_ENDPOINT="https://test.medicare.gov/sso/signout"
- DJANGO_SLSX_USERINFO_ENDPOINT="https://test.accounts.cms.gov/v1/users"
+ export USE_MSLSX=false
+ export DJANGO_MEDICARE_SLSX_REDIRECT_URI="http://bb2slsx:8000/mymedicare/sls-callback"
+ export DJANGO_MEDICARE_SLSX_LOGIN_URI="https://test.medicare.gov/sso/authorize?client_id=bb2api"
+ export DJANGO_SLSX_HEALTH_CHECK_ENDPOINT="https://test.accounts.cms.gov/health"
+ export DJANGO_SLSX_TOKEN_ENDPOINT="https://test.medicare.gov/sso/session"
+ export DJANGO_SLSX_SIGNOUT_ENDPOINT="https://test.medicare.gov/sso/signout"
+ export DJANGO_SLSX_USERINFO_ENDPOINT="https://test.accounts.cms.gov/v1/users"
fi
if [ $1 == "logit" ]
then
@@ -198,24 +199,22 @@ cp ${keybase_key_file} "${CERTSTORE_TEMPORARY_MOUNT_PATH}/ca.key.nocrypt.pem"
# stop all before run selenium tests
docker-compose -f docker-compose.selenium.yml down
-export DJANGO_PASSWORD_HASH_ITERATIONS=${DJANGO_PASSWORD_HASH_ITERATIONS}
export DJANGO_USER_ID_SALT=${DJANGO_USER_ID_SALT}
export DJANGO_USER_ID_ITERATIONS=${DJANGO_USER_ID_ITERATIONS}
export DJANGO_SLSX_CLIENT_ID=${DJANGO_SLSX_CLIENT_ID}
export DJANGO_SLSX_CLIENT_SECRET=${DJANGO_SLSX_CLIENT_SECRET}
-export HOSTNAME_URL=${HOSTNAME_URL}
-export USE_MSLSX=${USE_MSLSX}
-export DJANGO_MEDICARE_SLSX_REDIRECT_URI=${DJANGO_MEDICARE_SLSX_REDIRECT_URI}
-export DJANGO_MEDICARE_SLSX_LOGIN_URI=${DJANGO_MEDICARE_SLSX_LOGIN_URI}
-export DJANGO_SLSX_HEALTH_CHECK_ENDPOINT=${DJANGO_SLSX_HEALTH_CHECK_ENDPOINT}
-export DJANGO_SLSX_TOKEN_ENDPOINT=${DJANGO_SLSX_TOKEN_ENDPOINT}
-export DJANGO_SLSX_SIGNOUT_ENDPOINT=${DJANGO_SLSX_SIGNOUT_ENDPOINT}
-export DJANGO_SLSX_USERINFO_ENDPOINT=${DJANGO_SLSX_USERINFO_ENDPOINT}
echo "Selenium tests ..."
docker-compose -f docker-compose.selenium.yml run tests bash -c "python runtests.py ${TEST_TYPE} ${TESTS_LIST}"
+# Stop containers after use
+echo_msg
+echo_msg "Stopping containers..."
+echo_msg
+
+docker-compose -f docker-compose.selenium.yml stop
+
# Remove certfiles from local directory
echo_msg
echo_msg Shred and Remove certfiles from CERTSTORE_TEMPORARY_MOUNT_PATH=${CERTSTORE_TEMPORARY_MOUNT_PATH}
From bc675cd29fe406586b20bc6ede2b48dbee808d6a Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 23 Jul 2021 12:40:07 -0700
Subject: [PATCH 07/39] merge
---
docker-compose.selenium.yml | 2 +-
docker-compose/run_selenium_tests_local_keybase.sh | 4 ++--
runtests.py | 3 ---
3 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/docker-compose.selenium.yml b/docker-compose.selenium.yml
index e6511767f..dcc28caa1 100755
--- a/docker-compose.selenium.yml
+++ b/docker-compose.selenium.yml
@@ -88,7 +88,7 @@ services:
- DJANGO_DEFAULT_SAMPLE_FHIR_ID="-20140000008325"
- DJANGO_SECURE_SESSION=False
- FHIR_URL="https://prod-sbx.bfd.cms.gov"
- - DJANGO_FHIR_CERTSTORE=/code/docker-compose/certstore/
+ - DJANGO_FHIR_CERTSTORE=${DJANGO_FHIR_CERTSTORE}
- DJANGO_MEDICARE_SLSX_REDIRECT_URI=${DJANGO_MEDICARE_SLSX_REDIRECT_URI}
- DJANGO_MEDICARE_SLSX_LOGIN_URI=${DJANGO_MEDICARE_SLSX_LOGIN_URI}
- DJANGO_SLSX_HEALTH_CHECK_ENDPOINT=${DJANGO_SLSX_HEALTH_CHECK_ENDPOINT}
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
index dbef6e1da..aaa36425c 100755
--- a/docker-compose/run_selenium_tests_local_keybase.sh
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -13,8 +13,7 @@
KEYBASE_ENV_FILE="team/bb20/infrastructure/creds/ENV_secrets_for_local_integration_tests.env"
KEYBASE_CERTFILES_SUBPATH="team/bb20/infrastructure/certs/local_integration_tests/fhir_client/certstore/"
-DJANGO_FHIR_CERTSTORE="/certstore"
-CERTSTORE_TEMPORARY_MOUNT_PATH="/tmp/certstore"
+CERTSTORE_TEMPORARY_MOUNT_PATH="./docker-compose/certstore"
CERT_FILENAME="client_data_server_bluebutton_local_integration_tests_certificate.pem"
KEY_FILENAME="client_data_server_bluebutton_local_integration_tests_private_key.pem"
@@ -45,6 +44,7 @@ TEST_TYPE="--selenium"
export USE_MSLSX=true
export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.dev"
+export DJANGO_FHIR_CERTSTORE="/code/docker-compose/certstore"
export DJANGO_MEDICARE_SLSX_REDIRECT_URI="http://bb2slsx:8000/mymedicare/sls-callback"
export DJANGO_MEDICARE_SLSX_LOGIN_URI="http://msls:8080/sso/authorize?client_id=bb2api"
diff --git a/runtests.py b/runtests.py
index 50cd6b5ab..336589bfa 100644
--- a/runtests.py
+++ b/runtests.py
@@ -18,12 +18,9 @@
--selenium This optional flag indicates tests are to run in selenium test mode.
Space separated list of Django tests to run.
-<<<<<<< HEAD
--logit This optional flag indicates tests are to run in logging integration test mode.
Space separated list of Django tests to run.
-=======
->>>>>>> origin/master
For example:
$ docker-compose exec web python runtests.py apps.dot_ext.tests
From b15130a758ebd124d8daf9fc0371d94a0ca628aa Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 27 Aug 2021 09:30:09 -0700
Subject: [PATCH 08/39] refactor test_logging settings, temp pull in cbc job
selenium pipeline to facilitate reviewing and verifying.
---
...insfile.cbc-run-multi-pr-checks-w-selenium | 130 ++++++++++++++++++
.../cbc-pod-deployment-config-w-selenium.yaml | 11 ++
hhs_oauth_server/settings/test_logging.py | 84 +++--------
3 files changed, 158 insertions(+), 67 deletions(-)
create mode 100755 Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
create mode 100755 Jenkinsfiles/cbc-pod-deployment-config-w-selenium.yaml
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
new file mode 100755
index 000000000..2348dd012
--- /dev/null
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -0,0 +1,130 @@
+pipeline {
+ agent {
+ kubernetes {
+ defaultContainer "bb2-cbc-build-selenium"
+ yamlFile "Jenkinsfiles/cbc-pod-deployment-config-w-selenium.yaml"
+ }
+ }
+
+ environment {
+ USE_MSLSX = true
+ USE_DEBUG = false
+ DJANGO_SLSX_VERIFY_SSL_INTERNAL = false
+ DJANGO_SLSX_VERIFY_SSL_EXTERNAL = false
+ DJANGO_LOG_JSON_FORMAT_PRETTY = true
+ DJANGO_SETTINGS_MODULE = "hhs_oauth_server.settings.dev"
+ OAUTHLIB_INSECURE_TRANSPORT = true
+ DJANGO_SECURE_SESSION = false
+ DJANGO_FHIR_CERTSTORE = "./certstore"
+ DJANGO_MEDICARE_SLSX_REDIRECT_URI = "http://localhost:8000/mymedicare/sls-callback"
+ DJANGO_MEDICARE_SLSX_LOGIN_URI = "http://localhost:8080/sso/authorize?client_id=bb2api"
+ DJANGO_SLSX_HEALTH_CHECK_ENDPOINT = "http://localhost:8080/health"
+ DJANGO_SLSX_TOKEN_ENDPOINT = "http://localhost:8080/sso/session"
+ DJANGO_SLSX_SIGNOUT_ENDPOINT = "http://localhost:8080/sso/signout"
+ DJANGO_SLSX_USERINFO_ENDPOINT = "http://localhost:8080/v1/users"
+ DJANGO_SLSX_CLIENT_ID = credentials("bb2-selenium-tests-slsx-client-id")
+ DJANGO_SLSX_CLIENT_SECRET = credentials("bb2-selenium-tests-slsx-client-secret")
+ DJANGO_USER_ID_ITERATIONS = credentials("bb2-integration-tests-bfd-iterations")
+ DJANGO_USER_ID_SALT = credentials("bb2-integration-tests-bfd-salt")
+ FHIR_CERT = credentials("bb2-integration-tests-bfd-cert")
+ FHIR_KEY = credentials("bb2-integration-tests-bfd-key")
+ FHIR_URL = "${params.FHIR_URL}"
+ }
+
+ parameters {
+ string(
+ name: 'FHIR_URL',
+ defaultValue: "https://prod-sbx.bfd.cms.gov",
+ description: 'The default FHIR URL for the back end BFD service.'
+ )
+ booleanParam(
+ name: 'RUN_SELENIUM_TESTS',
+ defaultValue: true,
+ description: 'Set to true, selenium tests will be run as part of integration tests'
+ )
+ }
+
+ stages {
+ stage("SETUP FHIR cert and key") {
+ steps {
+ writeFile(file: "${env.DJANGO_FHIR_CERTSTORE}/certstore/ca.cert.pem", text: readFile(env.FHIR_CERT))
+ writeFile(file: "${env.DJANGO_FHIR_CERTSTORE}/certstore/ca.key.nocrypt.pem", text: readFile(env.FHIR_KEY))
+ }
+ }
+
+ stage("INSTALL Python Packages") {
+ steps {
+ sh """
+ python -m venv venv
+ . venv/bin/activate
+ make reqs-install-dev
+ pip install selenium
+ """
+ }
+ }
+
+ stage("CHECK Flake8 Python Lint/Style") {
+ steps{
+ sh """
+ . venv/bin/activate
+ flake8
+ """
+ }
+ }
+
+ stage("RUN Django Unit Tests") {
+ steps{
+ sh """
+ . venv/bin/activate
+ python runtests.py
+ """
+ }
+ }
+
+ stage("START MSLSX in background") {
+ when {
+ expression { params.RUN_SELENIUM_TESTS == true }
+ }
+ steps{
+ sh """
+ . venv/bin/activate
+ cd dev-local && export DJANGO_SETTINGS_MODULE=mslsx_django.settings && python manage.py migrate && echo 'starting mslsx ...' && (python manage.py runserver 0.0.0.0:8080 &)
+ """
+ }
+ }
+
+ stage("START BB2 server in background") {
+ when {
+ expression { params.RUN_SELENIUM_TESTS == true }
+ }
+ steps{
+ sh """
+ . venv/bin/activate
+ export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.dev && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 &)
+ """
+ }
+ }
+
+ stage("RUN integration tests") {
+ steps{
+ sh """
+ . venv/bin/activate
+ python runtests.py --integration apps.integration_tests.integration_test_fhir_resources.IntegrationTestFhirApiResources
+ """
+ }
+ }
+
+ stage("RUN selenium tests") {
+ when {
+ expression { params.RUN_SELENIUM_TESTS == true }
+ }
+ steps{
+ sh """
+ . venv/bin/activate
+ python runtests.py --selenium apps.integration_tests.selenium_tests.SeleniumTests
+ """
+ }
+ }
+
+ }
+}
diff --git a/Jenkinsfiles/cbc-pod-deployment-config-w-selenium.yaml b/Jenkinsfiles/cbc-pod-deployment-config-w-selenium.yaml
new file mode 100755
index 000000000..b62af702e
--- /dev/null
+++ b/Jenkinsfiles/cbc-pod-deployment-config-w-selenium.yaml
@@ -0,0 +1,11 @@
+apiVersion: v1
+kind: Pod
+spec:
+ containers:
+ - name: bb2-cbc-build-selenium
+ image: "public.ecr.aws/f5g8o1y9/bb2-cbc-build-selenium:latest"
+ tty: true
+ command: ["tail", "-f"]
+ imagePullPolicy: Always
+ nodeSelector:
+ Agents: true
diff --git a/hhs_oauth_server/settings/test_logging.py b/hhs_oauth_server/settings/test_logging.py
index da344474a..d90642520 100755
--- a/hhs_oauth_server/settings/test_logging.py
+++ b/hhs_oauth_server/settings/test_logging.py
@@ -1,70 +1,20 @@
-from .test import *
+from .dev import *
# Use env-specific logging config if present
-LOGGING = env("DJANGO_LOGGING", {
- 'version': 1,
- 'disable_existing_loggers': False,
- 'formatters': {
- 'verbose': {
- 'format': '%(asctime)s %(levelname)s '
- '[%(process)d] %(name)s line:%(lineno)d %(message)s'
- },
- 'simple': {
- 'format': '%(asctime)s %(levelname)s %(name)s %(message)s'
- },
- 'jsonout': {
- 'format': '{"env": "' + env('TARGET_ENV', 'DEV') + '", "time": "%(asctime)s", "level": "%(levelname)s", '
- '"name": "%(name)s", "message": "%(message)s"}',
- 'datefmt': '%Y-%m-%d %H:%M:%S'
+# Add file handler.
+LOGGING['handlers']['file'] = {
+ 'class': 'logging.FileHandler',
+ 'filename': '/code/docker-compose/tmp/bb2_logging_test.log',
+}
- }
- },
- 'handlers': {
- 'console': {
- 'class': 'logging.StreamHandler',
- 'formatter': 'verbose',
- },
- 'file': {
- 'class': 'logging.FileHandler',
- 'filename': '/code/docker-compose/tmp/bb2_logging_test.log',
- },
- },
- 'loggers': {
- 'hhs_server': {
- 'handlers': ['console', 'file'],
- 'level': 'INFO',
- },
- 'hhs_oauth_server.accounts': {
- 'handlers': ['console'],
- 'level': 'INFO',
- },
- 'oauth2_provider': {
- 'handlers': ['console'],
- 'level': 'INFO',
- },
- 'oauthlib': {
- 'handlers': ['console'],
- 'level': 'INFO',
- },
- 'unsuccessful_logins': {
- 'handlers': ['console'],
- 'level': 'INFO',
- },
- 'admin_interface': {
- 'handlers': ['console'],
- 'level': 'INFO',
- },
- 'tests': {
- 'handlers': ['console'],
- 'level': 'DEBUG',
- },
- 'audit': {
- 'handlers': ['console', 'file'],
- 'level': 'INFO',
- },
- 'performance': {
- 'handlers': ['console'],
- 'level': 'INFO',
- }
- },
-})
+if LOGGING.get('loggers'):
+ # Update hhs_server logger
+ LOGGING.get['loggers']['hhs_server'] = {
+ 'handlers': ['console', 'file'],
+ 'level': 'INFO',
+ }
+ # Update audit logger
+ LOGGING['loggers']['audit'] = {
+ 'handlers': ['console', 'file'],
+ 'level': 'INFO',
+ }
From 8fe0aa522a9aeb9e14bca82367344cf070db5899 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Mon, 30 Aug 2021 15:12:10 -0700
Subject: [PATCH 09/39] refactor, hookup with selenium tests job.
---
.dockerignore | 7 +
Dockerfile.selenium | 2 +-
Dockerfiles/Dockerfile.jenkins | 20 ++
Dockerfiles/readme.md | 13 +
apps/fhir/server/authentication.py | 4 +-
.../integration_test_fhir_resources.py | 50 ++--
apps/integration_tests/selenium_tests.py | 20 +-
dev-local/manage.py | 21 ++
dev-local/msls/Dockerfile | 8 -
dev-local/msls/go.mod | 3 -
dev-local/msls/login_form.go | 71 -----
dev-local/msls/main.go | 279 ------------------
dev-local/mslsx_django/__init__.py | 0
dev-local/mslsx_django/settings.py | 121 ++++++++
dev-local/mslsx_django/templates/login.html | 75 +++++
dev-local/mslsx_django/urls.py | 20 ++
dev-local/mslsx_django/views.py | 164 ++++++++++
dev-local/mslsx_django/wsgi.py | 16 +
docker-compose.selenium.yml | 80 ++---
docker-compose.yml | 9 +-
docker-compose/readme.md | 25 +-
.../run_selenium_tests_local_keybase.sh | 36 ++-
hhs_oauth_server/settings/test_logging.py | 8 +-
runtests.py | 4 +-
24 files changed, 584 insertions(+), 472 deletions(-)
create mode 100755 .dockerignore
create mode 100755 Dockerfiles/Dockerfile.jenkins
create mode 100755 Dockerfiles/readme.md
create mode 100755 dev-local/manage.py
delete mode 100644 dev-local/msls/Dockerfile
delete mode 100644 dev-local/msls/go.mod
delete mode 100644 dev-local/msls/login_form.go
delete mode 100644 dev-local/msls/main.go
create mode 100755 dev-local/mslsx_django/__init__.py
create mode 100755 dev-local/mslsx_django/settings.py
create mode 100755 dev-local/mslsx_django/templates/login.html
create mode 100755 dev-local/mslsx_django/urls.py
create mode 100755 dev-local/mslsx_django/views.py
create mode 100755 dev-local/mslsx_django/wsgi.py
diff --git a/.dockerignore b/.dockerignore
new file mode 100755
index 000000000..684acecaf
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,7 @@
+# exclude when build image
+apidocs/
+splunk/
+bluebutton-css/
+apidocs/
+bluebutton-openapi-doc/
+*.sh
\ No newline at end of file
diff --git a/Dockerfile.selenium b/Dockerfile.selenium
index 25c601384..ad68b60cb 100755
--- a/Dockerfile.selenium
+++ b/Dockerfile.selenium
@@ -2,7 +2,7 @@ FROM selenium/standalone-chrome-debug
ENV PYTHONUNBUFFERED 1
USER root
-RUN apt-get update && apt-get install -yq python3.7 python3-pip
+RUN apt-get update && apt-get install -yq python3.7 python3-pip git
RUN pip3 install --upgrade pip
RUN pip3 install selenium psycopg2-binary==2.8.6 pyyaml==5.4.1 Pillow==8.3.1
RUN mkdir /code
diff --git a/Dockerfiles/Dockerfile.jenkins b/Dockerfiles/Dockerfile.jenkins
new file mode 100755
index 000000000..fd47b8f92
--- /dev/null
+++ b/Dockerfiles/Dockerfile.jenkins
@@ -0,0 +1,20 @@
+FROM python:3.7.10
+# For build CBC Jenkins job ECR image
+ENV PYTHONUNBUFFERED 1
+# ENV PYTHONDEVMODE 1
+
+RUN mkdir /code
+ADD . /code/
+WORKDIR /code
+
+RUN apt-get update && apt-get install -yq git unzip curl
+
+# Install Chrome for Selenium
+RUN curl https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o /chrome.deb \
+ && dpkg -i /chrome.deb || apt-get install -yf \
+ && rm /chrome.deb
+
+# Install chromedriver for Selenium
+RUN wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`/chromedriver_linux64.zip \
+ && unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/ \
+ && chmod +x /usr/local/bin/chromedriver
diff --git a/Dockerfiles/readme.md b/Dockerfiles/readme.md
new file mode 100755
index 000000000..4725b9872
--- /dev/null
+++ b/Dockerfiles/readme.md
@@ -0,0 +1,13 @@
+# Build, Tag, and Publish integration and selenium tests ECR iamge
+
+Go to BB2 local repo base directory and do the followings (assume aws cli installed and configured properly):
+
+```
+
+aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/f5g8o1y9
+cd /Dockerfiles
+docker build -f Dockerfile.jenkins -t bb2-cbc-build-selenium .
+docker tag bb2-cbc-build-selenium:latest public.ecr.aws/f5g8o1y9/bb2-cbc-build-selenium:latest
+docker push public.ecr.aws/f5g8o1y9/bb2-cbc-build-selenium:latest
+
+```
\ No newline at end of file
diff --git a/apps/fhir/server/authentication.py b/apps/fhir/server/authentication.py
index 816f7b483..89af9938c 100644
--- a/apps/fhir/server/authentication.py
+++ b/apps/fhir/server/authentication.py
@@ -4,12 +4,12 @@
from rest_framework import exceptions
from apps.dot_ext.loggers import get_session_auth_flow_trace
-from apps.fhir.bluebutton.utils import (generate_info_headers,
- set_default_header)
from apps.fhir.bluebutton.signals import (
pre_fetch,
post_fetch
)
+from apps.fhir.bluebutton.utils import (generate_info_headers,
+ set_default_header)
from ..bluebutton.exceptions import UpstreamServerException
from ..bluebutton.utils import (FhirServerAuth,
diff --git a/apps/integration_tests/integration_test_fhir_resources.py b/apps/integration_tests/integration_test_fhir_resources.py
index 40f84b6ef..5a4bd9e97 100644
--- a/apps/integration_tests/integration_test_fhir_resources.py
+++ b/apps/integration_tests/integration_test_fhir_resources.py
@@ -186,17 +186,20 @@ def test_health_external_endpoint_v2(self):
self._call_health_external_endpoint(True)
def _call_health_external_endpoint(self, v2=False):
- client = APIClient()
- # no authenticate needed
- response = client.get(self.live_server_url + "/health/external_v2" if v2 else "/health/external")
- self.assertEqual(response.status_code, 200)
- content = json.loads(response.content)
- msg = None
- try:
- msg = content['message']
- except KeyError:
- pass
- self.assertEqual(msg, "all's well")
+ use_mslsx = os.environ.get('USE_MSLSX', None)
+ if use_mslsx is not None and not use_mslsx == 'true':
+ # do not ping health end point if using MSLSX
+ client = APIClient()
+ # no authenticate needed
+ response = client.get(self.live_server_url + "/health/external_v2" if v2 else "/health/external")
+ self.assertEqual(response.status_code, 200)
+ content = json.loads(response.content)
+ msg = None
+ try:
+ msg = content['message']
+ except KeyError:
+ pass
+ self.assertEqual(msg, "all's well")
@override_switch('require-scopes', active=True)
def test_health_bfd_endpoint(self):
@@ -236,17 +239,20 @@ def test_health_db_endpoint(self):
@override_switch('require-scopes', active=True)
def test_health_sls_endpoint(self):
- client = APIClient()
- # no authenticate needed
- response = client.get(self.live_server_url + "/health/sls")
- self.assertEqual(response.status_code, 200)
- content = json.loads(response.content)
- msg = None
- try:
- msg = content['message']
- except KeyError:
- pass
- self.assertEqual(msg, "all's well")
+ use_mslsx = os.environ.get('USE_MSLSX', None)
+ if use_mslsx is not None and not use_mslsx == 'true':
+ # do not ping health end point if using MSLSX
+ client = APIClient()
+ # no authenticate needed
+ response = client.get(self.live_server_url + "/health/sls")
+ self.assertEqual(response.status_code, 200)
+ content = json.loads(response.content)
+ msg = None
+ try:
+ msg = content['message']
+ except KeyError:
+ pass
+ self.assertEqual(msg, "all's well")
@override_switch('require-scopes', active=True)
def test_userinfo_endpoint(self):
diff --git a/apps/integration_tests/selenium_tests.py b/apps/integration_tests/selenium_tests.py
index 95a9c7856..292675dfb 100755
--- a/apps/integration_tests/selenium_tests.py
+++ b/apps/integration_tests/selenium_tests.py
@@ -32,7 +32,7 @@ class SeleniumTests(TestCase):
def setUp(self):
super(SeleniumTests, self).setUp()
- # a bit waiting for selenium service ready for sure
+ # a bit waiting for selenium services ready for sure
if not SeleniumTests.wait_completed:
time.sleep(20)
SeleniumTests.wait_completed = True
@@ -40,8 +40,12 @@ def setUp(self):
else:
print("wait_completed={}".format(SeleniumTests.wait_completed))
+ self.use_mslsx = os.environ['USE_MSLSX']
+ self.use_debug = os.environ['USE_DEBUG']
+ self.login_seq = SEQ_LOGIN_MSLSX if self.use_mslsx == 'true' else SEQ_LOGIN_SLSX
+ print("use_mslsx={}, use_debug={}".format(self.use_mslsx, self.use_debug))
+
opt = webdriver.ChromeOptions()
- opt.add_argument('--headless')
opt.add_argument("--disable-dev-shm-usage")
opt.add_argument("--disable-web-security")
opt.add_argument("--allow-running-insecure-content")
@@ -54,9 +58,13 @@ def setUp(self):
opt.add_argument('--window-size=1920,1080')
opt.add_argument("--whitelisted-ips=''")
- self.driver = webdriver.Remote(
- command_executor='http://selenium-hub:4444',
- desired_capabilities=DesiredCapabilities.CHROME, options=opt)
+ if self.use_debug == 'true':
+ self.driver = webdriver.Remote(
+ command_executor='http://chrome:4444/wd/hub',
+ desired_capabilities=DesiredCapabilities.CHROME, options=opt)
+ else:
+ opt.add_argument('--headless')
+ self.driver = webdriver.Chrome(options=opt)
self.actions = {
Action.LOAD_PAGE: self._load_page,
@@ -70,8 +78,6 @@ def setUp(self):
Action.LOGIN: self._login,
Action.SLEEP: self._sleep,
}
- self.use_mslsx = os.environ['USE_MSLSX']
- self.login_seq = SEQ_LOGIN_MSLSX if self.use_mslsx == 'true' else SEQ_LOGIN_SLSX
def tearDown(self):
self.driver.quit()
diff --git a/dev-local/manage.py b/dev-local/manage.py
new file mode 100755
index 000000000..bca5b1fb7
--- /dev/null
+++ b/dev-local/manage.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mslsx_django.settings')
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/dev-local/msls/Dockerfile b/dev-local/msls/Dockerfile
deleted file mode 100644
index 38551e45e..000000000
--- a/dev-local/msls/Dockerfile
+++ /dev/null
@@ -1,8 +0,0 @@
-FROM golang:alpine
-
-WORKDIR /go/src/app
-COPY . .
-
-RUN go install -v .
-
-CMD ["app"]
diff --git a/dev-local/msls/go.mod b/dev-local/msls/go.mod
deleted file mode 100644
index 3bab48201..000000000
--- a/dev-local/msls/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module github.com/whytheplatypus/msls
-
-go 1.12
diff --git a/dev-local/msls/login_form.go b/dev-local/msls/login_form.go
deleted file mode 100644
index 66579ec77..000000000
--- a/dev-local/msls/login_form.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package main
-
-var login_template = `
-
-
-MSLSX Component Inputs for simulating SLSX/MyMedicare auth flow locally
-
-
-
Simulated Authentication no PHI or PII
-Use Only Synthetic Beneficiary Info
-Enter values to be returned by the SLSX user_info endpoint below:
-
-
-
-
-`
diff --git a/dev-local/msls/main.go b/dev-local/msls/main.go
deleted file mode 100644
index e69568bf4..000000000
--- a/dev-local/msls/main.go
+++ /dev/null
@@ -1,279 +0,0 @@
-package main
-
-import (
- "encoding/base64"
- "encoding/json"
- "fmt"
- "html/template"
- "log"
- "net/http"
- "net/http/httputil"
- "net/url"
- "strings"
-)
-
-/*
- accept regular endpoints and return sain responses
- match usernames and passwords, but as plain text
- 1. login screen
- 2. redirect with code
- 3. accept code post
- 4. return token
- 5. return info on userinfo endpoint
-
-
-MEDICARE_LOGIN_URI = env('DJANGO_MEDICARE_LOGIN_URI',
- 'https://dev2.account.mymedicare.gov/?scope=openid%20profile&client_id=bluebutton')
-MEDICARE_REDIRECT_URI = env(
- 'DJANGO_MEDICARE_REDIRECT_URI', 'http://localhost:8000/mymedicare/sls-callback')
-SLS_USERINFO_ENDPOINT = env(
- 'DJANGO_SLS_USERINFO_ENDPOINT', 'https://dev.accounts.cms.gov/v1/oauth/userinfo')
-SLS_TOKEN_ENDPOINT = env(
- 'DJANGO_SLS_TOKEN_ENDPOINT', 'https://dev.accounts.cms.gov/v1/oauth/token')
-
-MEDICARE_SLSX_LOGIN_URI=env('DJANGO_MEDICARE_SLSX_LOGIN_URI',
- 'https://test.medicare.gov/sso/authorize?client_id=bb2api')
-MEDICARE_SLSX_REDIRECT_URI=env('DJANGO_MEDICARE_SLSX_REDIRECT_URI',
- 'http://localhost:8000/mymedicare/sls-callback')
-SLSX_USERINFO_ENDPOINT=env('DJANGO_SLSX_USERINFO_ENDPOINT', 'https://test.accounts.cms.gov/v1/users')
-SLSX_TOKEN_ENDPOINT=env('DJANGO_SLSX_TOKEN_ENDPOINT', 'https://test.medicare.gov/sso/session')
-
-SLSX exchange for auth_token:
-
-{
-"auth_token":"6yemAjHlDCa15RxXXNr15hfd/Q6Uvcc11KbgXhp/AgrJ",
-"role":"consumer",
-"user_id":"0854b569-5d28-4aa7-9878-fccdb15b4ffc",
-"session_id":"36106cbd6982479c8c1dce52d8fb1588"}'
-
-
-Sample SLSX response:
-
-{
- "status": "ok",
- "code": 200,
- "data": {
- "user": {
- "id": "0854b569-5d28-4aa7-9878-fccdb15b4ffc",
- "username": "BbUser10000",
- "email": null,
- "firstName": null,
- "middleName": null,
- "lastName": null,
- "suffix": null,
- "dateOfBirth": null,
- "ssn": null,
- "city": null,
- "state": null,
- "addressLine1": null,
- "addressLine2": null,
- "zipcode": null,
- "zipcodeExtension": null,
- "phoneNumber": null,
- "challenges": null,
- "webBrokerInfo": null,
- "isManuallyDisabled": false,
- "requiresConfirm": null,
- "loa": 0,
- "loaAdminReason": null,
- "lastLoginTime": 1617920826,
- "createdTime": 1594071993,
- "updatedTime": 1617920826,
- "hicn": "1000087197",
- "passwordExpirationTime": 1680992826,
- "isDisabled": false,
- "customUserInfo": {
- "mbi": "2S17E00AA00"
- },
- "mbi": "2S17E00AA00"
- }
- }
- }
-
-
- */
-
-var signed_in = true
-
-const (
- ID_FIELD = "id"
- USERNAME_FIELD = "username"
- NAME_FIELD = "name"
- EMAIL_FIELD = "email"
- FIRST_NAME_FIELD = "fisrt_name"
- LAST_NAME_FIELD = "last_name"
- HICN_FIELD = "hicn"
- MBI_FIELD = "mbi"
- CODE_KEY = "code"
- AUTH_HEADER = "Authorization"
-)
-
-func logRequest(w http.Handler) http.Handler {
- return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
- v, err := httputil.DumpRequest(r, true)
- log.Printf("%q : %s", v, err)
- w.ServeHTTP(rw, r)
- })
-}
-
-func main() {
- t := template.Must(template.New("loginpage").Parse(login_template))
- http.Handle("/", logRequest(presentLogin(t)))
-
- http.Handle("/health", logRequest(http.HandlerFunc(handleHealth)))
- http.Handle("/login", logRequest(http.HandlerFunc(handleLogin)))
- http.Handle("/sso/session", logRequest(http.HandlerFunc(handleCode)))
- http.Handle("/sso/signout", logRequest(http.HandlerFunc(handleSignout)))
- http.Handle("/v1/users/", logRequest(http.HandlerFunc(handleUserinfo)))
- http.ListenAndServe(":8080", nil)
-}
-
-func handleCode(rw http.ResponseWriter, r *http.Request) {
- body := &struct {
- Code string `json:"request_token"`
- }{}
-
- // Try to decode the request body into the struct. If there is an error,
- // respond to the client with the error message and a 400 status code.
- err := json.NewDecoder(r.Body).Decode(body)
- if err != nil {
- http.Error(rw, err.Error(), http.StatusBadRequest)
- return
- }
-
- tkn := code(body.Code)
-
- user_info := tkn.userinfo()
-
- token := map[string]string{
- "user_id": user_info.Sub,
- "auth_token": body.Code,
- }
-
- log.Println(token)
- rw.Header().Set("Content-Type", "application/json")
- json.NewEncoder(rw).Encode(token)
-}
-
-func handleHealth(rw http.ResponseWriter, r *http.Request) {
- all_is_well := map[string]string{
- "message": "all's well",
- }
- json.NewEncoder(rw).Encode(all_is_well)
-}
-
-func handleSignout(rw http.ResponseWriter, r *http.Request) {
- rw.WriteHeader(http.StatusFound)
-}
-
-func handleUserinfo(rw http.ResponseWriter, r *http.Request) {
- if signed_in == true {
- tkn := code(strings.Split(r.Header.Get(AUTH_HEADER), " ")[1])
- user_info := tkn.userinfo()
- slsx_userinfo := map[string]map[string]map[string]string{
- "data": {
- "user": {
- "id": user_info.Sub,
- "username": user_info.Name,
- "email": user_info.Email,
- "firstName": user_info.First_name,
- "lastName": user_info.Last_name,
- "hicn": user_info.Hicn,
- "mbi": user_info.Mbi,
- },
- },
- }
- signed_in = false
- json.NewEncoder(rw).Encode(slsx_userinfo)
- } else {
- signed_in = true
- rw.WriteHeader(http.StatusForbidden)
- }
-}
-
-func presentLogin(t *template.Template) http.Handler {
- return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
- rw.Header().Set("Content-Type", "text/html; charset=utf-8")
- r.ParseForm()
- t.Execute(rw, r.Form)
- })
-}
-
-func handleLogin(rw http.ResponseWriter, r *http.Request) {
- code := login(r)
- // redirect with the state, and code
- u, err := url.Parse(r.FormValue("redirect_uri"))
- if err != nil {
- http.Error(rw, err.Error(), http.StatusInternalServerError)
- return
- }
-
- q := u.Query()
- q.Add("req_token", string(code))
- q.Add("relay", r.FormValue("relay"))
-
- u.RawQuery = q.Encode()
-
- http.Redirect(rw, r, u.String(), http.StatusFound)
-}
-
-func login(r *http.Request) code {
- usr := r.FormValue(USERNAME_FIELD)
- name := r.FormValue(NAME_FIELD)
- first_name := r.FormValue(FIRST_NAME_FIELD)
- last_name := r.FormValue(LAST_NAME_FIELD)
- email := r.FormValue(EMAIL_FIELD)
- hicn := r.FormValue(HICN_FIELD)
- mbi := r.FormValue(MBI_FIELD)
-
- return encode(usr, name, first_name, last_name, email, hicn, mbi)
-}
-
-type code string
-
-func (c code) userinfo() *userinfo {
- usr, name, first_name, last_name, email, hicn, mbi := decode(string(c))
- return &userinfo{
- Sub: usr,
- Name: name,
- First_name: first_name,
- Last_name: last_name,
- Email: email,
- Hicn: hicn,
- Mbi: mbi,
- }
-}
-
-func decode(c string) (string, string, string, string, string, string, string) {
- d_usr, _ := base64.RawURLEncoding.DecodeString(strings.Split(c, ".")[0])
- d_name, _ := base64.RawURLEncoding.DecodeString(strings.Split(c, ".")[1])
- d_first_name, _ := base64.RawURLEncoding.DecodeString(strings.Split(c, ".")[2])
- d_last_name, _ := base64.RawURLEncoding.DecodeString(strings.Split(c, ".")[3])
- d_email, _ := base64.RawURLEncoding.DecodeString(strings.Split(c, ".")[4])
- d_hicn, _ := base64.RawURLEncoding.DecodeString(strings.Split(c, ".")[5])
- d_mbi, _ := base64.RawURLEncoding.DecodeString(strings.Split(c, ".")[6])
- return string(d_usr), string(d_name), string(d_first_name), string(d_last_name),
- string(d_email), string(d_hicn), string(d_mbi)
-}
-
-func encode(usr, name, first_name, last_name, email, hicn, mbi string) code {
- e_usr := base64.RawURLEncoding.EncodeToString([]byte(usr))
- e_name := base64.RawURLEncoding.EncodeToString([]byte(name))
- e_first_name := base64.RawURLEncoding.EncodeToString([]byte(first_name))
- e_last_name := base64.RawURLEncoding.EncodeToString([]byte(last_name))
- e_email := base64.RawURLEncoding.EncodeToString([]byte(email))
- e_hicn := base64.RawURLEncoding.EncodeToString([]byte(hicn))
- e_mbi := base64.RawURLEncoding.EncodeToString([]byte(mbi))
- return code(fmt.Sprintf("%s.%s.%s.%s.%s.%s.%s", e_usr, e_name, e_first_name,
- e_last_name, e_email, e_hicn, e_mbi))
-}
-
-type userinfo struct {
- Sub string `json:"sub"`
- Name string `json:"name"`
- First_name string `json:"first_name"`
- Last_name string `json:"last_name"`
- Email string `json:"email"`
- Hicn string `json:"hicn"`
- Mbi string `json:"mbi"`
-}
diff --git a/dev-local/mslsx_django/__init__.py b/dev-local/mslsx_django/__init__.py
new file mode 100755
index 000000000..e69de29bb
diff --git a/dev-local/mslsx_django/settings.py b/dev-local/mslsx_django/settings.py
new file mode 100755
index 000000000..1e779961f
--- /dev/null
+++ b/dev-local/mslsx_django/settings.py
@@ -0,0 +1,121 @@
+"""
+Django settings for mslsx_django project.
+
+Generated by 'django-admin startproject' using Django 2.2.13.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/2.2/ref/settings/
+"""
+
+import os
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = '9iq6l*3n7-ljq#wc-fz496#2ri*zdt2skq!4f$!lx@dt8-!t8='
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = ["msls", "localhost", "127.0.0.1"]
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'mslsx_django',
+]
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'mslsx_django.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'mslsx_django.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.2/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.2/howto/static-files/
+
+STATIC_URL = '/static/'
diff --git a/dev-local/mslsx_django/templates/login.html b/dev-local/mslsx_django/templates/login.html
new file mode 100755
index 000000000..842f3199b
--- /dev/null
+++ b/dev-local/mslsx_django/templates/login.html
@@ -0,0 +1,75 @@
+
+
+ MSLSX Login
+
+
+
+
+ MSLSX Component Inputs for simulating SLSX/MyMedicare auth flow locally
+
+
+
Simulated Authentication no PHI or PII
+ Use Only Synthetic Beneficiary Info
+ Enter values to be returned by the SLSX user_info endpoint below:
+
+
+
+
+
+
diff --git a/dev-local/mslsx_django/urls.py b/dev-local/mslsx_django/urls.py
new file mode 100755
index 000000000..bd28a9d12
--- /dev/null
+++ b/dev-local/mslsx_django/urls.py
@@ -0,0 +1,20 @@
+from django.conf.urls import url
+
+from .views import (
+ login_page,
+ login,
+ token,
+ userinfo,
+ signout,
+ health,
+)
+
+urlpatterns = [
+ # mslsx end points
+ url(r'^sso/authorize\\?.+', login_page),
+ url(r'^login/', login),
+ url(r'^health', health),
+ url(r'^sso/session', token),
+ url(r'^v1/users/', userinfo),
+ url(r'^sso/signout', signout),
+]
diff --git a/dev-local/mslsx_django/views.py b/dev-local/mslsx_django/views.py
new file mode 100755
index 000000000..fa41e0e05
--- /dev/null
+++ b/dev-local/mslsx_django/views.py
@@ -0,0 +1,164 @@
+import json
+import base64
+
+from django.shortcuts import render, HttpResponse, redirect
+from django.views.decorators.csrf import csrf_exempt
+from urllib.parse import urlencode
+
+
+signed_in = True
+
+ENCODE_NAME = "ascii"
+
+ID_FIELD = "id"
+USERNAME_FIELD = "username"
+NAME_FIELD = "name"
+EMAIL_FIELD = "email"
+FIRST_NAME_FIELD = "fisrt_name"
+LAST_NAME_FIELD = "last_name"
+HICN_FIELD = "hicn"
+MBI_FIELD = "mbi"
+CODE_KEY = "code"
+AUTH_HEADER = "Authorization"
+
+
+def _base64_encode(string):
+ """
+ Removes any `=` used as padding from the encoded string.
+ """
+ encoded = base64.urlsafe_b64encode(string)
+ return encoded.rstrip(b"=")
+
+
+def _base64_decode(string):
+ """
+ Adds back in the required padding before decoding.
+ """
+ padding = 4 - (len(string) % 4)
+ string = string + ("=" * padding)
+ return base64.urlsafe_b64decode(string)
+
+
+def _encode(usr="", name="", first_name="", last_name="", email="", hicn="", mbi=""):
+ return "{}.{}.{}.{}.{}.{}.{}".format(_base64_encode(usr.encode(ENCODE_NAME)).decode(ENCODE_NAME),
+ _base64_encode(name.encode(ENCODE_NAME)).decode(ENCODE_NAME),
+ _base64_encode(first_name.encode(ENCODE_NAME)).decode(ENCODE_NAME),
+ _base64_encode(last_name.encode(ENCODE_NAME)).decode(ENCODE_NAME),
+ _base64_encode(email.encode(ENCODE_NAME)).decode(ENCODE_NAME),
+ _base64_encode(hicn.encode(ENCODE_NAME)).decode(ENCODE_NAME),
+ _base64_encode(mbi.encode(ENCODE_NAME)).decode(ENCODE_NAME))
+
+
+def _decode(b64code):
+ flds = b64code.split(".")
+ return {
+ "usr": _base64_decode(flds[0]).decode(ENCODE_NAME),
+ "name": _base64_decode(flds[1]).decode(ENCODE_NAME),
+ "first_name": _base64_decode(flds[2]).decode(ENCODE_NAME),
+ "last_name": _base64_decode(flds[3]).decode(ENCODE_NAME),
+ "email": _base64_decode(flds[4]).decode(ENCODE_NAME),
+ "hicn": _base64_decode(flds[5]).decode(ENCODE_NAME),
+ "mbi": _base64_decode(flds[6]).decode(ENCODE_NAME),
+ }
+
+
+def login_page(request):
+ '''
+ response with login form
+ '''
+ return render(request, 'login.html', {
+ "relay": request.GET.get("relay", "missing"),
+ "redirect_uri": request.GET.get("redirect_uri", "missing"),
+ })
+
+
+def login(request):
+ '''
+ process login form POST, collect sub, mbi, hicn, etc.
+ '''
+
+ redirect_url = request.POST.get("redirect_uri", None)
+
+ req_token = _encode(request.POST.get(USERNAME_FIELD, ""),
+ request.POST.get(NAME_FIELD, ""),
+ request.POST.get(FIRST_NAME_FIELD, ""),
+ request.POST.get(LAST_NAME_FIELD, ""),
+ request.POST.get(EMAIL_FIELD, ""),
+ request.POST.get(HICN_FIELD, ""),
+ request.POST.get(MBI_FIELD, ""))
+
+ qparams = {
+ "req_token": req_token,
+ "relay": request.POST.get("relay", "")
+ }
+ print("redirect={}?{}".format(redirect_url, urlencode(qparams)))
+ return redirect("{}?{}".format(redirect_url, urlencode(qparams)))
+
+
+def health(request):
+ '''
+ always good
+ '''
+ return HttpResponse(json.dumps({"message": "all's well"}),
+ status=200, content_type='application/json')
+
+
+@csrf_exempt
+def token(request):
+ '''
+ grant access token to further get userinfo
+ '''
+ body_unicode = request.body.decode('utf-8')
+ body = json.loads(body_unicode)
+ request_token = body.get("request_token", None)
+
+ if request_token is None:
+ return HttpResponse(json.dumps({"message": "Bad Request, missing request token."}),
+ status=400, content_type='application/json')
+
+ user_info = _decode(request_token)
+
+ token = {
+ "user_id": user_info['usr'],
+ "auth_token": request_token,
+ }
+
+ return HttpResponse(json.dumps(token), status=200, content_type='application/json')
+
+
+def userinfo(request):
+
+ global signed_in
+
+ if signed_in is True:
+ tkn = request.headers.get(AUTH_HEADER, None)
+ if tkn is None:
+ return HttpResponse(json.dumps({"message": "Bad Request, missing request token."}),
+ status=400, content_type='application/json')
+ if not tkn.startswith("Bearer "):
+ return HttpResponse(json.dumps({"message": "Bad Request, malformed bearer token."}),
+ status=400, content_type='application/json')
+ tkn = tkn.split()[1]
+ user_info = _decode(tkn)
+ slsx_userinfo = {
+ "data": {
+ "user": {
+ "id": user_info["usr"],
+ "username": user_info["name"],
+ "email": user_info["email"],
+ "firstName": user_info["first_name"],
+ "lastName": user_info["last_name"],
+ "hicn": user_info["hicn"],
+ "mbi": user_info["mbi"],
+ },
+ },
+ }
+ signed_in = False
+ return HttpResponse(json.dumps(slsx_userinfo), status=200, content_type='application/json')
+ else:
+ signed_in = True
+ return HttpResponse(status=403, content_type='application/json')
+
+
+def signout(request):
+ return HttpResponse(status=302, content_type='application/json')
diff --git a/dev-local/mslsx_django/wsgi.py b/dev-local/mslsx_django/wsgi.py
new file mode 100755
index 000000000..dea691653
--- /dev/null
+++ b/dev-local/mslsx_django/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for mslsx_django project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mslsx_django.settings')
+
+application = get_wsgi_application()
diff --git a/docker-compose.selenium.yml b/docker-compose.selenium.yml
index dcc28caa1..9861107b6 100755
--- a/docker-compose.selenium.yml
+++ b/docker-compose.selenium.yml
@@ -9,6 +9,21 @@ services:
environment:
- HOSTNAME_URL=${HOSTNAME_URL}
- USE_MSLSX=${USE_MSLSX}
+ - USE_DEBUG=${USE_DEBUG}
+ volumes:
+ - .:/code
+ depends_on:
+ - bb2slsx
+
+ tests-debug:
+ build:
+ context: ./
+ dockerfile: Dockerfile.selenium
+ command: python runtests.py apps.integration_tests.selenium_tests.SeleniumTests
+ environment:
+ - HOSTNAME_URL=${HOSTNAME_URL}
+ - USE_MSLSX=${USE_MSLSX}
+ - USE_DEBUG=${USE_DEBUG}
volumes:
- .:/code
depends_on:
@@ -16,67 +31,28 @@ services:
- chrome
chrome:
- image: selenium/node-chrome:4.0.0-beta-4-prerelease-20210517
- volumes:
- - /dev/shm:/dev/shm
- depends_on:
- - selenium-hub
- environment:
- - SE_EVENT_BUS_HOST=selenium-hub
- - SE_EVENT_BUS_PUBLISH_PORT=4442
- - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- ports:
- - "6900:5900"
-
- # edge:
- # image: selenium/node-edge:4.0.0-beta-4-prerelease-20210517
- # volumes:
- # - /dev/shm:/dev/shm
- # depends_on:
- # - selenium-hub
- # environment:
- # - SE_EVENT_BUS_HOST=selenium-hub
- # - SE_EVENT_BUS_PUBLISH_PORT=4442
- # - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- # ports:
- # - "6901:5900"
-
- # firefox:
- # image: selenium/node-firefox:4.0.0-beta-4-prerelease-20210517
- # volumes:
- # - /dev/shm:/dev/shm
- # depends_on:
- # - selenium-hub
- # environment:
- # - SE_EVENT_BUS_HOST=selenium-hub
- # - SE_EVENT_BUS_PUBLISH_PORT=4442
- # - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
- # ports:
- # - "6902:5900"
-
- selenium-hub:
- image: selenium/hub:4.0.0-beta-4-prerelease-20210517
- container_name: selenium-hub
+ image: selenium/standalone-chrome-debug
+ hostname: chrome
ports:
- - "4442:4442"
- - "4443:4443"
- "4444:4444"
+ - "5900:5900"
msls:
- build:
- context: ./dev-local/msls
- dockerfile: Dockerfile
- command: msls
+ build: .
+ command: bash -c "cd dev-local ; python manage.py migrate ; python3 -m debugpy --listen 0.0.0.0:7890 manage.py runserver 0.0.0.0:8080 --noreload"
+ environment:
+ - DJANGO_SETTINGS_MODULE=mslsx_django.settings
ports:
- - "8080:8080"
-
+ - "8080:8080"
+ - "7890:7890"
+
db:
image: postgres
environment:
- - POSTGRES_DB=bluebutton
- - POSTGRES_PASSWORD=toor
+ - POSTGRES_DB=bluebutton
+ - POSTGRES_PASSWORD=toor
ports:
- - "5432:5432"
+ - "5432:5432"
bb2slsx:
build: .
diff --git a/docker-compose.yml b/docker-compose.yml
index 5d1d7f318..0d43ba406 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,12 +2,13 @@ version: '3'
services:
msls:
- build:
- context: ./dev-local/msls
- dockerfile: Dockerfile
- command: msls
+ build: .
+ command: bash -c "cd dev-local ; python manage.py migrate ; python3 -m debugpy --listen 0.0.0.0:7890 manage.py runserver 0.0.0.0:8080 --noreload"
+ environment:
+ - DJANGO_SETTINGS_MODULE=mslsx_django.settings
ports:
- "8080:8080"
+ - "7890:7890"
db:
image: postgres
environment:
diff --git a/docker-compose/readme.md b/docker-compose/readme.md
index 967b5ea83..7e876abd3 100644
--- a/docker-compose/readme.md
+++ b/docker-compose/readme.md
@@ -349,15 +349,20 @@ You can run selenium tests by following below steps:
./docker-compose/run_selenium_tests_local_keybase.sh slsx
```
- 3. To trouble shoot tests (visualize webUI interaction): point VNC client to localhost:6900
+ 3. To debug tests (visualize webUI interaction): point VNC client to localhost:5900
1. requires installation of vnc viewer, password (secret)
- 2. also need to comment out webdriver headless option, as shown below:
- ```
- ./apps/integration_tests/selenium_tests.py: setUp():
- ...
- opt = webdriver.ChromeOptions()
- opt.add_argument('--headless')
- opt.add_argument("--disable-dev-shm-usage")
- ...
- ```
+ 2. Start tests using -debug parameter as shown below:
+ use MSLSX (default)
+ ```
+ ./docker-compose/run_selenium_tests_local_keybase.sh debug
+ ```
+
+ ```
+ ./docker-compose/run_selenium_tests_local_keybase.sh mslsx-debug
+ ```
+
+ use SLSX
+ ```
+ ./docker-compose/run_selenium_tests_local_keybase.sh slsx-debug
+ ```
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
index 7208e4d63..6d597c4d0 100755
--- a/docker-compose/run_selenium_tests_local_keybase.sh
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -13,7 +13,9 @@
KEYBASE_ENV_FILE="team/bb20/infrastructure/creds/ENV_secrets_for_local_integration_tests.env"
KEYBASE_CERTFILES_SUBPATH="team/bb20/infrastructure/certs/local_integration_tests/fhir_client/certstore/"
-CERTSTORE_TEMPORARY_MOUNT_PATH="./docker-compose/certstore"
+export CERTSTORE_TEMPORARY_MOUNT_PATH="./docker-compose/certstore"
+export DJANGO_FHIR_CERTSTORE="/code/docker-compose/certstore"
+
CERT_FILENAME="client_data_server_bluebutton_local_integration_tests_certificate.pem"
KEY_FILENAME="client_data_server_bluebutton_local_integration_tests_private_key.pem"
@@ -43,6 +45,7 @@ set -e -u -o pipefail
TEST_TYPE="--selenium"
export USE_MSLSX=true
+export USE_DEBUG=false
export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.dev"
export DJANGO_FHIR_CERTSTORE="/code/docker-compose/certstore"
@@ -58,7 +61,7 @@ if [ $# -eq 0 ]
then
echo "Use MSLSX for identity service."
else
- if [[ $1 != "slsx" && $1 != "mslsx" && $1 != "logit" ]]
+ if [[ $1 != "slsx" && $1 != "mslsx" && $1 != "slsx-debug" && $1 != "mslsx-debug" && $1 != "debug" && $1 != "logit" ]]
then
echo
echo "COMMAND USAGE HELP"
@@ -66,15 +69,25 @@ else
echo
echo " Use one of the following command line options for the type of test to run:"
echo
- echo " logit = run integration tests for bb2 loggings, MSLSX used as identity service."
+ echo " slsx = use SLSX for identity service with webdriver in headless mode."
+ echo
+ echo " slsx-debug = use SLSX for identity service, and start selenium standalone chrome debug mode (visualized browser interactions)."
+ echo
+ echo " mslsx (default) = use MSLSX for identity service with webdriver in headless mode."
+ echo
+ echo " mslsx-debug = use MSLSX for identity service with selenium chrome standalone debug mode."
echo
- echo " slsx = use SLSX for identity service."
+ echo " debug = same as 'mslsx-debug'"
echo
- echo " mslsx (default) = use MSLSX for identity service."
+ echo " logit = run integration tests for bb2 loggings, MSLSX used as identity service."
echo
exit 1
else
- if [ $1 == "slsx" ]
+ if [[ $1 == *debug ]]
+ then
+ export USE_DEBUG=true
+ fi
+ if [[ $1 == "slsx" || $1 == "slsx-debug" ]]
then
export USE_MSLSX=false
export DJANGO_MEDICARE_SLSX_REDIRECT_URI="http://bb2slsx:8000/mymedicare/sls-callback"
@@ -84,7 +97,7 @@ else
export DJANGO_SLSX_SIGNOUT_ENDPOINT="https://test.medicare.gov/sso/signout"
export DJANGO_SLSX_USERINFO_ENDPOINT="https://test.accounts.cms.gov/v1/users"
fi
- if [ $1 == "logit" ]
+ if [[ $1 == "logit" ]]
then
TEST_TYPE="--logit"
TESTS_LIST="apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging"
@@ -205,8 +218,15 @@ export DJANGO_SLSX_CLIENT_ID=${DJANGO_SLSX_CLIENT_ID}
export DJANGO_SLSX_CLIENT_SECRET=${DJANGO_SLSX_CLIENT_SECRET}
echo "Selenium tests ..."
+echo "MSLSX=" ${USE_MSLSX}
+echo "DEBUG=" ${USE_DEBUG}
-docker-compose -f docker-compose.selenium.yml run tests bash -c "python runtests.py ${TEST_TYPE} ${TESTS_LIST}"
+if [ "$USE_DEBUG" = true ]
+then
+ docker-compose -f docker-compose.selenium.yml run tests-debug bash -c "python runtests.py ${TEST_TYPE} ${TESTS_LIST}"
+else
+ docker-compose -f docker-compose.selenium.yml run tests bash -c "python runtests.py ${TEST_TYPE} ${TESTS_LIST}"
+fi
# Stop containers after use
echo_msg
diff --git a/hhs_oauth_server/settings/test_logging.py b/hhs_oauth_server/settings/test_logging.py
index d90642520..90674693f 100755
--- a/hhs_oauth_server/settings/test_logging.py
+++ b/hhs_oauth_server/settings/test_logging.py
@@ -7,14 +7,16 @@
'filename': '/code/docker-compose/tmp/bb2_logging_test.log',
}
-if LOGGING.get('loggers'):
+loggers = LOGGING.get('loggers')
+
+if loggers:
# Update hhs_server logger
- LOGGING.get['loggers']['hhs_server'] = {
+ loggers['hhs_server'] = {
'handlers': ['console', 'file'],
'level': 'INFO',
}
# Update audit logger
- LOGGING['loggers']['audit'] = {
+ loggers['audit'] = {
'handlers': ['console', 'file'],
'level': 'INFO',
}
diff --git a/runtests.py b/runtests.py
index 336589bfa..291630c06 100644
--- a/runtests.py
+++ b/runtests.py
@@ -50,7 +50,7 @@
# Unset ENV variables for integration type tests so default values get set.
for env_var in ['DJANGO_MEDICARE_SLSX_LOGIN_URI', 'DJANGO_MEDICARE_SLSX_REDIRECT_URI',
'DJANGO_SLSX_USERINFO_ENDPOINT', 'DJANGO_SLSX_TOKEN_ENDPOINT',
- 'DJANGO_SLSX_HEALTH_CHECK_ENDPOINT',
+ 'DJANGO_SLSX_HEALTH_CHECK_ENDPOINT', "DJANGO_SLSX_SIGNOUT_ENDPOINT",
'DATABASES_CUSTOM', 'DJANGO_LOG_JSON_FORMAT_PRETTY']:
if env_var in os.environ:
del os.environ[env_var]
@@ -59,7 +59,7 @@
# Unset ENV variables for Django unit type tests so default values get set.
for env_var in ['FHIR_URL', 'DJANGO_MEDICARE_SLSX_LOGIN_URI', 'DJANGO_MEDICARE_SLSX_REDIRECT_URI',
'DJANGO_SLSX_USERINFO_ENDPOINT', 'DJANGO_SLSX_TOKEN_ENDPOINT',
- 'DJANGO_SLSX_HEALTH_CHECK_ENDPOINT',
+ 'DJANGO_SLSX_HEALTH_CHECK_ENDPOINT', "DJANGO_SLSX_SIGNOUT_ENDPOINT",
'DJANGO_FHIR_CERTSTORE', 'DATABASES_CUSTOM', 'DJANGO_LOG_JSON_FORMAT_PRETTY',
'DJANGO_USER_ID_ITERATIONS', 'DJANGO_USER_ID_SALT']:
if env_var in os.environ:
From c53cfb3a34f9600007f6ef3d4ba268cbe34f2d2d Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Mon, 30 Aug 2021 16:02:43 -0700
Subject: [PATCH 10/39] fix linting.
---
apps/integration_tests/integration_test_fhir_resources.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/apps/integration_tests/integration_test_fhir_resources.py b/apps/integration_tests/integration_test_fhir_resources.py
index 5a4bd9e97..25e4a5717 100644
--- a/apps/integration_tests/integration_test_fhir_resources.py
+++ b/apps/integration_tests/integration_test_fhir_resources.py
@@ -1,4 +1,5 @@
import json
+import os
from django.conf import settings
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
From 807cea4befb68f3cf881e0dc2dd1f915a1d63065 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Tue, 31 Aug 2021 10:58:59 -0700
Subject: [PATCH 11/39] simplify audit logging redirect.
---
apps/integration_tests/logging_tests.py | 8 ++++++++
hhs_oauth_server/settings/test_logging.py | 22 ----------------------
runtests.py | 4 ++--
3 files changed, 10 insertions(+), 24 deletions(-)
delete mode 100755 hhs_oauth_server/settings/test_logging.py
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index 65d662af7..af234c562 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -1,6 +1,7 @@
import copy
import json
import re
+import logging
from json.decoder import JSONDecodeError
@@ -196,6 +197,13 @@ def _validate_events(self):
self.assertEqual(len(expected_events), 0)
def test_auth_fhir_flows_logging(self):
+ # direct relevant log records to the file
+ audit_logger = logging.getLogger("audit")
+ file_handler = logging.FileHandler(TEST_LOGGING_FILE)
+ for h in audit_logger.handlers[:]:
+ audit_logger.removeHandler(h)
+ audit_logger.addHandler(file_handler)
+ audit_logger.setLevel(logging.INFO)
self.test_auth_grant_fhir_calls_v1()
print("validating logging events in log...")
self._validate_events()
diff --git a/hhs_oauth_server/settings/test_logging.py b/hhs_oauth_server/settings/test_logging.py
deleted file mode 100755
index 90674693f..000000000
--- a/hhs_oauth_server/settings/test_logging.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from .dev import *
-
-# Use env-specific logging config if present
-# Add file handler.
-LOGGING['handlers']['file'] = {
- 'class': 'logging.FileHandler',
- 'filename': '/code/docker-compose/tmp/bb2_logging_test.log',
-}
-
-loggers = LOGGING.get('loggers')
-
-if loggers:
- # Update hhs_server logger
- loggers['hhs_server'] = {
- 'handlers': ['console', 'file'],
- 'level': 'INFO',
- }
- # Update audit logger
- loggers['audit'] = {
- 'handlers': ['console', 'file'],
- 'level': 'INFO',
- }
diff --git a/runtests.py b/runtests.py
index 291630c06..be2401bbf 100644
--- a/runtests.py
+++ b/runtests.py
@@ -66,10 +66,10 @@
del os.environ[env_var]
if __name__ == '__main__':
- if not args.logit:
+ if not args.selenium and not args.logit:
os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.test'
else:
- os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.test_logging'
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.dev'
django.setup()
TestRunner = get_runner(settings)
test_runner = TestRunner()
From 2ac4a3fc9fa99c114cecfff4b827e96e76c7ff30 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Wed, 1 Sep 2021 15:47:29 -0700
Subject: [PATCH 12/39] cleanup.
---
apps/integration_tests/logging_tests.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index af234c562..f492b06ee 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -197,7 +197,6 @@ def _validate_events(self):
self.assertEqual(len(expected_events), 0)
def test_auth_fhir_flows_logging(self):
- # direct relevant log records to the file
audit_logger = logging.getLogger("audit")
file_handler = logging.FileHandler(TEST_LOGGING_FILE)
for h in audit_logger.handlers[:]:
From 77e95457fb93c7009fd6f6b4cee4c751f8430490 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 3 Sep 2021 20:35:42 -0700
Subject: [PATCH 13/39] add logging integration tests to cbc job pipeline.
---
...insfile.cbc-run-multi-pr-checks-w-selenium | 16 +++++++++++--
apps/integration_tests/logging_tests.py | 7 ------
.../run_selenium_tests_local_keybase.sh | 24 +++++++++----------
hhs_oauth_server/settings/logging_it.py | 20 ++++++++++++++++
runtests.py | 11 ++-------
5 files changed, 47 insertions(+), 31 deletions(-)
create mode 100755 hhs_oauth_server/settings/logging_it.py
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 2348dd012..4849e9169 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -11,7 +11,7 @@ pipeline {
USE_DEBUG = false
DJANGO_SLSX_VERIFY_SSL_INTERNAL = false
DJANGO_SLSX_VERIFY_SSL_EXTERNAL = false
- DJANGO_LOG_JSON_FORMAT_PRETTY = true
+ DJANGO_LOG_JSON_FORMAT_PRETTY = false
DJANGO_SETTINGS_MODULE = "hhs_oauth_server.settings.dev"
OAUTHLIB_INSECURE_TRANSPORT = true
DJANGO_SECURE_SESSION = false
@@ -100,7 +100,19 @@ pipeline {
steps{
sh """
. venv/bin/activate
- export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.dev && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 &)
+ export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.logging_it && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 &)
+ """
+ }
+ }
+
+ stage("RUN logging integration tests") {
+ when {
+ expression { params.RUN_SELENIUM_TESTS == true }
+ }
+ steps{
+ sh """
+ . venv/bin/activate
+ python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
"""
}
}
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index f492b06ee..65d662af7 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -1,7 +1,6 @@
import copy
import json
import re
-import logging
from json.decoder import JSONDecodeError
@@ -197,12 +196,6 @@ def _validate_events(self):
self.assertEqual(len(expected_events), 0)
def test_auth_fhir_flows_logging(self):
- audit_logger = logging.getLogger("audit")
- file_handler = logging.FileHandler(TEST_LOGGING_FILE)
- for h in audit_logger.handlers[:]:
- audit_logger.removeHandler(h)
- audit_logger.addHandler(file_handler)
- audit_logger.setLevel(logging.INFO)
self.test_auth_grant_fhir_calls_v1()
print("validating logging events in log...")
self._validate_events()
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
index 6d597c4d0..9907c2a53 100755
--- a/docker-compose/run_selenium_tests_local_keybase.sh
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -42,8 +42,6 @@ echo_msg
# Set bash builtins for safety
set -e -u -o pipefail
-TEST_TYPE="--selenium"
-
export USE_MSLSX=true
export USE_DEBUG=false
export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.dev"
@@ -99,9 +97,8 @@ else
fi
if [[ $1 == "logit" ]]
then
- TEST_TYPE="--logit"
TESTS_LIST="apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging"
- export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.test_logging"
+ export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.logging_it"
export DJANGO_LOG_JSON_FORMAT_PRETTY=False
mkdir -p docker-compose/tmp
if [ -f docker-compose/tmp/bb2_logging_test.log ]
@@ -114,7 +111,6 @@ fi
echo "DJANGO_SETTINGS_MODULE: " ${DJANGO_SETTINGS_MODULE}
echo "HOSTNAME_URL: " ${HOSTNAME_URL}
-echo "TEST_TYPE: " ${TEST_TYPE}
echo "TESTS: " ${TESTS_LIST}
# Set KeyBase ENV path based on your type of system
@@ -217,17 +213,19 @@ export DJANGO_PASSWORD_HASH_ITERATIONS=${DJANGO_PASSWORD_HASH_ITERATIONS}
export DJANGO_SLSX_CLIENT_ID=${DJANGO_SLSX_CLIENT_ID}
export DJANGO_SLSX_CLIENT_SECRET=${DJANGO_SLSX_CLIENT_SECRET}
-echo "Selenium tests ..."
-echo "MSLSX=" ${USE_MSLSX}
-echo "DEBUG=" ${USE_DEBUG}
-
-if [ "$USE_DEBUG" = true ]
+TEST_SERVICE_NAME="tests"
+if [[ "$USE_DEBUG" = true ]]
then
- docker-compose -f docker-compose.selenium.yml run tests-debug bash -c "python runtests.py ${TEST_TYPE} ${TESTS_LIST}"
-else
- docker-compose -f docker-compose.selenium.yml run tests bash -c "python runtests.py ${TEST_TYPE} ${TESTS_LIST}"
+ TEST_SERVICE_NAME="tests-debug"
fi
+echo "Selenium tests ..."
+echo "MSLSX =" ${USE_MSLSX}
+echo "DEBUG =" ${USE_DEBUG}
+echo "DOCKER COMPOSE TEST SERVICE NAME =" ${TEST_SERVICE_NAME}
+
+docker-compose -f docker-compose.selenium.yml run ${TEST_SERVICE_NAME} bash -c "python runtests.py --selenium ${TESTS_LIST}"
+
# Stop containers after use
echo_msg
echo_msg "Stopping containers..."
diff --git a/hhs_oauth_server/settings/logging_it.py b/hhs_oauth_server/settings/logging_it.py
new file mode 100755
index 000000000..9b0b328f5
--- /dev/null
+++ b/hhs_oauth_server/settings/logging_it.py
@@ -0,0 +1,20 @@
+from .dev import *
+
+# Override audit logging handler with a file handler
+logging_handlers = LOGGING['handlers']
+
+if logging_handlers is None:
+ raise ValueError("Bad settings, expecting handlers defined in settings.LOGGING")
+
+logging_handlers['file'] = {'class': 'logging.FileHandler',
+ 'filename': '/code/docker-compose/tmp/bb2_logging_test.log', }
+
+loggers = LOGGING.get('loggers')
+
+if loggers:
+ logging_logger_audit_handlers = LOGGING['loggers']['audit']['handlers']
+
+ if logging_logger_audit_handlers is None:
+ raise ValueError("Bad settings, expecting handlers defined in settings.LOGGING for 'audit' logger")
+
+ logging_logger_audit_handlers.append('file')
diff --git a/runtests.py b/runtests.py
index be2401bbf..1eafd0402 100644
--- a/runtests.py
+++ b/runtests.py
@@ -18,9 +18,6 @@
--selenium This optional flag indicates tests are to run in selenium test mode.
Space separated list of Django tests to run.
- --logit This optional flag indicates tests are to run in logging integration test mode.
- Space separated list of Django tests to run.
-
For example:
$ docker-compose exec web python runtests.py apps.dot_ext.tests
@@ -42,7 +39,6 @@
parser = argparse.ArgumentParser()
parser.add_argument('--integration', help='Integration tests mode', action='store_true')
parser.add_argument('--selenium', help='Selenium tests mode', action='store_true')
-parser.add_argument('--logit', help='Logging tests mode (use selenium as driver)', action='store_true')
parser.add_argument('test', nargs='*')
args = parser.parse_args()
@@ -54,7 +50,7 @@
'DATABASES_CUSTOM', 'DJANGO_LOG_JSON_FORMAT_PRETTY']:
if env_var in os.environ:
del os.environ[env_var]
-elif not args.selenium and not args.logit:
+elif not args.selenium:
# For tests using selenium, inherit SLSX config from context;
# Unset ENV variables for Django unit type tests so default values get set.
for env_var in ['FHIR_URL', 'DJANGO_MEDICARE_SLSX_LOGIN_URI', 'DJANGO_MEDICARE_SLSX_REDIRECT_URI',
@@ -66,10 +62,7 @@
del os.environ[env_var]
if __name__ == '__main__':
- if not args.selenium and not args.logit:
- os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.test'
- else:
- os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.dev'
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'hhs_oauth_server.settings.test'
django.setup()
TestRunner = get_runner(settings)
test_runner = TestRunner()
From eea26f9b42c8e7240bff8043c739af390e761521 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 3 Sep 2021 20:59:17 -0700
Subject: [PATCH 14/39] fix log file path.
---
hhs_oauth_server/settings/logging_it.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hhs_oauth_server/settings/logging_it.py b/hhs_oauth_server/settings/logging_it.py
index 9b0b328f5..4117e60b3 100755
--- a/hhs_oauth_server/settings/logging_it.py
+++ b/hhs_oauth_server/settings/logging_it.py
@@ -7,7 +7,7 @@
raise ValueError("Bad settings, expecting handlers defined in settings.LOGGING")
logging_handlers['file'] = {'class': 'logging.FileHandler',
- 'filename': '/code/docker-compose/tmp/bb2_logging_test.log', }
+ 'filename': './docker-compose/tmp/bb2_logging_test.log', }
loggers = LOGGING.get('loggers')
From b8f649079f5ff937174c20db9ae9072897bd6463 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 3 Sep 2021 21:12:09 -0700
Subject: [PATCH 15/39] remove print.
---
dev-local/mslsx_django/views.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/dev-local/mslsx_django/views.py b/dev-local/mslsx_django/views.py
index fa41e0e05..c59745cd3 100755
--- a/dev-local/mslsx_django/views.py
+++ b/dev-local/mslsx_django/views.py
@@ -91,7 +91,6 @@ def login(request):
"req_token": req_token,
"relay": request.POST.get("relay", "")
}
- print("redirect={}?{}".format(redirect_url, urlencode(qparams)))
return redirect("{}?{}".format(redirect_url, urlencode(qparams)))
From 6b9a98abdff7fbad1d7fca43c74759fca1817faf Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 3 Sep 2021 21:31:55 -0700
Subject: [PATCH 16/39] create audit logger file handler path.
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 4849e9169..881a13f95 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -100,7 +100,7 @@ pipeline {
steps{
sh """
. venv/bin/activate
- export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.logging_it && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 &)
+ export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.logging_it && mkdir -p docker-compose/tmp && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 &)
"""
}
}
From d3d2a1f868c94f28ff0c7e61b085c9e846fbf3ba Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 3 Sep 2021 22:47:53 -0700
Subject: [PATCH 17/39] trace logging.
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 1 +
1 file changed, 1 insertion(+)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 881a13f95..7570b8411 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -112,6 +112,7 @@ pipeline {
steps{
sh """
. venv/bin/activate
+ ls -al ./docker-compose/tmp
python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
"""
}
From 6c0c2d72bd8e692611da4f798c63af89f649545c Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 3 Sep 2021 23:26:27 -0700
Subject: [PATCH 18/39] trace
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 1 +
1 file changed, 1 insertion(+)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 7570b8411..a7641a9ba 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -113,6 +113,7 @@ pipeline {
sh """
. venv/bin/activate
ls -al ./docker-compose/tmp
+ find . -name "bb2_logging_test.log"
python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
"""
}
From f123d1f50688c7d364fceb354dda3b6c3686155f Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 3 Sep 2021 23:46:05 -0700
Subject: [PATCH 19/39] trace
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index a7641a9ba..cb5dc58f0 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -100,7 +100,8 @@ pipeline {
steps{
sh """
. venv/bin/activate
- export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.logging_it && mkdir -p docker-compose/tmp && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 &)
+ pwd
+ export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.logging_it && mkdir -p docker-compose/tmp && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 > bb2.log 2>&1 &)
"""
}
}
@@ -112,8 +113,11 @@ pipeline {
steps{
sh """
. venv/bin/activate
+ ls -al .
ls -al ./docker-compose/tmp
find . -name "bb2_logging_test.log"
+ pwd
+ cat ./bb2.log
python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
"""
}
From 8b00a95ea9cea5ff94247c3b20321a43523acce8 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 10:00:41 -0700
Subject: [PATCH 20/39] fix file handler.
---
hhs_oauth_server/settings/logging_it.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/hhs_oauth_server/settings/logging_it.py b/hhs_oauth_server/settings/logging_it.py
index 4117e60b3..1c77336a1 100755
--- a/hhs_oauth_server/settings/logging_it.py
+++ b/hhs_oauth_server/settings/logging_it.py
@@ -3,11 +3,13 @@
# Override audit logging handler with a file handler
logging_handlers = LOGGING['handlers']
+logfile_path = os.path.abspath(os.getcwd() + "/docker-compose/tmp/bb2_logging_test.log")
+
if logging_handlers is None:
raise ValueError("Bad settings, expecting handlers defined in settings.LOGGING")
logging_handlers['file'] = {'class': 'logging.FileHandler',
- 'filename': './docker-compose/tmp/bb2_logging_test.log', }
+ 'filename': logfile_path, }
loggers = LOGGING.get('loggers')
From bc2d352f2008c0b688934bd4ff2b1f77b5959481 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 11:53:24 -0700
Subject: [PATCH 21/39] fix logger file handler.
---
.../Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 8 +-------
apps/integration_tests/logging_tests.py | 1 -
docker-compose/run_selenium_tests_local_keybase.sh | 5 -----
hhs_oauth_server/settings/logging_it.py | 12 ++++++++++++
4 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index cb5dc58f0..4849e9169 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -100,8 +100,7 @@ pipeline {
steps{
sh """
. venv/bin/activate
- pwd
- export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.logging_it && mkdir -p docker-compose/tmp && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 > bb2.log 2>&1 &)
+ export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.logging_it && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 &)
"""
}
}
@@ -113,11 +112,6 @@ pipeline {
steps{
sh """
. venv/bin/activate
- ls -al .
- ls -al ./docker-compose/tmp
- find . -name "bb2_logging_test.log"
- pwd
- cat ./bb2.log
python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
"""
}
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index 65d662af7..1da54aad9 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -167,7 +167,6 @@ class LoggingTests(SeleniumTests):
the driver (selenium)
'''
def _validate_events(self):
- # validate middleware logging records in log file ./docker-compose/tmp/bb2_logging_test.log
with open(TEST_LOGGING_FILE, 'r') as f:
log_records = f.readlines()
start_validation = False
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
index 9907c2a53..6b2774234 100755
--- a/docker-compose/run_selenium_tests_local_keybase.sh
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -100,11 +100,6 @@ else
TESTS_LIST="apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging"
export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.logging_it"
export DJANGO_LOG_JSON_FORMAT_PRETTY=False
- mkdir -p docker-compose/tmp
- if [ -f docker-compose/tmp/bb2_logging_test.log ]
- then
- rm -f docker-compose/tmp/bb2_logging_test.log
- fi
fi
fi
fi
diff --git a/hhs_oauth_server/settings/logging_it.py b/hhs_oauth_server/settings/logging_it.py
index 1c77336a1..bd88a1da9 100755
--- a/hhs_oauth_server/settings/logging_it.py
+++ b/hhs_oauth_server/settings/logging_it.py
@@ -4,6 +4,18 @@
logging_handlers = LOGGING['handlers']
logfile_path = os.path.abspath(os.getcwd() + "/docker-compose/tmp/bb2_logging_test.log")
+logdir_path = os.path.abspath(os.getcwd() + "/docker-compose/tmp/")
+
+try:
+ # remove left over just in case
+ os.remove(logfile_path)
+except FileNotFoundError as err:
+ print("Error removing left over log file: {}".format(err))
+
+try:
+ os.mkdir(logdir_path)
+except FileExistsError as err:
+ print("Error os.mkdir: {}".format(err))
if logging_handlers is None:
raise ValueError("Bad settings, expecting handlers defined in settings.LOGGING")
From e8ef516eceb94d4b4014deaa7b880614abd59779 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 12:20:47 -0700
Subject: [PATCH 22/39] temp comment out logging integration tests from
pipeline.
---
...insfile.cbc-run-multi-pr-checks-w-selenium | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 4849e9169..400921c17 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -105,17 +105,17 @@ pipeline {
}
}
- stage("RUN logging integration tests") {
- when {
- expression { params.RUN_SELENIUM_TESTS == true }
- }
- steps{
- sh """
- . venv/bin/activate
- python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
- """
- }
- }
+ // stage("RUN logging integration tests") {
+ // when {
+ // expression { params.RUN_SELENIUM_TESTS == true }
+ // }
+ // steps{
+ // sh """
+ // . venv/bin/activate
+ // python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
+ // """
+ // }
+ // }
stage("RUN integration tests") {
steps{
From 52e3c8cdf72471003d0257154b15be03f3e4de02 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 13:04:51 -0700
Subject: [PATCH 23/39] trace
---
hhs_oauth_server/settings/logging_it.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/hhs_oauth_server/settings/logging_it.py b/hhs_oauth_server/settings/logging_it.py
index bd88a1da9..77549ed33 100755
--- a/hhs_oauth_server/settings/logging_it.py
+++ b/hhs_oauth_server/settings/logging_it.py
@@ -31,4 +31,10 @@
if logging_logger_audit_handlers is None:
raise ValueError("Bad settings, expecting handlers defined in settings.LOGGING for 'audit' logger")
+ print("------------ append file handler------------")
logging_logger_audit_handlers.append('file')
+ print("------------ LOGGING begin ------------")
+ print("{}".format(LOGGING))
+ print("------------ LOGGING end ------------")
+else:
+ print("------------ no loggers found ------------")
From 7d8196fe8d0438bb2a6b4799e53c9524e349ecd6 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 13:35:39 -0700
Subject: [PATCH 24/39] trace
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 400921c17..2bd4af8f9 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -100,7 +100,7 @@ pipeline {
steps{
sh """
. venv/bin/activate
- export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.logging_it && python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (python manage.py runserver 0.0.0.0:8000 &)
+ python manage.py migrate && python manage.py create_admin_groups && python manage.py loaddata scopes.json && python manage.py create_blue_button_scopes && python manage.py create_test_user_and_application && python manage.py create_user_identification_label_selection && python manage.py create_test_feature_switches && (if [ ! -d 'bluebutton-css' ] ; then git clone https://github.com/CMSgov/bluebutton-css.git ; else echo 'CSS already installed.' ; fi) && echo 'starting bb2...' && (export DJANGO_SETTINGS_MODULE=hhs_oauth_server.settings.logging_it && python manage.py runserver 0.0.0.0:8000 &)
"""
}
}
From b726c24cb2d84b9ff58e9aae43a49ff7d3d3d282 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 13:49:10 -0700
Subject: [PATCH 25/39] trace
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 1 +
1 file changed, 1 insertion(+)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 2bd4af8f9..5966855d1 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -133,6 +133,7 @@ pipeline {
steps{
sh """
. venv/bin/activate
+ ls -al .
python runtests.py --selenium apps.integration_tests.selenium_tests.SeleniumTests
"""
}
From 2e1877de23883a5cd26112a054577d67d425e689 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 14:23:57 -0700
Subject: [PATCH 26/39] trace
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 5966855d1..c4a7bdce9 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -133,7 +133,8 @@ pipeline {
steps{
sh """
. venv/bin/activate
- ls -al .
+ ls -al docker-compose/tmp
+ cat docker-compose/tmp/bb2_logging_test.log
python runtests.py --selenium apps.integration_tests.selenium_tests.SeleniumTests
"""
}
From 8d96d3802b20eab36cdf690c216efbf51ccc05b5 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 14:59:22 -0700
Subject: [PATCH 27/39] trace
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 1 +
1 file changed, 1 insertion(+)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index c4a7bdce9..4a9d2e2cd 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -136,6 +136,7 @@ pipeline {
ls -al docker-compose/tmp
cat docker-compose/tmp/bb2_logging_test.log
python runtests.py --selenium apps.integration_tests.selenium_tests.SeleniumTests
+ cat docker-compose/tmp/bb2_logging_test.log
"""
}
}
From d4e661ca6e15707f4b00a963682942dc420adcdf Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 17:54:26 -0700
Subject: [PATCH 28/39] trace
---
...insfile.cbc-run-multi-pr-checks-w-selenium | 25 ++++++++-----------
1 file changed, 11 insertions(+), 14 deletions(-)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 4a9d2e2cd..e4d02d4ad 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -105,17 +105,17 @@ pipeline {
}
}
- // stage("RUN logging integration tests") {
- // when {
- // expression { params.RUN_SELENIUM_TESTS == true }
- // }
- // steps{
- // sh """
- // . venv/bin/activate
- // python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
- // """
- // }
- // }
+ stage("RUN logging integration tests") {
+ when {
+ expression { params.RUN_SELENIUM_TESTS == true }
+ }
+ steps{
+ sh """
+ . venv/bin/activate
+ python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
+ """
+ }
+ }
stage("RUN integration tests") {
steps{
@@ -133,10 +133,7 @@ pipeline {
steps{
sh """
. venv/bin/activate
- ls -al docker-compose/tmp
- cat docker-compose/tmp/bb2_logging_test.log
python runtests.py --selenium apps.integration_tests.selenium_tests.SeleniumTests
- cat docker-compose/tmp/bb2_logging_test.log
"""
}
}
From dfa79ddf2d2d85eeb4c918ec29dc22e73708739b Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 19:51:58 -0700
Subject: [PATCH 29/39] trace
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 1 +
apps/integration_tests/logging_tests.py | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index e4d02d4ad..dbaece830 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -113,6 +113,7 @@ pipeline {
sh """
. venv/bin/activate
python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
+ cat docker-compose/tmp/bb2_logging_test.log
"""
}
}
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index 1da54aad9..caaaed55d 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -192,7 +192,7 @@ def _validate_events(self):
pass
# all log events present and validated
- self.assertEqual(len(expected_events), 0)
+ # self.assertEqual(len(expected_events), 0)
def test_auth_fhir_flows_logging(self):
self.test_auth_grant_fhir_calls_v1()
From 8d69bb34b544edf69d02d5aab184014cc2a4357b Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Sat, 4 Sep 2021 20:41:54 -0700
Subject: [PATCH 30/39] turn off pretty json in logging.
---
apps/integration_tests/logging_tests.py | 2 +-
hhs_oauth_server/settings/logging_it.py | 8 ++------
2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index caaaed55d..1da54aad9 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -192,7 +192,7 @@ def _validate_events(self):
pass
# all log events present and validated
- # self.assertEqual(len(expected_events), 0)
+ self.assertEqual(len(expected_events), 0)
def test_auth_fhir_flows_logging(self):
self.test_auth_grant_fhir_calls_v1()
diff --git a/hhs_oauth_server/settings/logging_it.py b/hhs_oauth_server/settings/logging_it.py
index 77549ed33..12c813a5c 100755
--- a/hhs_oauth_server/settings/logging_it.py
+++ b/hhs_oauth_server/settings/logging_it.py
@@ -31,10 +31,6 @@
if logging_logger_audit_handlers is None:
raise ValueError("Bad settings, expecting handlers defined in settings.LOGGING for 'audit' logger")
- print("------------ append file handler------------")
logging_logger_audit_handlers.append('file')
- print("------------ LOGGING begin ------------")
- print("{}".format(LOGGING))
- print("------------ LOGGING end ------------")
-else:
- print("------------ no loggers found ------------")
+
+LOG_JSON_FORMAT_PRETTY = False
From 91651219a99fce57fe2fd869ade8f37434332eaa Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Thu, 16 Sep 2021 19:44:05 -0700
Subject: [PATCH 31/39] sync up with Pillow ver bump.
---
Dockerfile.selenium | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Dockerfile.selenium b/Dockerfile.selenium
index ad68b60cb..7b35180ac 100755
--- a/Dockerfile.selenium
+++ b/Dockerfile.selenium
@@ -4,7 +4,7 @@ ENV PYTHONUNBUFFERED 1
USER root
RUN apt-get update && apt-get install -yq python3.7 python3-pip git
RUN pip3 install --upgrade pip
-RUN pip3 install selenium psycopg2-binary==2.8.6 pyyaml==5.4.1 Pillow==8.3.1
+RUN pip3 install selenium psycopg2-binary==2.8.6 pyyaml==5.4.1 Pillow==8.3.2
RUN mkdir /code
ADD . /code/
WORKDIR /code
From 5e5fa70f3af7d4ab25befb1f85230523179cbc7e Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Tue, 5 Oct 2021 16:10:51 -0700
Subject: [PATCH 32/39] print schema to facilitate debugging.
---
apps/integration_tests/logging_tests.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index 1da54aad9..a89668667 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -186,6 +186,7 @@ def _validate_events(self):
self.assertTrue(re.match(event_desc.get('path_regex'), p))
else:
self.assertEqual(p, event_desc.get('path'))
+ print("SCHEMA={}".format(event_desc.get('schema')))
self.assertTrue(validate_json_schema(event_desc.get('schema'), event_json))
except JSONDecodeError:
# skip non json line
From b16dd8e2458811d239b0de8bdedbf4eaa7bc15ca Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Tue, 5 Oct 2021 16:22:17 -0700
Subject: [PATCH 33/39] print schema to facilitate debugging.
---
apps/integration_tests/logging_tests.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index a89668667..04665e847 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -182,11 +182,11 @@ def _validate_events(self):
start_validation = True
else:
event_desc = expected_events.pop(0)
+ print("SCHEMA={}".format(event_desc.get('schema')))
if event_desc.get('path_regex') is not None:
self.assertTrue(re.match(event_desc.get('path_regex'), p))
else:
self.assertEqual(p, event_desc.get('path'))
- print("SCHEMA={}".format(event_desc.get('schema')))
self.assertTrue(validate_json_schema(event_desc.get('schema'), event_json))
except JSONDecodeError:
# skip non json line
From a1607cf0a79519669bbf2de568f60d5e88d234f5 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Wed, 6 Oct 2021 07:55:25 -0700
Subject: [PATCH 34/39] relax attr check for crosswalk type, for runing under
local(mslsx) vs remote(slsx) .
---
Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium | 1 -
apps/integration_tests/log_event_schemas.py | 6 +++---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
index 7435946f3..38d18aecf 100755
--- a/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
+++ b/Jenkinsfiles/Jenkinsfile.cbc-run-multi-pr-checks-w-selenium
@@ -99,7 +99,6 @@ pipeline {
sh """
. venv/bin/activate
python runtests.py --selenium apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging
- cat docker-compose/tmp/bb2_logging_test.log
"""
}
}
diff --git a/apps/integration_tests/log_event_schemas.py b/apps/integration_tests/log_event_schemas.py
index 2ab982155..b40359730 100755
--- a/apps/integration_tests/log_event_schemas.py
+++ b/apps/integration_tests/log_event_schemas.py
@@ -136,7 +136,7 @@
"auth_client_id": {"type": "string"},
"auth_app_id": {"type": "string"},
"auth_app_name": {"pattern": "TestApp"},
- "auth_crosswalk_action": {"pattern": "R"},
+ "auth_crosswalk_action": {"enum": ["R", "C"]},
"auth_require_demographic_scopes": {"pattern": "^True$"},
"req_user_id": {"type": "number"},
"req_user_username": {"pattern": "fred"},
@@ -169,7 +169,7 @@
"auth_client_id": {"type": "string"},
"auth_app_id": {"type": "string"},
"auth_app_name": {"pattern": "TestApp"},
- "auth_crosswalk_action": {"pattern": "R"},
+ "auth_crosswalk_action": {"enum": ["R", "C"]},
"auth_require_demographic_scopes": {"pattern": "^True$"},
"req_qparam_client_id": {"type": "string"},
"req_qparam_response_type": {"pattern": "code"},
@@ -204,7 +204,7 @@
"auth_client_id": {"type": "string"},
"auth_app_id": {"type": "string"},
"auth_app_name": {"pattern": "TestApp"},
- "auth_crosswalk_action": {"pattern": "R"},
+ "auth_crosswalk_action": {"enum": ["R", "C"]},
"auth_require_demographic_scopes": {"pattern": "^True$"},
"req_redirect_uri": {"type": "string"},
"req_scope": {"type": "string"},
From 1b14c71379ad253fd1492d52c988c0f7c3d7d777 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Wed, 6 Oct 2021 08:52:54 -0700
Subject: [PATCH 35/39] cleanup and fix schema checking.
---
apps/integration_tests/log_event_schemas.py | 20 ++++++++++----------
apps/integration_tests/logging_tests.py | 1 -
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/apps/integration_tests/log_event_schemas.py b/apps/integration_tests/log_event_schemas.py
index b40359730..1d900becb 100755
--- a/apps/integration_tests/log_event_schemas.py
+++ b/apps/integration_tests/log_event_schemas.py
@@ -139,7 +139,7 @@
"auth_crosswalk_action": {"enum": ["R", "C"]},
"auth_require_demographic_scopes": {"pattern": "^True$"},
"req_user_id": {"type": "number"},
- "req_user_username": {"pattern": "fred"},
+ "req_user_username": {"type": "string"},
"req_fhir_id": {"type": "string"},
"path": {"pattern": "/mymedicare/sls-callback"},
"user": {"type": "string"},
@@ -211,7 +211,7 @@
"req_share_demographic_scopes": {"pattern": "^True$"},
"req_allow": {"pattern": "Allow"},
"req_user_id": {"type": "integer"},
- "req_user_username": {"pattern": "fred"},
+ "req_user_username": {"type": "string"},
"req_fhir_id": {"type": "string"},
"req_qparam_client_id": {"type": "string"},
"req_qparam_response_type": {"pattern": "code"},
@@ -308,7 +308,7 @@
"request_scheme": {"pattern": "http"},
"response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
"req_user_id": {"type": "integer"},
- "req_user_username": {"pattern": "fred"},
+ "req_user_username": {"type": "string"},
"req_fhir_id": {"type": "string"},
"req_qparam_format": {"pattern": "json"},
"req_qparam_patient": {"type": "string"},
@@ -320,7 +320,7 @@
"access_token_id": {"type": "number"},
"app_require_demographic_scopes": {"type": "boolean"},
"user_id": {"type": "integer"},
- "user_username": {"pattern": "fred"},
+ "user_username": {"type": "string"},
"fhir_bundle_type": {"pattern": "searchset|null"},
"fhir_resource_id": {"type": "string"},
"fhir_resource_type": {"pattern": "Bundle|Patient|Coverage|ExplanationOfBenefit"},
@@ -350,7 +350,7 @@
"request_scheme": {"pattern": "http"},
"response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
"req_user_id": {"type": "integer"},
- "req_user_username": {"pattern": "fred"},
+ "req_user_username": {"type": "string"},
"req_fhir_id": {"type": "string"},
"req_qparam__count": {"type": "string"},
"req_qparam_format": {"pattern": "json"},
@@ -364,7 +364,7 @@
"access_token_id": {"type": "number"},
"app_require_demographic_scopes": {"type": "boolean"},
"user_id": {"type": "integer"},
- "user_username": {"pattern": "fred"},
+ "user_username": {"type": "string"},
"fhir_bundle_type": {"pattern": "searchset|null"},
"fhir_resource_id": {"type": "string"},
"fhir_resource_type": {"pattern": "Bundle|Patient|Coverage|ExplanationOfBenefit"},
@@ -395,7 +395,7 @@
"request_scheme": {"pattern": "http"},
"response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
"req_user_id": {"type": "integer"},
- "req_user_username": {"pattern": "fred"},
+ "req_user_username": {"type": "string"},
"req_fhir_id": {"type": "string"},
"path": {"pattern": "/v1/fhir/.+"},
"user": {"type": "string"},
@@ -404,7 +404,7 @@
"access_token_id": {"type": "number"},
"app_require_demographic_scopes": {"type": "boolean"},
"user_id": {"type": "integer"},
- "user_username": {"pattern": "fred"},
+ "user_username": {"type": "string"},
"fhir_bundle_type": {"pattern": "searchset|null"},
"fhir_resource_id": {"type": "string"},
"fhir_resource_type": {"pattern": "Bundle|Patient|Coverage|ExplanationOfBenefit"},
@@ -434,7 +434,7 @@
"request_scheme": {"pattern": "http"},
"response_code": {"type": "integer", "enum": [status.HTTP_200_OK]},
"req_user_id": {"type": "integer"},
- "req_user_username": {"pattern": "fred"},
+ "req_user_username": {"type": "string"},
"req_fhir_id": {"type": "string"},
"path": {"pattern": "/v1/connect/userinfo"},
"user": {"type": "string"},
@@ -443,7 +443,7 @@
"access_token_id": {"type": "number"},
"app_require_demographic_scopes": {"type": "boolean"},
"user_id": {"type": "integer"},
- "user_username": {"pattern": "fred"},
+ "user_username": {"type": "string"},
},
"required": ["type", "size", "start_time", "end_time", "ip_addr", "request_uuid",
"request_method", "request_scheme", "response_code",
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index 04665e847..1da54aad9 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -182,7 +182,6 @@ def _validate_events(self):
start_validation = True
else:
event_desc = expected_events.pop(0)
- print("SCHEMA={}".format(event_desc.get('schema')))
if event_desc.get('path_regex') is not None:
self.assertTrue(re.match(event_desc.get('path_regex'), p))
else:
From 3c95cd94804f51368fb8edd02ec714ec4efb9039 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Wed, 6 Oct 2021 09:48:47 -0700
Subject: [PATCH 36/39] cleanup and fix path validation.
---
apps/integration_tests/logging_tests.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/integration_tests/logging_tests.py b/apps/integration_tests/logging_tests.py
index 1da54aad9..620012865 100755
--- a/apps/integration_tests/logging_tests.py
+++ b/apps/integration_tests/logging_tests.py
@@ -80,7 +80,7 @@
},
{
"schema": LOG_MIDDLEWARE_FHIR_READ_EVENT_SCHEMA,
- "path": "/v1/fhir/Patient/-20140000008325"
+ "path_regex": "/v1/fhir/Patient/-20140000008325|/v1/fhir/Patient/-19990000000001"
},
{
"schema": LOG_MIDDLEWARE_TESTCLIENT_FHIR_READ_EVENT_SCHEMA,
From f045a7b905abdd39b23b81f9b843d0bdefe540be Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 8 Oct 2021 08:51:31 -0700
Subject: [PATCH 37/39] changes per review, remove django mslsx.
---
dev-local/manage.py | 21 ---
dev-local/mslsx_django/__init__.py | 0
dev-local/mslsx_django/settings.py | 121 ---------------
dev-local/mslsx_django/templates/login.html | 75 ---------
dev-local/mslsx_django/urls.py | 20 ---
dev-local/mslsx_django/views.py | 163 --------------------
dev-local/mslsx_django/wsgi.py | 16 --
hhs_oauth_server/settings/logging_it.py | 2 +-
8 files changed, 1 insertion(+), 417 deletions(-)
delete mode 100755 dev-local/manage.py
delete mode 100755 dev-local/mslsx_django/__init__.py
delete mode 100755 dev-local/mslsx_django/settings.py
delete mode 100755 dev-local/mslsx_django/templates/login.html
delete mode 100755 dev-local/mslsx_django/urls.py
delete mode 100755 dev-local/mslsx_django/views.py
delete mode 100755 dev-local/mslsx_django/wsgi.py
diff --git a/dev-local/manage.py b/dev-local/manage.py
deleted file mode 100755
index bca5b1fb7..000000000
--- a/dev-local/manage.py
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env python
-"""Django's command-line utility for administrative tasks."""
-import os
-import sys
-
-
-def main():
- os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mslsx_django.settings')
- try:
- from django.core.management import execute_from_command_line
- except ImportError as exc:
- raise ImportError(
- "Couldn't import Django. Are you sure it's installed and "
- "available on your PYTHONPATH environment variable? Did you "
- "forget to activate a virtual environment?"
- ) from exc
- execute_from_command_line(sys.argv)
-
-
-if __name__ == '__main__':
- main()
diff --git a/dev-local/mslsx_django/__init__.py b/dev-local/mslsx_django/__init__.py
deleted file mode 100755
index e69de29bb..000000000
diff --git a/dev-local/mslsx_django/settings.py b/dev-local/mslsx_django/settings.py
deleted file mode 100755
index 1e779961f..000000000
--- a/dev-local/mslsx_django/settings.py
+++ /dev/null
@@ -1,121 +0,0 @@
-"""
-Django settings for mslsx_django project.
-
-Generated by 'django-admin startproject' using Django 2.2.13.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/2.2/topics/settings/
-
-For the full list of settings and their values, see
-https://docs.djangoproject.com/en/2.2/ref/settings/
-"""
-
-import os
-
-# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
-BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-
-
-# Quick-start development settings - unsuitable for production
-# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
-
-# SECURITY WARNING: keep the secret key used in production secret!
-SECRET_KEY = '9iq6l*3n7-ljq#wc-fz496#2ri*zdt2skq!4f$!lx@dt8-!t8='
-
-# SECURITY WARNING: don't run with debug turned on in production!
-DEBUG = True
-
-ALLOWED_HOSTS = ["msls", "localhost", "127.0.0.1"]
-
-
-# Application definition
-
-INSTALLED_APPS = [
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'mslsx_django',
-]
-
-MIDDLEWARE = [
- 'django.middleware.security.SecurityMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.csrf.CsrfViewMiddleware',
- 'django.contrib.auth.middleware.AuthenticationMiddleware',
- 'django.contrib.messages.middleware.MessageMiddleware',
- 'django.middleware.clickjacking.XFrameOptionsMiddleware',
-]
-
-ROOT_URLCONF = 'mslsx_django.urls'
-
-TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [],
- 'APP_DIRS': True,
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
- ],
- },
- },
-]
-
-WSGI_APPLICATION = 'mslsx_django.wsgi.application'
-
-
-# Database
-# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
-
-DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.sqlite3',
- 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
- }
-}
-
-
-# Password validation
-# https://docs.djangoproject.com/en/2.2/ref/settings/#auth-password-validators
-
-AUTH_PASSWORD_VALIDATORS = [
- {
- 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
- },
- {
- 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
- },
-]
-
-
-# Internationalization
-# https://docs.djangoproject.com/en/2.2/topics/i18n/
-
-LANGUAGE_CODE = 'en-us'
-
-TIME_ZONE = 'UTC'
-
-USE_I18N = True
-
-USE_L10N = True
-
-USE_TZ = True
-
-
-# Static files (CSS, JavaScript, Images)
-# https://docs.djangoproject.com/en/2.2/howto/static-files/
-
-STATIC_URL = '/static/'
diff --git a/dev-local/mslsx_django/templates/login.html b/dev-local/mslsx_django/templates/login.html
deleted file mode 100755
index 842f3199b..000000000
--- a/dev-local/mslsx_django/templates/login.html
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
- MSLSX Login
-
-
-
-
- MSLSX Component Inputs for simulating SLSX/MyMedicare auth flow locally
-
-
-
Simulated Authentication no PHI or PII
- Use Only Synthetic Beneficiary Info
- Enter values to be returned by the SLSX user_info endpoint below:
-
-
-
-
-
-
diff --git a/dev-local/mslsx_django/urls.py b/dev-local/mslsx_django/urls.py
deleted file mode 100755
index bd28a9d12..000000000
--- a/dev-local/mslsx_django/urls.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from django.conf.urls import url
-
-from .views import (
- login_page,
- login,
- token,
- userinfo,
- signout,
- health,
-)
-
-urlpatterns = [
- # mslsx end points
- url(r'^sso/authorize\\?.+', login_page),
- url(r'^login/', login),
- url(r'^health', health),
- url(r'^sso/session', token),
- url(r'^v1/users/', userinfo),
- url(r'^sso/signout', signout),
-]
diff --git a/dev-local/mslsx_django/views.py b/dev-local/mslsx_django/views.py
deleted file mode 100755
index c59745cd3..000000000
--- a/dev-local/mslsx_django/views.py
+++ /dev/null
@@ -1,163 +0,0 @@
-import json
-import base64
-
-from django.shortcuts import render, HttpResponse, redirect
-from django.views.decorators.csrf import csrf_exempt
-from urllib.parse import urlencode
-
-
-signed_in = True
-
-ENCODE_NAME = "ascii"
-
-ID_FIELD = "id"
-USERNAME_FIELD = "username"
-NAME_FIELD = "name"
-EMAIL_FIELD = "email"
-FIRST_NAME_FIELD = "fisrt_name"
-LAST_NAME_FIELD = "last_name"
-HICN_FIELD = "hicn"
-MBI_FIELD = "mbi"
-CODE_KEY = "code"
-AUTH_HEADER = "Authorization"
-
-
-def _base64_encode(string):
- """
- Removes any `=` used as padding from the encoded string.
- """
- encoded = base64.urlsafe_b64encode(string)
- return encoded.rstrip(b"=")
-
-
-def _base64_decode(string):
- """
- Adds back in the required padding before decoding.
- """
- padding = 4 - (len(string) % 4)
- string = string + ("=" * padding)
- return base64.urlsafe_b64decode(string)
-
-
-def _encode(usr="", name="", first_name="", last_name="", email="", hicn="", mbi=""):
- return "{}.{}.{}.{}.{}.{}.{}".format(_base64_encode(usr.encode(ENCODE_NAME)).decode(ENCODE_NAME),
- _base64_encode(name.encode(ENCODE_NAME)).decode(ENCODE_NAME),
- _base64_encode(first_name.encode(ENCODE_NAME)).decode(ENCODE_NAME),
- _base64_encode(last_name.encode(ENCODE_NAME)).decode(ENCODE_NAME),
- _base64_encode(email.encode(ENCODE_NAME)).decode(ENCODE_NAME),
- _base64_encode(hicn.encode(ENCODE_NAME)).decode(ENCODE_NAME),
- _base64_encode(mbi.encode(ENCODE_NAME)).decode(ENCODE_NAME))
-
-
-def _decode(b64code):
- flds = b64code.split(".")
- return {
- "usr": _base64_decode(flds[0]).decode(ENCODE_NAME),
- "name": _base64_decode(flds[1]).decode(ENCODE_NAME),
- "first_name": _base64_decode(flds[2]).decode(ENCODE_NAME),
- "last_name": _base64_decode(flds[3]).decode(ENCODE_NAME),
- "email": _base64_decode(flds[4]).decode(ENCODE_NAME),
- "hicn": _base64_decode(flds[5]).decode(ENCODE_NAME),
- "mbi": _base64_decode(flds[6]).decode(ENCODE_NAME),
- }
-
-
-def login_page(request):
- '''
- response with login form
- '''
- return render(request, 'login.html', {
- "relay": request.GET.get("relay", "missing"),
- "redirect_uri": request.GET.get("redirect_uri", "missing"),
- })
-
-
-def login(request):
- '''
- process login form POST, collect sub, mbi, hicn, etc.
- '''
-
- redirect_url = request.POST.get("redirect_uri", None)
-
- req_token = _encode(request.POST.get(USERNAME_FIELD, ""),
- request.POST.get(NAME_FIELD, ""),
- request.POST.get(FIRST_NAME_FIELD, ""),
- request.POST.get(LAST_NAME_FIELD, ""),
- request.POST.get(EMAIL_FIELD, ""),
- request.POST.get(HICN_FIELD, ""),
- request.POST.get(MBI_FIELD, ""))
-
- qparams = {
- "req_token": req_token,
- "relay": request.POST.get("relay", "")
- }
- return redirect("{}?{}".format(redirect_url, urlencode(qparams)))
-
-
-def health(request):
- '''
- always good
- '''
- return HttpResponse(json.dumps({"message": "all's well"}),
- status=200, content_type='application/json')
-
-
-@csrf_exempt
-def token(request):
- '''
- grant access token to further get userinfo
- '''
- body_unicode = request.body.decode('utf-8')
- body = json.loads(body_unicode)
- request_token = body.get("request_token", None)
-
- if request_token is None:
- return HttpResponse(json.dumps({"message": "Bad Request, missing request token."}),
- status=400, content_type='application/json')
-
- user_info = _decode(request_token)
-
- token = {
- "user_id": user_info['usr'],
- "auth_token": request_token,
- }
-
- return HttpResponse(json.dumps(token), status=200, content_type='application/json')
-
-
-def userinfo(request):
-
- global signed_in
-
- if signed_in is True:
- tkn = request.headers.get(AUTH_HEADER, None)
- if tkn is None:
- return HttpResponse(json.dumps({"message": "Bad Request, missing request token."}),
- status=400, content_type='application/json')
- if not tkn.startswith("Bearer "):
- return HttpResponse(json.dumps({"message": "Bad Request, malformed bearer token."}),
- status=400, content_type='application/json')
- tkn = tkn.split()[1]
- user_info = _decode(tkn)
- slsx_userinfo = {
- "data": {
- "user": {
- "id": user_info["usr"],
- "username": user_info["name"],
- "email": user_info["email"],
- "firstName": user_info["first_name"],
- "lastName": user_info["last_name"],
- "hicn": user_info["hicn"],
- "mbi": user_info["mbi"],
- },
- },
- }
- signed_in = False
- return HttpResponse(json.dumps(slsx_userinfo), status=200, content_type='application/json')
- else:
- signed_in = True
- return HttpResponse(status=403, content_type='application/json')
-
-
-def signout(request):
- return HttpResponse(status=302, content_type='application/json')
diff --git a/dev-local/mslsx_django/wsgi.py b/dev-local/mslsx_django/wsgi.py
deleted file mode 100755
index dea691653..000000000
--- a/dev-local/mslsx_django/wsgi.py
+++ /dev/null
@@ -1,16 +0,0 @@
-"""
-WSGI config for mslsx_django project.
-
-It exposes the WSGI callable as a module-level variable named ``application``.
-
-For more information on this file, see
-https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
-"""
-
-import os
-
-from django.core.wsgi import get_wsgi_application
-
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'mslsx_django.settings')
-
-application = get_wsgi_application()
diff --git a/hhs_oauth_server/settings/logging_it.py b/hhs_oauth_server/settings/logging_it.py
index 12c813a5c..a1f026187 100755
--- a/hhs_oauth_server/settings/logging_it.py
+++ b/hhs_oauth_server/settings/logging_it.py
@@ -1,4 +1,4 @@
-from .dev import *
+from .dev import * # lgtm [py/polluting-import]
# Override audit logging handler with a file handler
logging_handlers = LOGGING['handlers']
From 64c1503d1bbf8406399bc5705c972a9b14d26827 Mon Sep 17 00:00:00 2001
From: James Fuqian
Date: Fri, 8 Oct 2021 09:35:28 -0700
Subject: [PATCH 38/39] catch up fix of docker-compose.selenium.yaml revert
back to go lang mslsx.
---
docker-compose.selenium.yml | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/docker-compose.selenium.yml b/docker-compose.selenium.yml
index 9861107b6..58675977e 100755
--- a/docker-compose.selenium.yml
+++ b/docker-compose.selenium.yml
@@ -38,14 +38,13 @@ services:
- "5900:5900"
msls:
- build: .
- command: bash -c "cd dev-local ; python manage.py migrate ; python3 -m debugpy --listen 0.0.0.0:7890 manage.py runserver 0.0.0.0:8080 --noreload"
- environment:
- - DJANGO_SETTINGS_MODULE=mslsx_django.settings
+ build:
+ context: ./dev-local/msls
+ dockerfile: Dockerfile
+ command: msls
ports:
- - "8080:8080"
- - "7890:7890"
-
+ - "8080:8080"
+
db:
image: postgres
environment:
From fab58bed98c60efa9fcd37271958d956f2160532 Mon Sep 17 00:00:00 2001
From: Dave Tisza
Date: Tue, 12 Oct 2021 15:59:22 -0400
Subject: [PATCH 39/39] Fix local dev docker-compose issues
- Add healthcheck to postgres startup and bb2slsx to
depend on service_healthy to fix timing issue
in docker-compose.selenium.yml
- Move DJANGO_SETTINGS_MODULE location in
launcher script docker-compose/run_selenium_tests_local_keybase.sh
to enable other types of tests (non logit) to run.
BB2-537
---
docker-compose.selenium.yml | 13 +++++++++++--
docker-compose/run_selenium_tests_local_keybase.sh | 2 +-
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/docker-compose.selenium.yml b/docker-compose.selenium.yml
index 58675977e..75516f19b 100755
--- a/docker-compose.selenium.yml
+++ b/docker-compose.selenium.yml
@@ -52,6 +52,12 @@ services:
- POSTGRES_PASSWORD=toor
ports:
- "5432:5432"
+ healthcheck:
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
+ interval: 10s
+ timeout: 5s
+ retries: 5
+
bb2slsx:
build: .
@@ -84,5 +90,8 @@ services:
- "8000:8000"
- "5678:5678"
depends_on:
- - db
- - msls
+ msls:
+ condition: service_started
+ db:
+ condition: service_healthy
+
diff --git a/docker-compose/run_selenium_tests_local_keybase.sh b/docker-compose/run_selenium_tests_local_keybase.sh
index 542f21add..4d58df17b 100755
--- a/docker-compose/run_selenium_tests_local_keybase.sh
+++ b/docker-compose/run_selenium_tests_local_keybase.sh
@@ -28,6 +28,7 @@ FHIR_URL="https://prod-sbx.bfd.cms.gov"
# List of tests to run. To be passed in to runtests.py.
TESTS_LIST="apps.integration_tests.selenium_tests.SeleniumTests"
+export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.logging_it"
# Echo function that includes script name on each line for console log readability
echo_msg () {
@@ -96,7 +97,6 @@ else
if [[ $1 == "logit" ]]
then
TESTS_LIST="apps.integration_tests.logging_tests.LoggingTests.test_auth_fhir_flows_logging"
- export DJANGO_SETTINGS_MODULE="hhs_oauth_server.settings.logging_it"
export DJANGO_LOG_JSON_FORMAT_PRETTY=False
fi
fi