Skip to content

Commit 1a0c4b5

Browse files
authored
Dashboard Integration Test Improvements (#1623)
### Feature or Bugfix <!-- please choose --> - Test Enhancement ### Detail - Add documentation in README on how to set up dashboard tests - Add check for QS Account and skip if no Account exists in `session_env1` ### Relates ### Security Please answer the questions below briefly where applicable, or write `N/A`. Based on [OWASP 10](https://owasp.org/Top10/en/). - Does this PR introduce or modify any input fields or queries - this includes fetching data from storage outside the application (e.g. a database, an S3 bucket)? - Is the input sanitized? - What precautions are you taking before deserializing the data you consume? - Is injection prevented by parametrizing queries? - Have you ensured no `eval` or similar functions are used? - Does this PR introduce any functionality or component that requires authorization? - How have you ensured it respects the existing AuthN/AuthZ mechanisms? - Are you logging failed auth attempts? - Are you using or adding any cryptographic features? - Do you use a standard proven implementations? - Are the used keys controlled by the customer? Where are they stored? - Are you introducing any new policies/roles/users? - Have you used the least-privilege principle? How? By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent abbb10a commit 1a0c4b5

File tree

5 files changed

+84
-16
lines changed

5 files changed

+84
-16
lines changed

backend/dataall/core/environment/cdk/environment_stack.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,3 +678,13 @@ def create_integration_tests_role(self):
678678
resources=[f'arn:aws:iam::{self.account}:role/dataall-test-*'],
679679
),
680680
)
681+
682+
self.test_role.add_to_policy(
683+
iam.PolicyStatement(
684+
actions=[
685+
'quicksight:DescribeAccountSubscription',
686+
],
687+
effect=iam.Effect.ALLOW,
688+
resources=[f'arn:aws:quicksight:*:{self.account}:*'],
689+
),
690+
)

tests_new/integration_tests/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,18 @@ Currently **we support only Cognito based deployments** but support for any IdP
8383
8484
- The pipeline will create the users/groups
8585
86+
### Dashboard Tests Pre-Requisities
87+
88+
In order to run the tests on the dashboards module the following steps are required:
89+
90+
- Create Enterprise QuickSight Subscription in `session_env1` AWS Account
91+
- Update QuickSight Account with a Reader Capacity Pricing Plan (required for generating embed URLs - `GenerateEmbedUrlForAnonymousUser`)
92+
- Create / Publish a QuickSight Dashboard
93+
- Create a QuickSight Group named `dataall` and give owner access of the published dashboard to the `dataall` group
94+
- Provide the `dashboardId` in the `config.json` as shown above
95+
96+
Rather than failing if the above pre-requisites are not completed, if ther eis no QuickSight Account is detected in `session_env1` the dashboard tests will be **skipped**.
97+
8698
## Run tests
8799
88100
The tests are executed in CodeBuild as part of the CICD pipeline if the cdk.json parameter `with_approval_tests` is set
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import logging
2+
3+
log = logging.getLogger(__name__)
4+
5+
6+
class QuickSightClient:
7+
def __init__(self, session, account_id, region):
8+
self._client = session.client('quicksight', region_name=region)
9+
self._region = region
10+
self._account_id = account_id
11+
12+
def check_enterprise_account_exists(self):
13+
"""
14+
Check if a QuickSight Account exists in the account.
15+
:param
16+
:return: True if the account exists, False otherwise
17+
"""
18+
try:
19+
response = self._client.describe_account_subscription(AwsAccountId=self._account_id)
20+
if not response['AccountInfo']:
21+
log.info(f'Quicksight Enterprise Subscription not found in Account: {self._account_id}')
22+
return False
23+
else:
24+
if response['AccountInfo']['Edition'] not in ['ENTERPRISE', 'ENTERPRISE_AND_Q']:
25+
log.info(
26+
f"Quicksight Subscription found in Account: {self._account_id} of incorrect type: {response['AccountInfo']['Edition']}"
27+
)
28+
return False
29+
else:
30+
if response['AccountInfo']['AccountSubscriptionStatus'] == 'ACCOUNT_CREATED':
31+
return True
32+
log.info(
33+
f"Quicksight Subscription found in Account: {self._account_id} not active. Status = {response['AccountInfo']['AccountSubscriptionStatus']}"
34+
)
35+
return False
36+
except self._client.exceptions.ResourceNotFoundException:
37+
return False

