2727use OpenConext \EngineBlock \Metadata \Entity \ServiceProvider ;
2828use OpenConext \EngineBlock \Service \Consent \ConsentHashService ;
2929use OpenConext \EngineBlockBundle \Authentication \Repository \DbalConsentRepository ;
30+ use OpenConext \EngineBlockBundle \Configuration \FeatureConfiguration ;
3031use PHPUnit \Framework \Attributes \DataProvider ;
3132use PHPUnit \Framework \TestCase ;
3233
@@ -56,8 +57,20 @@ public function setup(): void
5657
5758 $ this ->response = Mockery::mock (EngineBlock_Saml2_ResponseAnnotationDecorator::class);
5859 $ this ->consentRepository = Mockery::mock (ConsentRepository::class);
59- $ this ->consentService = new ConsentHashService ($ this ->consentRepository );
6060
61+ $ this ->buildConsentAndService (migrationEnabled: true );
62+ }
63+
64+ /**
65+ * Rebuilds $this->consentService and $this->consent with the given toggle state.
66+ * Call this in tests that need a specific toggle setting different from setUp's default.
67+ */
68+ private function buildConsentAndService (bool $ migrationEnabled ): void
69+ {
70+ $ featureConfig = new FeatureConfiguration ([
71+ 'eb.stable_consent_hash_migration ' => $ migrationEnabled ,
72+ ]);
73+ $ this ->consentService = new ConsentHashService ($ this ->consentRepository , $ featureConfig );
6174 $ this ->consent = new EngineBlock_Corto_Model_Consent (
6275 "consent " ,
6376 true ,
@@ -151,14 +164,19 @@ public function test_stable_consent_given($consentType)
151164 }
152165 }
153166
167+ /**
168+ * Toggle ON (migration enabled): new consent stores only the stable hash.
169+ * The legacy attribute column must be left NULL so fully-migrated deployments
170+ * don't accumulate unnecessary data in the old column.
171+ */
154172 #[DataProvider('consentTypeProvider ' )]
155- public function test_give_consent_no_unstable_consent_given ($ consentType )
173+ public function test_give_consent_toggle_on_stores_only_stable_hash ($ consentType )
156174 {
175+ // setUp already builds with migrationEnabled=true
157176 $ serviceProvider = new ServiceProvider ("service-provider-entity-id " );
158177 $ this ->response ->shouldReceive ('getNameIdValue ' )
159178 ->once ()
160179 ->andReturn ('collab:person:id:org-a:joe-a ' );
161- // Now assert that the new stable consent hash is going to be set
162180 $ this ->consentRepository
163181 ->shouldReceive ('storeConsentHash ' )
164182 ->once ()
@@ -167,6 +185,7 @@ public function test_give_consent_no_unstable_consent_given($consentType)
167185 serviceId: 'service-provider-entity-id ' ,
168186 attributeStableHash: '8739602554c7f3241958e3cc9b57fdecb474d508 ' ,
169187 consentType: $ consentType ,
188+ attributeHash: null ,
170189 ))
171190 ->andReturn (true );
172191
@@ -180,14 +199,53 @@ public function test_give_consent_no_unstable_consent_given($consentType)
180199 }
181200 }
182201
202+ /**
203+ * Toggle OFF (migration disabled): new consent stores BOTH hashes so that
204+ * old EB instances (still reading only the `attribute` column) can still
205+ * find the consent record during a rolling deploy.
206+ */
183207 #[DataProvider('consentTypeProvider ' )]
184- public function test_upgrade_to_stable_consent ($ consentType )
208+ public function test_give_consent_toggle_off_stores_both_hashes ($ consentType )
185209 {
210+ $ this ->buildConsentAndService (migrationEnabled: false );
211+ $ serviceProvider = new ServiceProvider ("service-provider-entity-id " );
212+ $ this ->response ->shouldReceive ('getNameIdValue ' )
213+ ->once ()
214+ ->andReturn ('collab:person:id:org-a:joe-a ' );
215+ $ this ->consentRepository
216+ ->shouldReceive ('storeConsentHash ' )
217+ ->once ()
218+ ->with (new ConsentStoreParameters (
219+ hashedUserId: '0e54805079c56c2b1c1197a760af86ac337b7bac ' ,
220+ serviceId: 'service-provider-entity-id ' ,
221+ attributeStableHash: '8739602554c7f3241958e3cc9b57fdecb474d508 ' ,
222+ consentType: $ consentType ,
223+ attributeHash: '8739602554c7f3241958e3cc9b57fdecb474d508 ' ,
224+ ))
225+ ->andReturn (true );
226+
227+ switch ($ consentType ) {
228+ case ConsentType::TYPE_EXPLICIT :
229+ $ this ->assertTrue ($ this ->consent ->giveExplicitConsentFor ($ serviceProvider ));
230+ break ;
231+ case ConsentType::TYPE_IMPLICIT :
232+ $ this ->assertTrue ($ this ->consent ->giveImplicitConsentFor ($ serviceProvider ));
233+ break ;
234+ }
235+ }
236+
237+ /**
238+ * Toggle OFF (migration disabled): upgrading an old unstable consent leaves
239+ * the legacy `attribute` column intact so old instances keep working.
240+ */
241+ #[DataProvider('consentTypeProvider ' )]
242+ public function test_upgrade_toggle_off_preserves_legacy_hash ($ consentType )
243+ {
244+ $ this ->buildConsentAndService (migrationEnabled: false );
186245 $ serviceProvider = new ServiceProvider ("service-provider-entity-id " );
187246 $ this ->response ->shouldReceive ('getNameIdValue ' )
188247 ->once ()
189248 ->andReturn ('collab:person:id:org-a:joe-a ' );
190- // Now assert that the new stable consent hash is going to be set
191249 $ this ->consentRepository
192250 ->shouldReceive ('updateConsentHash ' )
193251 ->once ()
@@ -197,10 +255,38 @@ public function test_upgrade_to_stable_consent($consentType)
197255 hashedUserId: '0e54805079c56c2b1c1197a760af86ac337b7bac ' ,
198256 serviceId: 'service-provider-entity-id ' ,
199257 consentType: $ consentType ,
258+ clearLegacyHash: false ,
259+ ))
260+ ->andReturn (true );
261+
262+ $ this ->assertNull ($ this ->consent ->upgradeAttributeHashFor ($ serviceProvider , $ consentType , ConsentVersion::unstable ()));
263+ }
264+
265+ /**
266+ * Toggle ON (migration enabled): upgrading an old unstable consent nulls the
267+ * legacy `attribute` column so the old column is cleaned up over time.
268+ */
269+ #[DataProvider('consentTypeProvider ' )]
270+ public function test_upgrade_toggle_on_clears_legacy_hash ($ consentType )
271+ {
272+ // setUp already builds with migrationEnabled=true
273+ $ serviceProvider = new ServiceProvider ("service-provider-entity-id " );
274+ $ this ->response ->shouldReceive ('getNameIdValue ' )
275+ ->once ()
276+ ->andReturn ('collab:person:id:org-a:joe-a ' );
277+ $ this ->consentRepository
278+ ->shouldReceive ('updateConsentHash ' )
279+ ->once ()
280+ ->with (new ConsentUpdateParameters (
281+ attributeStableHash: '8739602554c7f3241958e3cc9b57fdecb474d508 ' ,
282+ attributeHash: '8739602554c7f3241958e3cc9b57fdecb474d508 ' ,
283+ hashedUserId: '0e54805079c56c2b1c1197a760af86ac337b7bac ' ,
284+ serviceId: 'service-provider-entity-id ' ,
285+ consentType: $ consentType ,
286+ clearLegacyHash: true ,
200287 ))
201288 ->andReturn (true );
202289
203- // Pass the pre-fetched ConsentVersion (unstable) — no second DB query is made
204290 $ this ->assertNull ($ this ->consent ->upgradeAttributeHashFor ($ serviceProvider , $ consentType , ConsentVersion::unstable ()));
205291 }
206292
0 commit comments