11
11
# ANY KIND, either express or implied. See the License for the specific
12
12
# language governing permissions and limitations under the License.
13
13
"""Functional tests for ``dynamodb_encryption_sdk.material_providers.most_recent``."""
14
+ from collections import defaultdict
15
+
14
16
import pytest
15
17
from mock import MagicMock , sentinel
16
18
19
+ from dynamodb_encryption_sdk .exceptions import NoKnownVersionError
20
+ from dynamodb_encryption_sdk .material_providers import CryptographicMaterialsProvider
17
21
from dynamodb_encryption_sdk .material_providers .most_recent import MostRecentProvider
18
22
from dynamodb_encryption_sdk .material_providers .store import ProviderStore
19
23
20
24
pytestmark = [pytest .mark .functional , pytest .mark .local ]
21
25
22
26
27
+ class SentinelCryptoMaterialsProvider (CryptographicMaterialsProvider ):
28
+ def __init__ (self , name , version ):
29
+ self .name = name
30
+ self .version = version
31
+ self ._material_description = version
32
+ self .provider_calls = []
33
+
34
+ def encryption_materials (self , encryption_context ):
35
+ self .provider_calls .append (("encryption_materials" , encryption_context ))
36
+ return getattr (sentinel , "{name}_{version}_encryption" .format (name = self .name , version = self .version ))
37
+
38
+ def decryption_materials (self , encryption_context ):
39
+ self .provider_calls .append (("decryption_materials" , encryption_context ))
40
+ return getattr (sentinel , "{name}_{version}_decryption" .format (name = self .name , version = self .version ))
41
+
42
+
43
+ class MockProviderStore (ProviderStore ):
44
+ def __init__ (self ):
45
+ self .provider_calls = []
46
+ self ._providers = defaultdict (dict )
47
+
48
+ def get_or_create_provider (self , material_name , version ):
49
+ self .provider_calls .append (("get_or_create_provider" , material_name , version ))
50
+ try :
51
+ return self ._providers [material_name ][version ]
52
+ except KeyError :
53
+ self ._providers [material_name ][version ] = SentinelCryptoMaterialsProvider (material_name , version )
54
+ return self ._providers [material_name ][version ]
55
+
56
+ def max_version (self , material_name ):
57
+ self .provider_calls .append (("max_version" , material_name ))
58
+ try :
59
+ return sorted (self ._providers [material_name ].keys ())[- 1 ]
60
+ except IndexError :
61
+ raise NoKnownVersionError ('No known version for name: "{}"' .format (material_name ))
62
+
63
+ def version_from_material_description (self , material_description ):
64
+ self .provider_calls .append (("version_from_material_description" , material_description ))
65
+ return material_description
66
+
67
+
23
68
def test_failed_lock_acquisition ():
24
69
store = MagicMock (__class__ = ProviderStore )
25
70
provider = MostRecentProvider (provider_store = store , material_name = "my material" , version_ttl = 10.0 )
@@ -31,3 +76,57 @@ def test_failed_lock_acquisition():
31
76
32
77
assert test is sentinel .nine
33
78
assert not store .mock_calls
79
+
80
+
81
+ def test_encryption_materials_cache_use ():
82
+ store = MockProviderStore ()
83
+ name = "material"
84
+ provider = MostRecentProvider (provider_store = store , material_name = name , version_ttl = 10.0 )
85
+
86
+ test1 = provider .encryption_materials (sentinel .encryption_context_1 )
87
+ assert test1 is sentinel .material_0_encryption
88
+
89
+ assert provider ._version == 0
90
+ assert len (provider ._cache ._cache ) == 1
91
+
92
+ expected_calls = [
93
+ ("max_version" , name ),
94
+ ("get_or_create_provider" , name , 0 ),
95
+ ("version_from_material_description" , 0 ),
96
+ ]
97
+
98
+ assert store .provider_calls == expected_calls
99
+
100
+ test2 = provider .encryption_materials (sentinel .encryption_context_1 )
101
+ assert test2 is sentinel .material_0_encryption
102
+
103
+ assert provider ._version == 0
104
+ assert len (provider ._cache ._cache ) == 1
105
+
106
+ assert store .provider_calls == expected_calls
107
+
108
+
109
+ def test_decryption_materials_cache_use ():
110
+ store = MockProviderStore ()
111
+ name = "material"
112
+ provider = MostRecentProvider (provider_store = store , material_name = name , version_ttl = 10.0 )
113
+
114
+ context = MagicMock (material_description = 0 )
115
+
116
+ test1 = provider .decryption_materials (context )
117
+ assert test1 is sentinel .material_0_decryption
118
+
119
+ assert len (provider ._cache ._cache ) == 1
120
+
121
+ expected_calls = [("version_from_material_description" , 0 ), ("get_or_create_provider" , name , 0 )]
122
+
123
+ assert store .provider_calls == expected_calls
124
+
125
+ test2 = provider .decryption_materials (context )
126
+ assert test2 is sentinel .material_0_decryption
127
+
128
+ assert len (provider ._cache ._cache ) == 1
129
+
130
+ expected_calls .append (("version_from_material_description" , 0 ))
131
+
132
+ assert store .provider_calls == expected_calls
0 commit comments