Skip to content

Commit ae15b63

Browse files
committed
[uss_qualifier] DSS0210,1b confirm subscription manager is synced
1 parent 0e28f5d commit ae15b63

File tree

3 files changed

+150
-0
lines changed

3 files changed

+150
-0
lines changed

monitoring/uss_qualifier/scenarios/astm/utm/dss/synchronization/subscription_synchronization.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,36 @@ Verifies that all subscription CRUD operations performed on a single DSS instanc
2222

2323
[`PlanningAreaResource`](../../../../../resources/astm/f3548/v21/planning_area.py) describes the 3D volume in which subscriptions will be created.
2424

25+
### second_utm_auth
26+
27+
A `resources.communications.AuthAdapterResource` containing a second set of valid credentials for interacting with the DSS.
28+
29+
This second set of credentials is required to validate that the DSS properly synchronizes the manager of a subscription to other DSS instances.
30+
31+
The participant under test is responsible for providing this second set of credentials along the primary ones used in most other scenarios.
32+
33+
#### Credential requirements
34+
35+
In general, these test credentials may be in all points equal to the ones used by the `AuthAdapterResource` that is
36+
provided to the `dss` resources above, except for the value contained in the `sub` claim of the token.
37+
38+
For the purpose of this scenario, these credentials must be allowed to create, modify and delete subscriptions on the DSS,
39+
as well as querying them.
40+
41+
Note that most checks in this scenario will work if the second set of credentials is not provided.
42+
43+
##### Required scope
44+
45+
For the purpose of this scenario, the `second_utm_auth` resource must provide access to a token with at least the following scope:
46+
47+
* `utm.strategic_coordination`
48+
49+
##### Separate subscription
50+
51+
Note that the subscription (or 'sub' claim, not to be confused with an SCD DSS subscription) of the token that will be obtained for this resource
52+
MUST be different from the one of the `dss` resources mentioned above:
53+
this will be verified at runtime, and the depending checks will not be run if this is not the case.
54+
2555
## Setup test case
2656

2757
### [Ensure clean workspace test step](../clean_workspace.md)
@@ -157,6 +187,25 @@ Verify that the subscription returned by the DSS is properly formatted and conta
157187

158188
#### [Validate version is updated by mutation](../fragments/sub/validate/mutated.md)
159189

190+
### Verify manager synchronization test step
191+
192+
Checks that the manager of a subscription is properly synchronized across all DSS instances.
193+
194+
This is done by means of using a separate set of credentials to create a subscription on the primary DSS,
195+
and then verifying that the main credentials are not able to mutate this subscription via one of the secondary DSS instances
196+
197+
#### [Create subscription](../fragments/sub/crud/create.md)
198+
199+
Verify that a subscription can be created on the primary DSS.
200+
201+
#### 🛑 Subscription deletion with different non-managing credentials on secondary DSS fails check
202+
203+
If the subscription can be deleted by a client which did not create it, via a DSS instance to which the subscription was synced
204+
following its creation on the primary DSS, either one of the primary DSS or the DSS that accepted the deletion failed to properly broadcast, respectively take into account, the manage of the subscription,
205+
and therefore violates **[astm.f3548.v21.DSS0210,1b](../../../../../requirements/astm/f3548/v21.md)**.
206+
207+
### Delete subscription test step
208+
160209
Verify that the version of the subscription returned by the DSS the subscription was mutated through has been updated.
161210

162211
#### [Validate new version is synced](../fragments/sub/validate/non_mutated.md)