tests_new/integration_tests/modules/dashboards/conftest.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
)
88
from integration_tests.modules.dashboards.queries import get_dashboard
99
from integration_tests.core.environment.utils import set_env_params
10+
from integration_tests.modules.dashboards.aws_clients import QuickSightClient
11+
12+
13+
@pytest.fixture(scope='session')
14+
def quicksight_account_exists(session_env1, session_env1_aws_client):
15+
if not QuickSightClient(
16+
session_env1_aws_client, session_env1.AwsAccountId, session_env1.region
17+
).check_enterprise_account_exists():
18+
pytest.skip('Skipping QuickSight tests because QuickSight account does not exist')
1019

1120

1221
def create_dataall_dashboard(client, session_id, dashboard_id, env):

tests_new/integration_tests/modules/dashboards/test_dashboard.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,61 +20,61 @@
2020
UPDATED_DESC = 'new description'
2121

2222

23-
def test_get_author_session(client1, session_env1):
23+
def test_get_author_session(quicksight_account_exists, client1, session_env1):
2424
set_env_params(client1, session_env1, dashboardsEnabled='true')
2525
assert_that(get_author_session(client1, session_env1.environmentUri)).starts_with('https://')
2626

2727

28-
def test_get_author_session_unauthorized(client2, session_env1):
28+
def test_get_author_session_unauthorized(quicksight_account_exists, client2, session_env1):
2929
assert_that(get_author_session).raises(GqlError).when_called_with(client2, session_env1.environmentUri).contains(
3030
'UnauthorizedOperation', 'CREATE_DASHBOARD', session_env1.environmentUri
3131
)
3232

3333

34-
def test_get_dashboard(session_id, dashboard1):
34+
def test_get_dashboard(quicksight_account_exists, session_id, dashboard1):
3535
assert_that(dashboard1.label).is_equal_to(session_id)
3636

3737

38-
def test_list_dashboards(client1, client2, session_id, dashboard1):
38+
def test_list_dashboards(quicksight_account_exists, client1, client2, session_id, dashboard1):
3939
filter = {'term': session_id}
4040
assert_that(search_dashboards(client1, filter).nodes).is_length(1)
4141
assert_that(search_dashboards(client2, filter).nodes).is_length(0)
4242

4343

44-
def test_get_dashboard_unauthorized(client2, dashboard1):
44+
def test_get_dashboard_unauthorized(quicksight_account_exists, client2, dashboard1):
4545
assert_that(get_dashboard).raises(GqlError).when_called_with(client2, dashboard1.dashboardUri).contains(
4646
'UnauthorizedOperation', 'GET_DASHBOARD', dashboard1.dashboardUri
4747
)
4848

4949

50-
def test_update_dashboard(client1, dashboard1):
50+
def test_update_dashboard(quicksight_account_exists, client1, dashboard1):
5151
update_dashboard(client1, {'dashboardUri': dashboard1.dashboardUri, 'description': UPDATED_DESC})
5252
ds = get_dashboard(client1, dashboard1.dashboardUri)
5353
assert_that(ds.description).is_equal_to(UPDATED_DESC)
5454

5555

56-
def test_update_dashboard_unauthorized(client2, dashboard1):
56+
def test_update_dashboard_unauthorized(quicksight_account_exists, client2, dashboard1):
5757
assert_that(update_dashboard).raises(GqlError).when_called_with(
5858
client2, {'dashboardUri': dashboard1.dashboardUri, 'description': UPDATED_DESC}
5959
).contains('UnauthorizedOperation', 'UPDATE_DASHBOARD', dashboard1.dashboardUri)
6060

6161

