@@ -474,22 +474,13 @@ async def test_verify_key_hashes_key_and_writes_to_cache_on_miss(
474474 2) super().verify_key -> returns a fake entity
475475 3) Cache.set is called with the SHA256 hash key and the returned entity
476476 """
477- # Arrange
478- api_key = "super-secret-key"
479- expected_hash = hashlib .sha256 (api_key .encode ()).hexdigest ()
480- fake_entity = {"id" : "abc123" }
481-
482477 # Mock cache with async get/set
483- cache = MagicMock ()
478+ cache = AsyncMock ()
484479 cache .get = AsyncMock (return_value = None )
485480 cache .set = AsyncMock ()
486481
487- # Patch the parent class verify_key to avoid touching real repo logic
488- super_verify_mock = AsyncMock (return_value = fake_entity )
489- monkeypatch .setattr (ApiKeyService , "verify_key" , super_verify_mock )
490-
491482 # Build service
492- repo_mock = MagicMock () # not used directly since we patched super().verify_key
483+ repo_mock = InMemoryApiKeyRepository ()
493484 service = CachedApiKeyService (
494485 repo = repo_mock ,
495486 cache = cache ,
@@ -500,21 +491,15 @@ async def test_verify_key_hashes_key_and_writes_to_cache_on_miss(
500491 global_prefix = "ak" ,
501492 )
502493
503- # Act
504- result = await service .verify_key ( api_key )
494+ entity = ApiKey ( name = "test" )
495+ entity , api_key = await service .create ( entity )
505496
506- # Assert
507- assert result == fake_entity
497+ expected_hash = hashlib . sha256 ( f" { entity . key_id } { entity . key_hash } " . encode ()). hexdigest ()
498+ await service . verify_key ( api_key )
508499
509500 # cache.get must be called with the hashed key only (never the raw key)
510501 cache .get .assert_awaited_once_with (expected_hash )
511- assert not any (call_args [0 ][0 ] == api_key for call_args in cache .get .await_args_list )
512-
513- # super().verify_key must be called once on miss
514- super_verify_mock .assert_awaited_once_with (api_key = api_key , required_scopes = None )
515-
516- # cache.set must store under the hashed key
517- cache .set .assert_awaited_once_with (expected_hash , fake_entity )
502+ cache .set .assert_awaited_once_with (expected_hash , entity )
518503
519504
520505@pytest .mark .asyncio
@@ -523,71 +508,32 @@ async def test_verify_key_returns_cached_when_present(
523508 fixed_salt_hasher : ApiKeyHasher ,
524509):
525510 """If the cache already contains the entity, return it and do NOT call the repo/super."""
526- # Arrange
527- api_key = "cached-key"
528- expected_hash = hashlib .sha256 (api_key .encode ()).hexdigest ()
529- cached_entity = {"id" : "in-cache" }
511+ entity = ApiKey (name = "test" )
530512
531- cache = MagicMock ()
532- cache .get = AsyncMock (return_value = cached_entity )
513+ cache = AsyncMock ()
514+ cache .get = AsyncMock (return_value = entity )
533515 cache .set = AsyncMock ()
534516
535517 # Even if patched, it must NOT be called in this scenario
536518 super_verify_mock = AsyncMock ()
537519 monkeypatch .setattr (ApiKeyService , "verify_key" , super_verify_mock )
538520
539- repo_mock = MagicMock ()
521+ repo_mock = InMemoryApiKeyRepository ()
540522 service = CachedApiKeyService (
541523 repo = repo_mock ,
542524 cache = cache ,
543525 hasher = fixed_salt_hasher ,
544526 )
545527
546- # Act
547- result = await service . verify_key ( api_key )
528+ entity , api_key = await service . create ( entity )
529+ expected_hash = hashlib . sha256 ( f" { entity . key_id } { entity . key_hash } " . encode ()). hexdigest ( )
548530
549- # Assert
550- assert result == cached_entity
531+ await service .verify_key (api_key )
551532 cache .get .assert_awaited_once_with (expected_hash )
552533 super_verify_mock .assert_not_awaited ()
553534 cache .set .assert_not_awaited ()
554535
555536
556- @pytest .mark .asyncio
557- async def test_verify_key_calls_super_on_cache_miss (
558- monkeypatch : pytest .MonkeyPatch ,
559- fixed_salt_hasher : ApiKeyHasher ,
560- ):
561- """On cache miss, the service must call super().verify_key and then populate the cache."""
562- # Arrange
563- api_key = "needs-lookup"
564- expected_hash = hashlib .sha256 (api_key .encode ()).hexdigest ()
565- entity_from_repo = {"id" : "from-repo" }
566-
567- cache = MagicMock ()
568- cache .get = AsyncMock (return_value = None ) # miss
569- cache .set = AsyncMock ()
570-
571- super_verify_mock = AsyncMock (return_value = entity_from_repo )
572- monkeypatch .setattr (ApiKeyService , "verify_key" , super_verify_mock )
573-
574- repo_mock = MagicMock ()
575- service = CachedApiKeyService (
576- repo = repo_mock ,
577- cache = cache ,
578- hasher = fixed_salt_hasher ,
579- )
580-
581- # Act
582- result = await service .verify_key (api_key )
583-
584- # Assert
585- assert result == entity_from_repo
586- cache .get .assert_awaited_once_with (expected_hash )
587- super_verify_mock .assert_awaited_once_with (api_key = "needs-lookup" , required_scopes = None )
588- cache .set .assert_awaited_once_with (expected_hash , entity_from_repo )
589-
590-
591537@pytest .mark .asyncio
592538async def test_verify_key_raises_when_missing_key (fixed_salt_hasher : ApiKeyHasher ):
593539 """If no API key is provided, a KeyNotProvided error must be raised."""
0 commit comments