19
19
from monitoring .uss_qualifier .resources .astm .f3548 .v21 .planning_area import (
20
20
SubscriptionParams ,
21
21
)
22
+ from monitoring .uss_qualifier .resources .communications import AuthAdapterResource
22
23
from monitoring .uss_qualifier .resources .interuss .id_generator import IDGeneratorResource
23
24
from monitoring .uss_qualifier .scenarios .astm .utm .dss import test_step_fragments
24
25
from monitoring .uss_qualifier .scenarios .astm .utm .dss .validators .subscription_validator import (
@@ -41,9 +42,13 @@ class SubscriptionSynchronization(TestScenario):
41
42
"""
42
43
43
44
SUB_TYPE = register_resource_type (379 , "Subscription" )
45
+ ACL_SUB_TYPE = register_resource_type (380 , "Subscription with different credentials" )
44
46
45
47
_dss : DSSInstance
46
48
49
+ # Separate DSS client for testing manager synchronization
50
+ _dss_separate_creds : Optional [DSSInstance ]
51
+
47
52
_dss_read_instances : List [DSSInstance ]
48
53
49
54
# Base identifier for the subscriptions that will be created
@@ -52,6 +57,11 @@ class SubscriptionSynchronization(TestScenario):
52
57
# Extra sub IDs for testing only deletions
53
58
_ids_for_deletion : List [SubscriptionID ]
54
59
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
+
55
65
# Base parameters used for subscription creation
56
66
_sub_params : SubscriptionParams
57
67
@@ -67,6 +77,7 @@ def __init__(
67
77
other_instances : DSSInstancesResource ,
68
78
id_generator : IDGeneratorResource ,
69
79
planning_area : PlanningAreaResource ,
80
+ second_utm_auth : Optional [AuthAdapterResource ] = None ,
70
81
):
71
82
"""
72
83
Args:
@@ -101,6 +112,7 @@ def __init__(
101
112
for i in range (1 , len (self ._dss_read_instances ) + 1 )
102
113
]
103
114
115
+ self ._acl_sub_id = id_generator .id_factory .make_id (self .ACL_SUB_TYPE )
104
116
self ._planning_area = planning_area .specification
105
117
106
118
# Build a ready-to-use 4D volume with no specified time for searching
@@ -140,6 +152,14 @@ def __init__(
140
152
notify_for_constraints = False ,
141
153
)
142
154
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
+
143
163
def run (self , context : ExecutionContext ):
144
164
145
165
# Check that we actually have at least one other DSS to test against:
@@ -169,6 +189,19 @@ def run(self, context: ExecutionContext):
169
189
self ._query_secondaries_and_compare (self ._sub_params )
170
190
self .end_test_step ()
171
191
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
+
172
205
self .begin_test_step ("Mutate subscription on secondaries" )
173
206
self ._step_mutate_subscriptions_secondaries_shift_time ()
174
207
self .end_test_step ()
@@ -210,6 +243,10 @@ def _ensure_test_sub_ids_do_not_exist(self):
210
243
test_step_fragments .cleanup_sub (self , self ._dss , self ._sub_id )
211
244
for sub_id in self ._ids_for_deletion :
212
245
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
+ )
213
250
214
251
def _ensure_no_active_subs_exist (self ):
215
252
test_step_fragments .cleanup_active_subs (
@@ -584,6 +621,69 @@ def _mutate_subscription_with_dss(
584
621
# Update the parameters we used for that subscription
585
622
self ._sub_params = new_params
586
623
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
+
587
687
def _step_mutate_subscriptions_broadcast_shift_time (self ):
588
688
"""Mutate the subscription on the primary DSS by adding 10 seconds to its start and end times"""
589
689
0 commit comments