async def test_noreturn_handler_produces_no_credentials(settings): vault = Vault() registry = OperatorRegistry() def login_fn(**_): pass # NB: id auto-detection does not work, as it is local to the test function. registry._activities.append( ActivityHandler( fn=login_fn, id='login_fn', activity=Activity.AUTHENTICATION, param=None, errors=None, timeout=None, retries=None, backoff=None, )) await authenticate( registry=registry, settings=settings, vault=vault, memo=Memo(), indices=OperatorIndexers().indices, ) assert not vault with pytest.raises(LoginError): async for _, _ in vault: pass
async def test_yielding_after_creation(mocker): vault = Vault() mocker.patch.object(vault._ready, 'wait_for') with pytest.raises(LoginError): async for _, _ in vault: pass assert vault._ready.wait_for.await_args_list == [((True, ), )]
async def test_caches_with_different_purposes(mocker): key1 = VaultKey('some-key') obj1 = object() info1 = ConnectionInfo(server='https://expected/') vault = Vault() await vault.populate({key1: info1}) def factory(_: ConnectionInfo) -> object: return obj1 factory_spy = mocker.MagicMock(spec=factory, wraps=factory) async for _, _, _ in vault.extended(factory_spy, purpose='A'): pass async for _, _, _ in vault.extended(factory_spy, purpose='B'): pass assert factory_spy.call_count == 2 # once per purpose.
async def test_invalidation_continues_if_nothing_is_left_without_exception( mocker): key1 = VaultKey('some-key') info1 = ConnectionInfo(server='https://expected/') vault = Vault() mocker.patch.object(vault._ready, 'wait_for') await vault.populate({key1: info1}) await vault.invalidate(key1) assert vault._ready.wait_for.await_args_list == [((True, ), )]
async def test_yielding_after_invalidation(mocker): key1 = VaultKey('some-key') info1 = ConnectionInfo(server='https://expected/') vault = Vault() mocker.patch.object(vault._ready, 'wait_for') await vault.populate({key1: info1}) await vault.invalidate(key1) with pytest.raises(LoginError): async for _, _ in vault: pass
async def test_caches_from_factory(mocker): key1 = VaultKey('some-key') obj1 = object() info1 = ConnectionInfo(server='https://expected/') vault = Vault() await vault.populate({key1: info1}) def factory(_: ConnectionInfo) -> object: return obj1 factory_spy = mocker.MagicMock(spec=factory, wraps=factory) results = [] async for key, info, obj in vault.extended(factory_spy): results.append((key, info, obj)) assert len(results) == 1 assert results[0][0] == key1 assert results[0][1] is info1 assert results[0][2] is obj1 assert factory_spy.called
async def test_invalidation_reraises_if_nothing_is_left_with_exception(mocker): exc = Exception("Sample error.") key1 = VaultKey('some-key') info1 = ConnectionInfo(server='https://expected/') vault = Vault() mocker.patch.object(vault._ready, 'wait_for') await vault.populate({key1: info1}) with pytest.raises(Exception) as e: await vault.invalidate(key1, exc=exc) assert e.value is exc assert vault._ready.wait_for.await_args_list == [((True, ), )]
async def test_yielding_after_population(mocker): key1 = VaultKey('some-key') info1 = ConnectionInfo(server='https://expected/') vault = Vault() mocker.patch.object(vault._ready, 'wait_for') await vault.populate({key1: info1}) results = [] async for key, info in vault: results.append((key, info)) assert len(results) == 1 assert results[0][0] == key1 assert results[0][1] is info1
async def test_empty_registry_produces_no_credentials(settings): vault = Vault() registry = OperatorRegistry() await authenticate( registry=registry, settings=settings, vault=vault, memo=Memo(), indices=OperatorIndexers().indices, ) assert not vault with pytest.raises(LoginError): async for _, _ in vault: pass
async def test_duplicates_are_remembered(mocker): key1 = VaultKey('some-key') info1 = ConnectionInfo(server='https://expected/') info2 = ConnectionInfo( server='https://expected/') # another instance, same fields vault = Vault() mocker.patch.object(vault._ready, 'wait_for') await vault.populate({key1: info1}) await vault.invalidate(key1) await vault.populate({key1: info2}) # There should be nothing to yield, despite the second populate() call. with pytest.raises(LoginError): async for _, _ in vault: pass
async def test_invalidation_continues_if_something_is_left(): exc = Exception("Sample error.") key1 = VaultKey('key1') key2 = VaultKey('key2') info1 = ConnectionInfo(server='https://server1/') info2 = ConnectionInfo(server='https://server2/') vault = Vault() await vault.populate({key1: info1}) await vault.populate({key2: info2}) await vault.invalidate(key1, exc=exc) # no exception! results = [] async for key, info in vault: results.append((key, info)) assert len(results) == 1 assert results[0][0] == key2 assert results[0][1] is info2
def fake_vault(mocker, hostname): """ Provide a freshly created and populated authentication vault for every test. Most of the tests expect some credentials to be at least provided (even if not used). So, we create and set the vault as if every coroutine is invoked from the central `operator` method (where it is set normally). Any blocking activities are mocked, so that the tests do not hang. """ from kopf._cogs.clients import auth key = VaultKey('fixture') info = ConnectionInfo(server=f'https://{hostname}') vault = Vault({key: info}) token = auth.vault_var.set(vault) mocker.patch.object(vault._ready, 'wait_for') try: yield vault finally: auth.vault_var.reset(token)
async def test_single_credentials_provided_to_vault(settings): info = ConnectionInfo(server='https://expected/') vault = Vault() registry = OperatorRegistry() def login_fn(**_): return info # NB: id auto-detection does not work, as it is local to the test function. registry._activities.append( ActivityHandler( fn=login_fn, id='login_fn', activity=Activity.AUTHENTICATION, param=None, errors=None, timeout=None, retries=None, backoff=None, )) await authenticate( registry=registry, settings=settings, vault=vault, memo=Memo(), indices=OperatorIndexers().indices, ) assert vault items = [] async for key, info in vault: items.append((key, info)) assert len(items) == 1 assert items[0][0] == 'login_fn' assert items[0][1] is info
async def test_evals_as_false_when_empty(): vault = Vault() assert not vault
async def test_evals_as_true_when_filled(): key1 = VaultKey('some-key') info1 = ConnectionInfo(server='https://expected/') vault = Vault() await vault.populate({key1: info1}) assert vault
def vault(): vault = Vault() vault_var.set(vault) return vault