3
3
from unittest import mock
4
4
5
5
import boto3
6
+ import pytest
6
7
from etl_utils .constants import CHANGELOG_NUMBER
7
8
from moto import mock_aws
8
9
16
17
"CPM_FQDN" : "cpm-fqdn" ,
17
18
"LDAP_HOST" : "ldap-host" ,
18
19
"ETL_BUCKET" : "etl-bucket" ,
19
- "ETL_EXTRACT_INPUT_KEY" : "etl-input" ,
20
20
"LDAP_CHANGELOG_USER" : "user" ,
21
21
"LDAP_CHANGELOG_PASSWORD" : "eggs" , # pragma: allowlist secret
22
22
}
23
23
24
24
ALLOWED_EXCEPTIONS = (JSONDecodeError ,)
25
- CHANGELOG_NUMBER_VALUE = "538684"
25
+ LATEST_CHANGELOG_NUMBER = b"540382"
26
+ CURRENT_CHANGELOG_NUMBER = str (int (LATEST_CHANGELOG_NUMBER ) - 1 ).encode ()
26
27
28
+ CHANGELOG_NUMBER_RESULT = [
29
+ 101 ,
30
+ [
31
+ [
32
+ "cn=changelog,o=nhs" ,
33
+ {
34
+ "firstchangenumber" : [b"46425" ],
35
+ "lastchangenumber" : [LATEST_CHANGELOG_NUMBER ],
36
+ },
37
+ ]
38
+ ],
39
+ ]
40
+
41
+ CHANGE_RESULT = (
42
+ 101 ,
43
+ [
44
+ [
45
+ "changenumber=540246,cn=changelog,o=nhs" ,
46
+ {
47
+ "objectClass" : [
48
+ b"top" ,
49
+ b"changeLogEntry" ,
50
+ b"nhsExternalChangelogEntry" ,
51
+ ],
52
+ "changeNumber" : [b"540246" ],
53
+ "changes" : [
54
+ b"\\ nobjectClass: nhsmhsservice\\ nobjectClass: top\\ nnhsIDCode: F2R5Q\\ nnhsMHSPartyKey: F2R5Q-823886\\ nnhsMHSServiceName: urn:nhs:names:services:pdsquery\\ nuniqueIdentifier: 4d554a907e83a4067695"
55
+ ],
56
+ "changeTime" : [b"20240502100040Z" ],
57
+ "changeType" : [b"add" ],
58
+ "targetDN" : [
59
+ b"uniqueIdentifier=4d554a907e83a4067695,ou=Services,o=nhs"
60
+ ],
61
+ },
62
+ ]
63
+ ],
64
+ )
65
+
66
+ CHANGE_RESULT_WITHOUT_UNIQUE_IDENTIFIER = (
67
+ 101 ,
68
+ [
69
+ [
70
+ "changenumber=540246,cn=changelog,o=nhs" ,
71
+ {
72
+ "objectClass" : [
73
+ b"top" ,
74
+ b"changeLogEntry" ,
75
+ b"nhsExternalChangelogEntry" ,
76
+ ],
77
+ "changeNumber" : [b"540246" ],
78
+ "changes" : [
79
+ b"\\ nobjectClass: nhsmhsservice\\ nobjectClass: top\\ nnhsIDCode: F2R5Q\\ nnhsMHSPartyKey: F2R5Q-823886\\ nnhsMHSServiceName: urn:nhs:names:services:pdsquery\\ n"
80
+ ],
81
+ "changeTime" : [b"20240502100040Z" ],
82
+ "changeType" : [b"add" ],
83
+ "targetDN" : [
84
+ b"uniqueIdentifier=4d554a907e83a4067695,ou=Services,o=nhs"
85
+ ],
86
+ },
87
+ ]
88
+ ],
89
+ )
27
90
28
- def test_update ():
91
+
92
+ CHANGE_AS_LDIF = """dn: o=nhs,ou=services,uniqueidentifier=4d554a907e83a4067695
93
+ changetype: add
94
+ objectClass: nhsmhsservice
95
+ objectClass: top
96
+ nhsIDCode: F2R5Q
97
+ nhsMHSPartyKey: F2R5Q-823886
98
+ nhsMHSServiceName: urn:nhs:names:services:pdsquery
99
+ uniqueIdentifier: 4d554a907e83a4067695""" .encode ()
100
+
101
+
102
+ @pytest .mark .parametrize (
103
+ "change_result" , [CHANGE_RESULT , CHANGE_RESULT_WITHOUT_UNIQUE_IDENTIFIER ]
104
+ )
105
+ def test_update (change_result ):
29
106
mocked_ldap = mock .Mock ()
30
107
mocked_ldap_client = mock .Mock ()
31
108
mocked_ldap .initialize .return_value = mocked_ldap_client
32
- mocked_ldap_client .result .return_value = (
33
- 101 ,
34
- [
35
- (
36
- "changenumber=75852519,cn=changelog,o=nhs" ,
37
- {
38
- "objectclass" : {
39
- "top" ,
40
- "changeLogEntry" ,
41
- "nhsExternalChangelogEntry" ,
42
- },
43
- "changenumber" : "75852519" ,
44
- "changes" : "foo" ,
45
- "changetime" : "20240116173441Z" ,
46
- "changetype" : "add" ,
47
- "targetdn" : "uniqueIdentifier=200000042019,ou=Services,o=nhs" ,
48
- },
49
- ),
50
- ],
51
- )
109
+ mocked_ldap_client .result .side_effect = (CHANGELOG_NUMBER_RESULT , change_result )
52
110
53
111
with mock_aws (), mock .patch .dict (
54
112
os .environ , MOCKED_UPDATE_TRIGGER_ENVIRONMENT , clear = True
@@ -75,7 +133,7 @@ def test_update():
75
133
s3_client .put_object (
76
134
Bucket = MOCKED_UPDATE_TRIGGER_ENVIRONMENT ["ETL_BUCKET" ],
77
135
Key = CHANGELOG_NUMBER ,
78
- Body = "0" ,
136
+ Body = CURRENT_CHANGELOG_NUMBER ,
79
137
)
80
138
81
139
from etl .sds .trigger .update import update
@@ -86,12 +144,36 @@ def test_update():
86
144
update .CACHE ["ldap_client" ] = mocked_ldap_client
87
145
88
146
# Remove start execution, since it's meaningless
89
- idx = update .steps .index (_start_execution )
90
- update .steps .pop (idx )
147
+ if _start_execution in update .steps :
148
+ idx = update .steps .index (_start_execution )
149
+ update .steps .pop (idx )
91
150
92
151
# Don't execute the notify lambda
93
- update .notify = mock .Mock (return_value = "abc" )
152
+ update .notify = (
153
+ lambda lambda_client , function_name , result , trigger_type : result
154
+ )
94
155
156
+ # Execute the test
95
157
response = update .handler ()
96
158
97
- assert response == "abc"
159
+ # Verify the changelog number is NOT updated (as it should be updated in the ETL, not the trigger)
160
+ changelog_number_response = s3_client .get_object (
161
+ Bucket = MOCKED_UPDATE_TRIGGER_ENVIRONMENT ["ETL_BUCKET" ], Key = CHANGELOG_NUMBER
162
+ )
163
+ assert changelog_number_response ["Body" ].read () == CURRENT_CHANGELOG_NUMBER
164
+
165
+ # Verify the history file was created
166
+ etl_history_response = s3_client .get_object (
167
+ Bucket = MOCKED_UPDATE_TRIGGER_ENVIRONMENT ["ETL_BUCKET" ],
168
+ Key = f"history/changelog/{ int (LATEST_CHANGELOG_NUMBER )} /input--extract/unprocessed" ,
169
+ )
170
+ assert etl_history_response ["Body" ].read ().lower () == CHANGE_AS_LDIF .lower ()
171
+
172
+ # Verify the ETL input file was created
173
+ etl_input_response = s3_client .get_object (
174
+ Bucket = MOCKED_UPDATE_TRIGGER_ENVIRONMENT ["ETL_BUCKET" ],
175
+ Key = "input--extract/unprocessed" ,
176
+ )
177
+ assert etl_input_response ["Body" ].read ().lower () == CHANGE_AS_LDIF .lower ()
178
+
179
+ assert not isinstance (response , Exception ), response
0 commit comments