monitoring/uss_qualifier/scenarios/astm/utm/dss/synchronization/subscription_synchronization.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from monitoring.uss_qualifier.resources.astm.f3548.v21.planning_area import (
2020
SubscriptionParams,
2121
)
22+
from monitoring.uss_qualifier.resources.communications import AuthAdapterResource
2223
from monitoring.uss_qualifier.resources.interuss.id_generator import IDGeneratorResource
2324
from monitoring.uss_qualifier.scenarios.astm.utm.dss import test_step_fragments
2425
from monitoring.uss_qualifier.scenarios.astm.utm.dss.validators.subscription_validator import (
@@ -41,9 +42,13 @@ class SubscriptionSynchronization(TestScenario):
4142
"""
4243

4344
SUB_TYPE = register_resource_type(379, "Subscription")
45+
ACL_SUB_TYPE = register_resource_type(380, "Subscription with different credentials")
4446

4547
_dss: DSSInstance
4648

49+
# Separate DSS client for testing manager synchronization
50+
_dss_separate_creds: Optional[DSSInstance]
51+
4752
_dss_read_instances: List[DSSInstance]
4853

4954
# Base identifier for the subscriptions that will be created
@@ -52,6 +57,11 @@ class SubscriptionSynchronization(TestScenario):
5257
# Extra sub IDs for testing only deletions
5358
_ids_for_deletion: List[SubscriptionID]
5459

60+
# Extra sub id for testing manager sync
61+
_acl_sub_id: SubscriptionID
62+
# The extra subscription for testing manager sync
63+
_current_acl_sub: Subscription
64+
5565
# Base parameters used for subscription creation
5666
_sub_params: SubscriptionParams
5767

@@ -67,6 +77,7 @@ def __init__(
6777
other_instances: DSSInstancesResource,
6878
id_generator: IDGeneratorResource,
6979
planning_area: PlanningAreaResource,
80+
second_utm_auth: Optional[AuthAdapterResource] = None,
7081
):
7182
"""
7283
Args:
@@ -101,6 +112,7 @@ def __init__(
101112
for i in range(1, len(self._dss_read_instances) + 1)
102113
]
103114

115+
self._acl_sub_id = id_generator.id_factory.make_id(self.ACL_SUB_TYPE)
104116
self._planning_area = planning_area.specification
105117

106118
# Build a ready-to-use 4D volume with no specified time for searching
@@ -140,6 +152,14 @@ def __init__(
140152
notify_for_constraints=False,
141153
)
142154

155+
if second_utm_auth is not None:
156+
# Build a second DSSWrapper identical to the first but with the other auth adapter
157+
self._dss_separate_creds = self._dss.with_different_auth(
158+
second_utm_auth, scopes_primary
159+
)
160+
else:
161+
self._dss_separate_creds = None
162+
143163
def run(self, context: ExecutionContext):
144164

145165
# Check that we actually have at least one other DSS to test against:
@@ -169,6 +189,19 @@ def run(self, context: ExecutionContext):
169189
self._query_secondaries_and_compare(self._sub_params)
170190
self.end_test_step()
171191

192+
if self._dss_separate_creds:
193+
self.begin_test_step("Create subscription with different credentials")
194+
195+
self.end_test_step()
196+
self.begin_test_step("Verify manager synchronization")
197+
self._step_test_delete_sub_with_separate_creds()
198+
self.end_test_step()
199+
else:
200+
self.record_note(
201+
"manager_check",
202+
"Skipping manager synchronization check: no extra credentials provided",
203+
)
204+
172205
self.begin_test_step("Mutate subscription on secondaries")
173206
self._step_mutate_subscriptions_secondaries_shift_time()
174207
self.end_test_step()
@@ -210,6 +243,10 @@ def _ensure_test_sub_ids_do_not_exist(self):
210243
test_step_fragments.cleanup_sub(self, self._dss, self._sub_id)
211244
for sub_id in self._ids_for_deletion:
212245
test_step_fragments.cleanup_sub(self, self._dss, sub_id)
246+
if self._dss_separate_creds:
247+
test_step_fragments.cleanup_sub(
248+
self, self._dss_separate_creds, self._acl_sub_id
249+
)
213250

214251
def _ensure_no_active_subs_exist(self):
215252
test_step_fragments.cleanup_active_subs(
@@ -584,6 +621,69 @@ def _mutate_subscription_with_dss(
584621
# Update the parameters we used for that subscription
585622
self._sub_params = new_params
586623

624+
def _step_create_sub_separate_creds(self):
625+
"""Create a subscription on the main DSS with the separate credentials"""
626+
params = self._sub_params.copy()
627+
params.sub_id = self._acl_sub_id
628+
with self.check(
629+
"Create subscription query succeeds", [self._primary_pid]
630+
) as check:
631+
acl_sub = self._dss_separate_creds.upsert_subscription(
632+
**params,
633+
)
634+
self.record_query(acl_sub)
635+
if not acl_sub.success:
636+
check.record_failed(
637+
"Subscription creation with separate credentials failed",
638+
details=f"Subscription creation failed with status code {acl_sub.status_code} when attempted "
639+
f"with separate credentials: {acl_sub.error_message}",
640+
query_timestamps=[acl_sub.request.timestamp],
641+
)
642+
self._current_acl_sub = acl_sub.subscription
643+
644+
def _step_test_delete_sub_with_separate_creds(self):
645+
"""Check we can't delete the subscription created with separate credentials with the main credentials.
646+
This is to confirm that the manager of the subscription is properly synced.
647+
Note that if the separate credentials are for the same subject as the main one, the checks are skipped.
648+
"""
649+
650+
if not self._credentials_are_different():
651+
self.record_note(
652+
"manager_check",
653+
"Skipping manager synchronization check: "
654+
"separate credentials have the same subscriber as the main ones.",
655+
)
656+
return
657+
658+
# For each secondary dss, try to delete the subscription using the main credentials:
659+
for secondary_dss in self._dss_read_instances:
660+
deleted_sub = secondary_dss.delete_subscription(
661+
sub_id=self._acl_sub_id, sub_version=self._current_acl_sub.version
662+
)
663+
self.record_query(deleted_sub)
664+
with self.check(
665+
"Subscription deletion with different non-managing credentials on secondary DSS fails",
666+
[secondary_dss.participant_id],
667+
) as check:
668+
if deleted_sub.status_code != 403:
669+
check.record_failed(
670+
"Subscription deletion with main credentials did not fail",
671+
details=f"Subscription deletion with main credentials did not fail with the expected "
672+
f"status code of 403; instead returned {deleted_sub.status_code}",
673+
query_timestamps=[deleted_sub.request.timestamp],
674+
)
675+
676+
def _credentials_are_different(self):
677+
"""
678+
Checks the auth adapters for the subscription (jwt 'sub' field) they used and returns False if they are the same.
679+
Note that both adapters need to have been used at least once before this check can be performed,
680+
otherwise they have no token available.
681+
"""
682+
return (
683+
self._dss_separate_creds.client.auth_adapter.get_sub()
684+
!= self._dss.client.auth_adapter.get_sub()
685+
)
686+
587687
def _step_mutate_subscriptions_broadcast_shift_time(self):
588688
"""Mutate the subscription on the primary DSS by adding 10 seconds to its start and end times"""
589689

monitoring/uss_qualifier/suites/astm/utm/dss_probing.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ actions:
4848
other_instances: all_dss_instances
4949
id_generator: id_generator
5050
planning_area: planning_area
51+
second_utm_auth: second_utm_auth
5152
- test_scenario:
5253
scenario_type: scenarios.astm.utm.dss.CRDBAccess
5354
resources:

0 commit comments

Comments
 (0)