62-
def test_request_dashboard_share(dashboard1_share):
62+
def test_request_dashboard_share(quicksight_account_exists, dashboard1_share):
6363
assert_that(dashboard1_share.shareUri).is_not_none()
6464
assert_that(dashboard1_share.status).is_equal_to('REQUESTED')
6565

6666

67-
def test_list_dashboard_shares(client1, session_id, dashboard1, dashboard1_share):
67+
def test_list_dashboard_shares(quicksight_account_exists, client1, session_id, dashboard1, dashboard1_share):
6868
assert_that(list_dashboard_shares(client1, dashboard1.dashboardUri, {'term': session_id}).nodes).is_length(1)
6969

7070

71-
def test_approve_dashboard_share_unauthorized(client2, dashboard1, dashboard1_share):
71+
def test_approve_dashboard_share_unauthorized(quicksight_account_exists, client2, dashboard1, dashboard1_share):
7272
assert_that(approve_dashboard_share).raises(GqlError).when_called_with(client2, dashboard1_share.shareUri).contains(
7373
'UnauthorizedOperation', 'SHARE_DASHBOARD', dashboard1.dashboardUri
7474
)
7575

7676

77-
def test_approve_dashboard_share(client1, client2, session_id, dashboard1, dashboard1_share):
77+
def test_approve_dashboard_share(quicksight_account_exists, client1, client2, session_id, dashboard1, dashboard1_share):
7878
filter = {'term': session_id}
7979
assert_that(search_dashboards(client2, filter).nodes).is_length(0)
8080
ds_share = approve_dashboard_share(client1, dashboard1_share.shareUri)
@@ -83,23 +83,23 @@ def test_approve_dashboard_share(client1, client2, session_id, dashboard1, dashb
8383
assert_that(search_dashboards(client2, filter).nodes).is_length(1)
8484

8585

86-
def test_reject_dashboard_share(client1, client2, session_id, dashboard1_share):
86+
def test_reject_dashboard_share(quicksight_account_exists, client1, client2, session_id, dashboard1_share):
8787
ds_share = reject_dashboard_share(client1, dashboard1_share.shareUri)
8888
assert_that(ds_share.status).is_equal_to('REJECTED')
8989
assert_that(search_dashboards(client2, {'term': session_id}).nodes).is_length(0)
9090

9191

92-
def test_get_reader_session(client1, dashboard1):
92+
def test_get_reader_session(quicksight_account_exists, client1, dashboard1):
9393
assert_that(get_reader_session(client1, dashboard1.dashboardUri)).starts_with('https://')
9494

9595

96-
def test_get_reader_session_unauthorized(client2, dashboard1):
96+
def test_get_reader_session_unauthorized(quicksight_account_exists, client2, dashboard1):
9797
assert_that(get_reader_session).raises(GqlError).when_called_with(client2, dashboard1.dashboardUri).contains(
9898
'UnauthorizedOperation', 'GET_DASHBOARD', dashboard1.dashboardUri
9999
)
100100

101101

102-
def test_delete_dashboard(client1, session_id, session_env1, testdata):
102+
def test_delete_dashboard(quicksight_account_exists, client1, session_id, session_env1, testdata):
103103
filter = {'term': session_id}
104104
dashboardId = testdata.dashboards['session_env1'].dashboardId
105105
dashboard2 = create_dataall_dashboard(client1, session_id, dashboardId, session_env1)
@@ -109,7 +109,7 @@ def test_delete_dashboard(client1, session_id, session_env1, testdata):
109109
assert_that(search_dashboards(client1, filter).nodes).is_length(1)
110110

111111

112-
def test_delete_dashboard_unauthorized(client2, dashboard1):
112+
def test_delete_dashboard_unauthorized(quicksight_account_exists, client2, dashboard1):
113113
assert_that(delete_dashboard).raises(GqlError).when_called_with(client2, dashboard1.dashboardUri).contains(
114114
'UnauthorizedOperation', 'DELETE_DASHBOARD', dashboard1.dashboardUri
115115
)

0 commit comments

Comments
 (0)