Skip to content

Commit 7dcafc3

Browse files
committed
Add unit tests
1 parent 28ab011 commit 7dcafc3

File tree

4 files changed

+197
-10
lines changed

4 files changed

+197
-10
lines changed

tests/test_identity_map_client.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import os
2+
import unittest
3+
from urllib.error import URLError, HTTPError
4+
5+
from uid2_client import IdentityMapClient, IdentityMapInput, normalize_and_hash_email, normalize_and_hash_phone
6+
7+
8+
class IdentityMapIntegrationTests(unittest.TestCase):
9+
UID2_BASE_URL = None
10+
UID2_API_KEY = None
11+
UID2_SECRET_KEY = None
12+
13+
identity_map_client = None
14+
15+
@classmethod
16+
def setUpClass(cls):
17+
cls.UID2_BASE_URL = os.getenv("UID2_BASE_URL")
18+
cls.UID2_API_KEY = os.getenv("UID2_API_KEY")
19+
cls.UID2_SECRET_KEY = os.getenv("UID2_SECRET_KEY")
20+
21+
print(cls.UID2_BASE_URL, cls.UID2_API_KEY, cls.UID2_SECRET_KEY)
22+
23+
if cls.UID2_BASE_URL and cls.UID2_API_KEY and cls.UID2_SECRET_KEY:
24+
cls.identity_map_client = IdentityMapClient(cls.UID2_BASE_URL, cls.UID2_API_KEY, cls.UID2_SECRET_KEY)
25+
else:
26+
raise Exception("set the required UID2_BASE_URL/UID2_API_KEY/UID2_SECRET_KEY environment variables first")
27+
28+
def test_identity_map_emails(self):
29+
identity_map_input = IdentityMapInput.from_emails(
30+
31+
response = self.identity_map_client.generate_identity_map(identity_map_input)
32+
self.assert_mapped(response, "[email protected]")
33+
self.assert_mapped(response, "[email protected]")
34+
35+
self.assert_unmapped(response, "optout", "[email protected]")
36+
37+
def test_identity_map_nothing_unmapped(self):
38+
identity_map_input = IdentityMapInput.from_emails(
39+
40+
response = self.identity_map_client.generate_identity_map(identity_map_input)
41+
self.assert_mapped(response, "[email protected]")
42+
self.assert_mapped(response, "[email protected]")
43+
44+
def test_identity_map_nothing_mapped(self):
45+
identity_map_input = IdentityMapInput.from_emails(["[email protected]"])
46+
response = self.identity_map_client.generate_identity_map(identity_map_input)
47+
self.assert_unmapped(response, "optout", "[email protected]")
48+
49+
def test_identity_map_invalid_email(self):
50+
self.assertRaises(ValueError, IdentityMapInput.from_emails,
51+
["[email protected]", "this is not an email"])
52+
53+
def test_identity_map_invalid_phone(self):
54+
self.assertRaises(ValueError, IdentityMapInput.from_phones,
55+
["+12345678901", "this is not a phone number"])
56+
57+
def test_identity_map_invalid_hashed_email(self):
58+
identity_map_input = IdentityMapInput.from_hashed_emails(["this is not a hashed email"])
59+
response = self.identity_map_client.generate_identity_map(identity_map_input)
60+
self.assert_unmapped(response, "invalid identifier", "this is not a hashed email")
61+
62+
def test_identity_map_invalid_hashed_phone(self):
63+
identity_map_input = IdentityMapInput.from_hashed_emails(["this is not a hashed phone"])
64+
response = self.identity_map_client.generate_identity_map(identity_map_input)
65+
self.assert_unmapped(response, "invalid identifier", "this is not a hashed phone")
66+
67+
def test_identity_map_hashed_emails(self):
68+
hashed_email1 = normalize_and_hash_email("[email protected]")
69+
hashed_email2 = normalize_and_hash_email("[email protected]")
70+
hashed_opted_out_email = normalize_and_hash_email("[email protected]")
71+
identity_map_input = IdentityMapInput.from_hashed_emails([hashed_email1, hashed_email2, hashed_opted_out_email])
72+
73+
response = self.identity_map_client.generate_identity_map(identity_map_input)
74+
75+
self.assert_mapped(response, hashed_email1)
76+
self.assert_mapped(response, hashed_email2)
77+
78+
self.assert_unmapped(response, "optout", hashed_opted_out_email)
79+
80+
def test_identity_map_duplicate_emails(self):
81+
identity_map_input = IdentityMapInput.from_emails(
82+
83+
84+
response = self.identity_map_client.generate_identity_map(identity_map_input)
85+
86+
mapped_identities = response.mapped_identities
87+
self.assertEqual(4, len(mapped_identities))
88+
89+
raw_uid = mapped_identities.get("[email protected]").get_raw_id()
90+
self.assertEqual(raw_uid, mapped_identities.get("[email protected]").get_raw_id())
91+
self.assertEqual(raw_uid, mapped_identities.get("[email protected]").get_raw_id())
92+
self.assertEqual(raw_uid, mapped_identities.get("[email protected]").get_raw_id())
93+
94+
def test_identity_map_duplicate_hashed_emails(self):
95+
hashed_email = normalize_and_hash_email("[email protected]")
96+
duplicate_hashed_email = hashed_email
97+
hashed_opted_out_email = normalize_and_hash_email("[email protected]")
98+
duplicate_hashed_opted_out_email = hashed_opted_out_email
99+
100+
identity_map_input = IdentityMapInput.from_hashed_emails(
101+
[hashed_email, duplicate_hashed_email, hashed_opted_out_email, duplicate_hashed_opted_out_email])
102+
response = self.identity_map_client.generate_identity_map(identity_map_input)
103+
104+
self.assert_mapped(response, hashed_email)
105+
self.assert_mapped(response, duplicate_hashed_email)
106+
107+
self.assert_unmapped(response, "optout", hashed_opted_out_email)
108+
self.assert_unmapped(response, "optout", duplicate_hashed_opted_out_email)
109+
110+
'''def test_identity_map_empty_input(self):
111+
identity_map_input = IdentityMapInput.from_emails([])
112+
response = self.identity_map_client.generate_identity_map(identity_map_input)
113+
self.assertIsNone(response.mapped_identities)
114+
self.assertIsNone(response.unmapped_identities)'''
115+
116+
def test_identity_map_phones(self):
117+
identity_map_input = IdentityMapInput.from_phones(["+12345678901", "+98765432109", "+00000000000"])
118+
response = self.identity_map_client.generate_identity_map(identity_map_input)
119+
self.assert_mapped(response, "+12345678901")
120+
self.assert_mapped(response, "+98765432109")
121+
122+
self.assert_unmapped(response, "optout", "+00000000000")
123+
124+
def test_identity_map_hashed_phones(self):
125+
hashed_phone1 = normalize_and_hash_phone("+12345678901")
126+
hashed_phone2 = normalize_and_hash_phone("+98765432109")
127+
hashed_opted_out_phone = normalize_and_hash_phone("+00000000000")
128+
identity_map_input = IdentityMapInput.from_hashed_phones([hashed_phone1, hashed_phone2, hashed_opted_out_phone])
129+
response = self.identity_map_client.generate_identity_map(identity_map_input)
130+
self.assert_mapped(response, hashed_phone1)
131+
self.assert_mapped(response, hashed_phone2)
132+
133+
self.assert_unmapped(response, "optout", hashed_opted_out_phone)
134+
135+
def test_identity_map_bad_url(self):
136+
identity_map_input = IdentityMapInput.from_emails(
137+
138+
client = IdentityMapClient("https://operator-bad-url.uidapi.com", os.getenv("UID2_API_KEY"), os.getenv("UID2_SECRET_KEY"))
139+
self.assertRaises(URLError, client.generate_identity_map, identity_map_input)
140+
141+
def test_identity_map_bad_api_key(self):
142+
identity_map_input = IdentityMapInput.from_emails(
143+
144+
client = IdentityMapClient(os.getenv("UID2_BASE_URL"), "bad-api-key", os.getenv("UID2_SECRET_KEY"))
145+
self.assertRaises(HTTPError, client.generate_identity_map,identity_map_input)
146+
147+
def test_identity_map_bad_secret(self):
148+
identity_map_input = IdentityMapInput.from_emails(
149+
150+
client = IdentityMapClient(os.getenv("UID2_BASE_URL"), os.getenv("UID2_API_KEY"), "wJ0hP19QU4hmpB64Y3fV2dAed8t/mupw3sjN5jNRFzg=")
151+
self.assertRaises(HTTPError, client.generate_identity_map,
152+
identity_map_input)
153+
154+
def assert_mapped(self, response, ddi):
155+
mapped_identity = response.mapped_identities.get(ddi)
156+
self.assertIsNotNone(mapped_identity)
157+
self.assertIsNotNone(mapped_identity.get_raw_id())
158+
self.assertIsNotNone(mapped_identity.get_bucket_id())
159+
160+
unmapped_identity = response.unmapped_identities.get(ddi)
161+
self.assertIsNone(unmapped_identity)
162+
163+
def assert_unmapped(self, response, reason, ddi):
164+
unmapped_identity = response.unmapped_identities.get(ddi)
165+
self.assertEqual(reason, unmapped_identity.get_reason())
166+
167+
mapped_identity = response.mapped_identities.get(ddi)
168+
self.assertIsNone(mapped_identity)
169+
170+
171+
if __name__ == '__main__':
172+
unittest.main()

uid2_client/identity_map_input.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22

3-
from uid2_client import IdentityType, normalize_email_string, get_base64_encoded_hash, is_phone_number_normalized
3+
from uid2_client import IdentityType, normalize_email_string, get_base64_encoded_hash, is_phone_number_normalized, \
4+
normalize_and_hash_email, normalize_and_hash_phone
45

56

67
class IdentityMapInput:
@@ -15,20 +16,15 @@ def __init__(self, identity_type, emails_or_phones, already_hashed):
1516
if already_hashed:
1617
self.hashed_normalized_emails.append(email)
1718
else:
18-
normalized_email = normalize_email_string(email)
19-
if normalized_email is None:
20-
raise ValueError("invalid email address")
21-
hashed_normalized_email = get_base64_encoded_hash(normalized_email)
22-
self.hashed_normalized_emails.append(hashed_normalized_email)
19+
hashed_normalized_email = normalize_and_hash_email(email)
2320
self._add_hashed_to_raw_dii_mapping(hashed_normalized_email, email)
21+
self.hashed_normalized_emails.append(hashed_normalized_email)
2422
else: # phone
2523
for phone in emails_or_phones:
2624
if already_hashed:
2725
self.hashed_normalized_phones.append(phone)
2826
else:
29-
if not is_phone_number_normalized(phone):
30-
raise ValueError("phone number is not normalized: " + phone)
31-
hashed_normalized_phone = get_base64_encoded_hash(phone)
27+
hashed_normalized_phone = normalize_and_hash_phone(phone)
3228
self._add_hashed_to_raw_dii_mapping(hashed_normalized_phone, phone)
3329
self.hashed_normalized_phones.append(hashed_normalized_phone)
3430

@@ -51,6 +47,12 @@ def from_hashed_phones(hashed_phones):
5147
def _add_hashed_to_raw_dii_mapping(self, hashed_dii, raw_dii):
5248
self.hashed_dii_to_raw_diis.setdefault(hashed_dii, []).append(raw_dii)
5349

50+
def get_raw_diis(self, identifier):
51+
if len(self.hashed_dii_to_raw_diis) <= 0:
52+
return [identifier]
53+
else:
54+
return self.hashed_dii_to_raw_diis[identifier]
55+
5456
def get_identity_map_input_as_json_string(self):
5557
json_object = {
5658
"email_hash": self.hashed_normalized_emails,

uid2_client/identity_map_response.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def _get_body_as_json(json_response):
3232
@staticmethod
3333
def _get_raw_diis(identity, identity_map_input):
3434
identifier = identity["identifier"]
35-
return identity_map_input.hashed_dii_to_raw_diis[identifier]
35+
return identity_map_input.get_raw_diis(identifier)
3636

3737
def is_success(self):
3838
return self.status == "success"

uid2_client/input_util.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,16 @@ def get_base64_encoded_hash(input):
106106

107107
def get_sha256_bytes(input):
108108
return hashlib.sha256(input.encode()).digest()
109+
110+
111+
def normalize_and_hash_email(email):
112+
normalized_email = normalize_email_string(email)
113+
if normalized_email is None:
114+
raise ValueError("invalid email address: " + email)
115+
return get_base64_encoded_hash(normalized_email)
116+
117+
118+
def normalize_and_hash_phone(phone):
119+
if not is_phone_number_normalized(phone):
120+
raise ValueError("phone number is not normalized: " + phone)
121+
return get_base64_encoded_hash(phone)

0 commit comments

Comments
 (0)