You've already forked keep-it-secret
Release v1.0.0
This commit is contained in:
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
12
tests/conftest.py
Normal file
12
tests/conftest.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from .fixtures import TestingSecrets
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def testing_secrets() -> TestingSecrets:
|
||||
return TestingSecrets()
|
||||
0
tests/ext/__init__.py
Normal file
0
tests/ext/__init__.py
Normal file
0
tests/ext/aws/__init__.py
Normal file
0
tests/ext/aws/__init__.py
Normal file
45
tests/ext/aws/test_AWSSecrets.py
Normal file
45
tests/ext/aws/test_AWSSecrets.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from unittest import mock
|
||||
|
||||
from keep_it_secret.ext import aws
|
||||
|
||||
|
||||
@mock.patch.dict(
|
||||
os.environ,
|
||||
{
|
||||
'AWS_ACCESS_KEY_ID': 'test_access_key_id',
|
||||
'AWS_SECRET_ACCESS_KEY': 'test_secret_access_key',
|
||||
'AWS_SESSION_TOKEN': 'test_aws_session_token',
|
||||
'AWS_DEFAULT_REGION': 'test_aws_default_region',
|
||||
},
|
||||
)
|
||||
def test_as_boto3_client_kwargs():
|
||||
# Given
|
||||
secrets = aws.AWSSecrets()
|
||||
|
||||
# When
|
||||
result = secrets.as_boto3_client_kwargs()
|
||||
|
||||
# Then
|
||||
assert result == {
|
||||
'aws_access_key_id': 'test_access_key_id',
|
||||
'aws_secret_access_key': 'test_secret_access_key',
|
||||
'aws_session_token': 'test_aws_session_token',
|
||||
'region_name': 'test_aws_default_region',
|
||||
}
|
||||
|
||||
|
||||
@mock.patch.dict(os.environ, {}, clear=True)
|
||||
def test_as_boto3_client_kwargs_empty():
|
||||
# Given
|
||||
secrets = aws.AWSSecrets()
|
||||
|
||||
# When
|
||||
result = secrets.as_boto3_client_kwargs()
|
||||
|
||||
# Then
|
||||
assert result == {}
|
||||
230
tests/ext/aws/test_AWSSecretsManagerField.py
Normal file
230
tests/ext/aws/test_AWSSecretsManagerField.py
Normal file
@@ -0,0 +1,230 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
import json
|
||||
from unittest import mock
|
||||
|
||||
import boto3
|
||||
import moto
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from keep_it_secret.ext import aws
|
||||
from keep_it_secret.secrets import Secrets
|
||||
|
||||
|
||||
class TestingAWSSecrets(Secrets):
|
||||
aws = aws.AWSSecrets()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def aws_secrets_manager_client() -> mock.Mock:
|
||||
return mock.Mock(spec=['get_secret_value'])
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_boto3_client(mocker: MockerFixture) -> mock.Mock:
|
||||
return mocker.patch.object(aws.boto3, 'client')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def testing_aws_secrets() -> TestingAWSSecrets:
|
||||
return TestingAWSSecrets()
|
||||
|
||||
|
||||
def test_init():
|
||||
# When
|
||||
result = aws.AWSSecretsManagerField('keep_it_secret/tests/spam')
|
||||
|
||||
# Then
|
||||
assert result.secret_id == 'keep_it_secret/tests/spam'
|
||||
assert result.default is None
|
||||
assert result.decoder == json.loads
|
||||
assert result.client is None
|
||||
|
||||
|
||||
def test_init_with_default():
|
||||
# When
|
||||
result = aws.AWSSecretsManagerField(
|
||||
'keep_it_secret/tests/spam', default='eggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
assert result.default == 'eggs'
|
||||
|
||||
|
||||
def test_init_with_decoder():
|
||||
# When
|
||||
result = aws.AWSSecretsManagerField(
|
||||
'keep_it_secret/tests/spam', decoder=int,
|
||||
)
|
||||
|
||||
# Then
|
||||
assert result.decoder == int
|
||||
|
||||
|
||||
def test_init_with_field_options():
|
||||
# When
|
||||
result = aws.AWSSecretsManagerField(
|
||||
'keep_it_secret/tests/spam',
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
assert result.as_type is None
|
||||
assert result.required is False
|
||||
assert result.description == 'spameggs'
|
||||
|
||||
|
||||
def test_new(mocker: MockerFixture):
|
||||
# Given
|
||||
mock_init = mocker.patch.object(
|
||||
aws.AWSSecretsManagerField, '__init__', return_value=None,
|
||||
)
|
||||
|
||||
# When
|
||||
_ = aws.AWSSecretsManagerField.new(
|
||||
'keep_it_secret/tests/spam',
|
||||
default='eggs',
|
||||
decoder=json.dumps,
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
mock_init.assert_called_once_with(
|
||||
'keep_it_secret/tests/spam',
|
||||
default='eggs',
|
||||
decoder=json.dumps,
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
|
||||
def test_get_client_cache_miss(mock_boto3_client: mock.Mock,
|
||||
aws_secrets_manager_client: mock.Mock,
|
||||
testing_aws_secrets: TestingAWSSecrets):
|
||||
# Given
|
||||
mock_boto3_client.return_value = aws_secrets_manager_client
|
||||
|
||||
field = aws.AWSSecretsManagerField('keep_it_secret/tests/spam')
|
||||
|
||||
# When
|
||||
result = field.get_client(testing_aws_secrets)
|
||||
|
||||
# Then
|
||||
assert result == aws_secrets_manager_client
|
||||
|
||||
assert field.client == aws_secrets_manager_client
|
||||
|
||||
mock_boto3_client.assert_called_once_with(
|
||||
'secretsmanager', **testing_aws_secrets.aws.as_boto3_client_kwargs(),
|
||||
)
|
||||
|
||||
|
||||
def test_get_client_cache_hit(mock_boto3_client: mock.Mock,
|
||||
aws_secrets_manager_client: mock.Mock,
|
||||
testing_aws_secrets: TestingAWSSecrets):
|
||||
# Given
|
||||
field = aws.AWSSecretsManagerField('keep_it_secret/tests/spam')
|
||||
field.client = aws_secrets_manager_client
|
||||
|
||||
# When
|
||||
result = field.get_client(testing_aws_secrets)
|
||||
|
||||
# Then
|
||||
assert result == aws_secrets_manager_client
|
||||
|
||||
mock_boto3_client.assert_not_called()
|
||||
|
||||
|
||||
def test_get_value_aws_dependency_missing(mocker: MockerFixture,
|
||||
aws_secrets_manager_client: mock.Mock,
|
||||
testing_secrets: Secrets):
|
||||
# Given
|
||||
field = aws.AWSSecretsManagerField('keep_it_secret/tests/spam')
|
||||
|
||||
mock_field_get_client = mocker.patch.object(
|
||||
field, 'get_client', return_value=aws_secrets_manager_client,
|
||||
)
|
||||
|
||||
with pytest.raises(field.DependencyMissing) as exception_info:
|
||||
# When
|
||||
_ = field(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert exception_info.value.args[0] == 'aws'
|
||||
|
||||
mock_field_get_client.assert_not_called()
|
||||
|
||||
aws_secrets_manager_client.get_secret_value.assert_not_called()
|
||||
|
||||
|
||||
@moto.mock_secretsmanager
|
||||
def test_get_value_required_value_not_found(testing_aws_secrets: Secrets):
|
||||
# Given
|
||||
field = aws.AWSSecretsManagerField('keep_it_secret/tests/spam')
|
||||
|
||||
with pytest.raises(field.RequiredValueMissing) as exception_info:
|
||||
# When
|
||||
_ = field(testing_aws_secrets)
|
||||
|
||||
# Then
|
||||
assert exception_info.value.args[0] == 'keep_it_secret/tests/spam'
|
||||
|
||||
|
||||
@moto.mock_secretsmanager
|
||||
def test_get_value_not_found_not_required(testing_aws_secrets: Secrets):
|
||||
# Given
|
||||
field = aws.AWSSecretsManagerField(
|
||||
'keep_it_secret/tests/spam', required=False,
|
||||
)
|
||||
|
||||
result = field(testing_aws_secrets)
|
||||
|
||||
# Then
|
||||
assert result is None
|
||||
|
||||
|
||||
@moto.mock_secretsmanager
|
||||
def test_get_value(testing_aws_secrets: Secrets):
|
||||
# Given
|
||||
aws_secrets_manager_client = boto3.client('secretsmanager')
|
||||
aws_secrets_manager_client.create_secret(
|
||||
Name='keep_it_secret/tests/spam',
|
||||
SecretString='{"spam":true}',
|
||||
)
|
||||
|
||||
field = aws.AWSSecretsManagerField('keep_it_secret/tests/spam')
|
||||
|
||||
# When
|
||||
result = field(testing_aws_secrets)
|
||||
|
||||
# Then
|
||||
assert result == {"spam": True}
|
||||
|
||||
|
||||
@moto.mock_secretsmanager
|
||||
def test_get_value_with_custom_decoder(testing_aws_secrets: Secrets):
|
||||
# Given
|
||||
aws_secrets_manager_client = boto3.client('secretsmanager')
|
||||
aws_secrets_manager_client.create_secret(
|
||||
Name='keep_it_secret/tests/spam',
|
||||
SecretString='1987-10-03T08:00:00',
|
||||
)
|
||||
|
||||
field = aws.AWSSecretsManagerField(
|
||||
'keep_it_secret/tests/spam', decoder=datetime.datetime.fromisoformat,
|
||||
)
|
||||
|
||||
# When
|
||||
result = field(testing_aws_secrets)
|
||||
|
||||
# Then
|
||||
assert result == datetime.datetime(1987, 10, 3, 8, 0, 0)
|
||||
0
tests/ext/loader/__init__.py
Normal file
0
tests/ext/loader/__init__.py
Normal file
15
tests/ext/loader/test_load_secrets.py
Normal file
15
tests/ext/loader/test_load_secrets.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
from keep_it_secret.ext import loader
|
||||
|
||||
from tests.fixtures import TestingSecrets
|
||||
|
||||
|
||||
def test_load_secrets():
|
||||
# When
|
||||
result = loader.load_secrets('tests.fixtures', 'testing', 'example')
|
||||
|
||||
# Then
|
||||
assert isinstance(result, TestingSecrets)
|
||||
0
tests/fields/__init__.py
Normal file
0
tests/fields/__init__.py
Normal file
62
tests/fields/test_AbstractField.py
Normal file
62
tests/fields/test_AbstractField.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from keep_it_secret import fields
|
||||
from keep_it_secret.secrets import Secrets
|
||||
|
||||
|
||||
def test_init():
|
||||
# When
|
||||
_ = fields.AbstractField()
|
||||
|
||||
# Then
|
||||
assert True # Nothing to test here ;)
|
||||
|
||||
|
||||
def test_init_with_field_options():
|
||||
# When
|
||||
result = fields.AbstractField(
|
||||
as_type=int, required=False, description='spameggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
assert result.as_type == int
|
||||
assert result.required is False
|
||||
assert result.description == 'spameggs'
|
||||
|
||||
|
||||
def test_new(mocker: MockerFixture):
|
||||
# Given
|
||||
mock_init = mocker.patch.object(
|
||||
fields.AbstractField, '__init__', return_value=None,
|
||||
)
|
||||
|
||||
# When
|
||||
_ = fields.AbstractField.new(
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
mock_init.assert_called_once_with(
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
|
||||
def test_get_value(testing_secrets: Secrets):
|
||||
# Given
|
||||
field = fields.AbstractField()
|
||||
|
||||
with pytest.raises(NotImplementedError) as exception_info:
|
||||
# When
|
||||
_ = field.get_value(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert field.name in exception_info.value.args[0]
|
||||
100
tests/fields/test_EnvField.py
Normal file
100
tests/fields/test_EnvField.py
Normal file
@@ -0,0 +1,100 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from keep_it_secret import fields
|
||||
from keep_it_secret.secrets import Secrets
|
||||
|
||||
|
||||
def test_init():
|
||||
# When
|
||||
result = fields.EnvField('KEEP_IT_SECRET_TESTS_SPAM')
|
||||
|
||||
# Then
|
||||
assert result.key == 'KEEP_IT_SECRET_TESTS_SPAM'
|
||||
assert result.default is None
|
||||
|
||||
|
||||
def test_init_with_default():
|
||||
# When
|
||||
result = fields.EnvField('KEEP_IT_SECRET_TESTS_SPAM', default='eggs')
|
||||
|
||||
# Then
|
||||
assert result.default == 'eggs'
|
||||
|
||||
|
||||
def test_init_with_field_options():
|
||||
# When
|
||||
result = fields.EnvField(
|
||||
'KEEP_IT_SECRET_TESTS_SPAM',
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
assert result.as_type == int
|
||||
assert result.required is False
|
||||
assert result.description == 'spameggs'
|
||||
|
||||
|
||||
def test_new(mocker: MockerFixture):
|
||||
# Given
|
||||
mock_init = mocker.patch.object(
|
||||
fields.EnvField, '__init__', return_value=None,
|
||||
)
|
||||
|
||||
# When
|
||||
_ = fields.EnvField.new(
|
||||
'KEEP_IT_SECRET_TESTS_SPAM',
|
||||
default='eggs',
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
mock_init.assert_called_once_with(
|
||||
'KEEP_IT_SECRET_TESTS_SPAM',
|
||||
default='eggs',
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
|
||||
def test_get_value(testing_secrets: Secrets):
|
||||
# Given
|
||||
field = fields.EnvField('KEEP_IT_SECRET_TESTS_SPAM')
|
||||
|
||||
# When
|
||||
result = field.get_value(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result == 'spam'
|
||||
|
||||
|
||||
def test_get_value_required_value_missing(testing_secrets: Secrets):
|
||||
# Given
|
||||
field = fields.EnvField('KEEP_IT_SECRET_TESTS_IDONTEXIST', default=None)
|
||||
|
||||
with pytest.raises(field.RequiredValueMissing) as exception_info:
|
||||
# When
|
||||
_ = field.get_value(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert exception_info.value.args[0] == 'KEEP_IT_SECRET_TESTS_IDONTEXIST'
|
||||
|
||||
|
||||
def test_get_value_missing_not_required(testing_secrets: Secrets):
|
||||
# Given
|
||||
field = fields.EnvField('KEEP_IT_SECRET_TESTS_IDONTEXIST', required=False)
|
||||
|
||||
# When
|
||||
result = field.get_value(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result == field.default
|
||||
117
tests/fields/test_Field.py
Normal file
117
tests/fields/test_Field.py
Normal file
@@ -0,0 +1,117 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from keep_it_secret import fields
|
||||
from keep_it_secret.secrets import Secrets
|
||||
|
||||
|
||||
class TestingField(fields.Field):
|
||||
def get_value(self, secrets):
|
||||
return 'test'
|
||||
|
||||
|
||||
def test_init():
|
||||
# When
|
||||
result = TestingField()
|
||||
|
||||
# Then
|
||||
assert result.as_type == str
|
||||
assert result.required is True
|
||||
assert result.description is None
|
||||
assert isinstance(result.name, str) is True
|
||||
assert len(result.name) > 0
|
||||
|
||||
|
||||
def test_new(mocker: MockerFixture):
|
||||
# Given
|
||||
mock_init = mocker.patch.object(
|
||||
TestingField, '__init__', return_value=None,
|
||||
)
|
||||
|
||||
# When
|
||||
_ = TestingField.new(
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
mock_init.assert_called_once_with(
|
||||
as_type=int,
|
||||
required=False,
|
||||
description='spameggs',
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'argument,value',
|
||||
[
|
||||
('as_type', int),
|
||||
('required', False),
|
||||
('description', 'spam'),
|
||||
],
|
||||
)
|
||||
def test_init_with_kwargs(argument, value):
|
||||
# When
|
||||
result = TestingField(**{argument: value})
|
||||
|
||||
# Then
|
||||
assert getattr(result, argument) == value
|
||||
|
||||
|
||||
def test_call(mocker: MockerFixture, testing_secrets: Secrets):
|
||||
# Given
|
||||
field = TestingField()
|
||||
|
||||
# When
|
||||
result = field(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result == 'test'
|
||||
|
||||
|
||||
def test_call_get_value_call(mocker: MockerFixture, testing_secrets: Secrets):
|
||||
# Given
|
||||
field = TestingField()
|
||||
|
||||
mock_get_value = mocker.patch.object(
|
||||
field, 'get_value', return_value='spam',
|
||||
)
|
||||
|
||||
# When
|
||||
result = field(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result == 'spam'
|
||||
|
||||
mock_get_value.assert_called_once_with(testing_secrets)
|
||||
|
||||
|
||||
def test_call_get_value_None(mocker: MockerFixture, testing_secrets: Secrets):
|
||||
# Given
|
||||
field = TestingField(as_type=int)
|
||||
|
||||
_ = mocker.patch.object(field, 'get_value', return_value=None)
|
||||
|
||||
# When
|
||||
result = field(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_call_with_as_type(mocker: MockerFixture, testing_secrets: Secrets):
|
||||
# Given
|
||||
field = TestingField(as_type=int)
|
||||
|
||||
_ = mocker.patch.object(field, 'get_value', return_value='5')
|
||||
|
||||
# When
|
||||
result = field(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result == 5
|
||||
57
tests/fields/test_LiteralField.py
Normal file
57
tests/fields/test_LiteralField.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from keep_it_secret import fields
|
||||
from keep_it_secret.secrets import Secrets
|
||||
|
||||
|
||||
def test_init():
|
||||
# When
|
||||
result = fields.LiteralField('spam')
|
||||
|
||||
# Then
|
||||
assert result.as_type is None
|
||||
assert result.value == 'spam'
|
||||
|
||||
|
||||
def test_init_with_field_options():
|
||||
# When
|
||||
result = fields.LiteralField(
|
||||
'spam', as_type=int, required=False, description='eggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
assert result.as_type is None
|
||||
assert result.required is False
|
||||
assert result.description == 'eggs'
|
||||
|
||||
|
||||
def test_new(mocker: MockerFixture):
|
||||
# Given
|
||||
mock_init = mocker.patch.object(
|
||||
fields.LiteralField, '__init__', return_value=None,
|
||||
)
|
||||
|
||||
# When
|
||||
_ = fields.LiteralField.new(
|
||||
'spam', as_type=int, required=False, description='eggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
mock_init.assert_called_once_with(
|
||||
'spam', as_type=int, required=False, description='eggs',
|
||||
)
|
||||
|
||||
|
||||
def test_get_value(testing_secrets: Secrets):
|
||||
# Given
|
||||
field = fields.LiteralField('spam')
|
||||
|
||||
# When
|
||||
result = field.get_value(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result == 'spam'
|
||||
64
tests/fields/test_SecretsField.py
Normal file
64
tests/fields/test_SecretsField.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest import mock
|
||||
|
||||
from pytest_mock import MockerFixture
|
||||
|
||||
from keep_it_secret import fields
|
||||
from keep_it_secret.secrets import Secrets
|
||||
|
||||
|
||||
def test_init():
|
||||
# When
|
||||
result = fields.SecretsField(Secrets)
|
||||
|
||||
# Then
|
||||
assert result.as_type is None
|
||||
assert result.klass == Secrets
|
||||
|
||||
|
||||
def test_init_with_field_options():
|
||||
# When
|
||||
result = fields.SecretsField(
|
||||
Secrets, as_type=int, required=False, description='eggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
assert result.as_type is None
|
||||
assert result.required is False
|
||||
assert result.description == 'eggs'
|
||||
|
||||
|
||||
def test_new(mocker: MockerFixture):
|
||||
# Given
|
||||
mock_init = mocker.patch.object(
|
||||
fields.SecretsField, '__init__', return_value=None,
|
||||
)
|
||||
|
||||
# When
|
||||
_ = fields.SecretsField.new(
|
||||
Secrets, as_type=int, required=False, description='eggs',
|
||||
)
|
||||
|
||||
# Then
|
||||
mock_init.assert_called_once_with(
|
||||
Secrets, as_type=int, required=False, description='eggs',
|
||||
)
|
||||
|
||||
|
||||
def test_get_value(testing_secrets: Secrets):
|
||||
# Given
|
||||
wrapped_secrets = mock.Mock(spec=Secrets)
|
||||
mock_secrets_class = mock.Mock(return_value=wrapped_secrets)
|
||||
|
||||
field = fields.SecretsField(mock_secrets_class)
|
||||
|
||||
# When
|
||||
result = field.get_value(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result == wrapped_secrets
|
||||
|
||||
mock_secrets_class.assert_called_once_with(parent=testing_secrets)
|
||||
2
tests/fixtures/__init__.py
vendored
Normal file
2
tests/fixtures/__init__.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# type: ignore
|
||||
from .models import TestingSecrets # noqa: F401
|
||||
11
tests/fixtures/models.py
vendored
Normal file
11
tests/fixtures/models.py
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
from keep_it_secret.fields import EnvField, LiteralField
|
||||
from keep_it_secret.secrets import Secrets
|
||||
|
||||
|
||||
class TestingSecrets(Secrets):
|
||||
spam: str = EnvField.new('KEEP_IT_SECRET_TESTS_SPAM')
|
||||
eggs: str = LiteralField.new('eggs')
|
||||
0
tests/fixtures/testing/__init__.py
vendored
Normal file
0
tests/fixtures/testing/__init__.py
vendored
Normal file
7
tests/fixtures/testing/example.py
vendored
Normal file
7
tests/fixtures/testing/example.py
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
from tests.fixtures.models import TestingSecrets
|
||||
|
||||
__secrets__ = TestingSecrets()
|
||||
0
tests/secrets/__init__.py
Normal file
0
tests/secrets/__init__.py
Normal file
40
tests/secrets/test_Secrets.py
Normal file
40
tests/secrets/test_Secrets.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
from keep_it_secret import secrets
|
||||
|
||||
from tests.fixtures import TestingSecrets
|
||||
|
||||
|
||||
class ParentSecrets(secrets.Secrets):
|
||||
pass
|
||||
|
||||
|
||||
def test_init():
|
||||
# When
|
||||
result = TestingSecrets()
|
||||
|
||||
# Then
|
||||
assert isinstance(result, TestingSecrets)
|
||||
assert result.__secrets_parent__ is None
|
||||
assert result.__secrets_data__ == {'spam': 'spam', 'eggs': 'eggs'}
|
||||
|
||||
|
||||
def test_init_with_parent():
|
||||
# Given
|
||||
parent_secrets = ParentSecrets()
|
||||
|
||||
# When
|
||||
result = TestingSecrets(parent=parent_secrets)
|
||||
|
||||
# Then
|
||||
assert result.__secrets_parent__ is parent_secrets
|
||||
|
||||
|
||||
def test_field_property(testing_secrets: TestingSecrets):
|
||||
# When
|
||||
result = testing_secrets.spam
|
||||
|
||||
# Then
|
||||
assert result == testing_secrets.__secrets_data__['spam']
|
||||
82
tests/secrets/test_SecretsBase.py
Normal file
82
tests/secrets/test_SecretsBase.py
Normal file
@@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
import types
|
||||
|
||||
from keep_it_secret import secrets
|
||||
from keep_it_secret.fields import EnvField, LiteralField
|
||||
|
||||
|
||||
class TestingSecrets(secrets.Secrets):
|
||||
spam: str = LiteralField.new('spam')
|
||||
|
||||
something = False
|
||||
|
||||
def do_something(self):
|
||||
return True
|
||||
|
||||
|
||||
class SubclassSecrets(TestingSecrets):
|
||||
spam: str = EnvField.new('KEEP_IT_SECRET_TESTS_SPAM')
|
||||
eggs: str = LiteralField.new('eggs')
|
||||
|
||||
|
||||
def test_generic_attribute_initialization():
|
||||
# Then
|
||||
assert TestingSecrets.__class__ is secrets.SecretsBase
|
||||
assert isinstance(TestingSecrets.__init__, types.FunctionType)
|
||||
|
||||
|
||||
def test_secrets_dunder_attribute_initialization():
|
||||
# Then
|
||||
assert hasattr(TestingSecrets, '__secrets_fields__')
|
||||
|
||||
assert 'spam' in TestingSecrets.__secrets_fields__
|
||||
assert isinstance(TestingSecrets.__secrets_fields__['spam'], LiteralField) is True
|
||||
assert TestingSecrets.__secrets_fields__['spam'].name == 'TestingSecrets.spam'
|
||||
|
||||
|
||||
def test_secret_properties_initialization():
|
||||
# Then
|
||||
assert hasattr(TestingSecrets, 'spam')
|
||||
assert isinstance(TestingSecrets.spam, property)
|
||||
|
||||
|
||||
def test_subclass_attribute_initialization():
|
||||
# Then
|
||||
assert hasattr(TestingSecrets, 'something')
|
||||
assert TestingSecrets.something is False
|
||||
|
||||
assert hasattr(TestingSecrets, 'do_something')
|
||||
assert isinstance(TestingSecrets.do_something, types.FunctionType)
|
||||
|
||||
|
||||
def test_inheritance():
|
||||
# Then
|
||||
assert isinstance(SubclassSecrets.__secrets_fields__['spam'], EnvField) is True
|
||||
assert isinstance(SubclassSecrets.__secrets_fields__['eggs'], LiteralField) is True
|
||||
|
||||
assert hasattr(SubclassSecrets, 'do_something')
|
||||
assert isinstance(SubclassSecrets.do_something, types.FunctionType)
|
||||
|
||||
|
||||
def test_multiple_inheritance():
|
||||
# Given
|
||||
class TestingMixin:
|
||||
def do_something_else(self):
|
||||
return False
|
||||
|
||||
class SubclassWithMixin(TestingMixin, SubclassSecrets):
|
||||
spameggs = LiteralField.new('spameggs')
|
||||
|
||||
# Then
|
||||
assert isinstance(SubclassWithMixin.__secrets_fields__['spam'], EnvField) is True
|
||||
assert isinstance(SubclassWithMixin.__secrets_fields__['eggs'], LiteralField) is True
|
||||
assert isinstance(SubclassWithMixin.__secrets_fields__['spameggs'], LiteralField) is True
|
||||
|
||||
assert hasattr(SubclassWithMixin, 'do_something')
|
||||
assert isinstance(SubclassWithMixin.do_something, types.FunctionType)
|
||||
|
||||
assert hasattr(SubclassWithMixin, 'do_something_else')
|
||||
assert isinstance(SubclassWithMixin.do_something_else, types.FunctionType)
|
||||
57
tests/secrets/test_field_property_factory.py
Normal file
57
tests/secrets/test_field_property_factory.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# type: ignore
|
||||
from __future__ import annotations
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from pytest_mock import MockFixture
|
||||
|
||||
from keep_it_secret import secrets
|
||||
from keep_it_secret.secrets import Secrets
|
||||
|
||||
|
||||
class TestingSecrets(Secrets):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_field(mocker: MockFixture) -> mock.Mock:
|
||||
result = mocker.Mock(return_value='spam')
|
||||
result.description = None
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def testing_secrets() -> TestingSecrets:
|
||||
yield TestingSecrets()
|
||||
|
||||
TestingSecrets.__secrets_fields__ = {}
|
||||
|
||||
|
||||
def test_getter_cache_miss(mock_field: mock.Mock, testing_secrets: TestingSecrets):
|
||||
# Given
|
||||
testing_secrets.__secrets_fields__['spam'] = mock_field
|
||||
|
||||
# When
|
||||
result = secrets.field_property_factory('spam', mock_field).fget(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result == 'spam'
|
||||
|
||||
mock_field.assert_called_once_with(testing_secrets)
|
||||
|
||||
|
||||
def test_getter_cache_hit(mock_field: mock.Mock, testing_secrets: TestingSecrets):
|
||||
# Given
|
||||
testing_secrets.__secrets_fields__['spam'] = mock_field
|
||||
testing_secrets.__secrets_data__['spam'] = 'eggs'
|
||||
|
||||
# When
|
||||
result = secrets.field_property_factory('spam', mock_field).fget(testing_secrets)
|
||||
|
||||
# Then
|
||||
assert result == 'eggs'
|
||||
|
||||
mock_field.assert_not_called()
|
||||
Reference in New Issue
Block a user