/
fingerprint_test.py
228 lines (170 loc) · 6.77 KB
/
fingerprint_test.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
import json
import os
from e3.env import Env
from e3.error import E3Error
from e3.fingerprint import Fingerprint
import pytest
def test_fingerprint():
f1 = Fingerprint()
f1.add("foo", "2")
f2 = Fingerprint()
f2.add("foo", "4")
f12_diff = f2.compare_to(f1)
assert f12_diff["new"] == set()
assert f12_diff["updated"] == {"foo"}
assert f12_diff["obsolete"] == set()
f3 = Fingerprint()
f3.add_file(__file__)
f23_diff = f3.compare_to(f2)
assert f23_diff["new"] == {"foo"}
assert f23_diff["updated"] == set()
assert f23_diff["obsolete"] == {os.path.abspath(__file__)}
assert f1.checksum() != f2.checksum() != f3.checksum()
assert Env().build.os.version in str(f3)
f4 = Fingerprint()
f4.add_file(__file__)
assert f4 == f3
f5 = Fingerprint()
with pytest.raises(E3Error) as err:
f5.add("f4", f4)
assert "f4 should be a string" in str(err.value)
f6 = Fingerprint()
f6.add("unicode", "6")
assert len(f6.checksum()) == 64
def test_add_order_not_important():
def create_fingerprint(first, second, third):
"""Create a fingerprint with 3 elements added in the given order.
The arguments, first, second, and third should be either
1, 2, or 3 (integers), and are meant as indices to (key, value)
pairs in the idx_to_entry_map below, indicating which part
of the fingerprint gets added in what order.
"""
idx_to_entry_map = {1: ("foo", "1"), 2: ("bar", "2"), 3: ("baz", "3")}
f = Fingerprint()
f.add(*idx_to_entry_map[first])
f.add(*idx_to_entry_map[second])
f.add(*idx_to_entry_map[third])
return f
f_ref = create_fingerprint(1, 2, 3)
def check_scenario(first, second, third):
"""Check scenario where adding fingerprint elements in given order.
Create a fingerprint using create_fingerprint above
(same arguments), and then check the resulting key against
the reference key f_ref above. Both the reference fingerprint
and the new fingerprint have the same contents, so they should
behave the same in all ways.
"""
f = create_fingerprint(first, second, third)
assert f == f_ref
assert f.compare_to(f_ref) is None
assert f_ref.compare_to(f) is None
assert str(f) == str(f_ref)
assert f.checksum() == f_ref.checksum()
check_scenario(1, 2, 3)
check_scenario(1, 3, 2)
check_scenario(2, 1, 3)
check_scenario(2, 3, 1)
check_scenario(3, 1, 2)
check_scenario(3, 2, 1)
def test_fingerprint_version():
"""Changing the FINGERPRINT_VERSION modify the fingerprint's checksum."""
import e3.fingerprint
f1 = Fingerprint()
e3.fingerprint.FINGERPRINT_VERSION = "0.0"
f2 = Fingerprint()
assert f1 != f2
assert f1.checksum() != f2.checksum()
f3 = Fingerprint()
assert f2 == f3
assert f2.checksum() == f3.checksum()
def test_invalid_fingerprint():
"""A fingerprint value should be hashable."""
f1 = Fingerprint()
with pytest.raises(E3Error):
f1.add("invalid", {})
def test_fingerprint_eq():
"""Check fingerprint __eq__ function."""
f1 = Fingerprint()
f1.add("1", "1")
assert f1 != 1
f2 = Fingerprint()
f2.add("1", "1")
f2.add("2", "2")
assert f1 != f2
assert f1.checksum() != f2.checksum()
assert f1.compare_to(f1) is None
def test_fingerprint_save_and_load():
# Create a directory where to store our fingerprints, allowing us
# to use any fingerprint name without potentially colliding with
# other files used by this testcase.
os.mkdir("fingerprints")
def fingerprint_path(filename):
return os.path.join("fingerprints", filename)
# Save and then load a minimal fingerprint...
f_min = Fingerprint()
f_min_filename = fingerprint_path("f_min")
assert not os.path.exists(f_min_filename)
f_min.save_to_file(f_min_filename)
f_min_restored = Fingerprint.load_from_file(f_min_filename)
assert f_min_restored == f_min
assert str(f_min_restored) == str(f_min)
assert f_min_restored.checksum() == f_min.checksum()
# Save and then load a fingerprint with more data than the minimum.
f2 = Fingerprint()
f2.add("job1", "job1sha1")
f2.add("job2", "sha1job2")
f2_filename = fingerprint_path("f2")
assert not os.path.exists(f2_filename)
f2.save_to_file(f2_filename)
f2_restored = Fingerprint.load_from_file(f2_filename)
assert f2_restored == f2
assert str(f2_restored) == str(f2)
assert f2_restored.checksum() == f2.checksum()
# Trying to load from a file with invalid contents (bad JSON)
f_bad_filename = fingerprint_path("f_bad_JSON")
with open(f_bad_filename, "w") as f:
f.write("yello{")
f3 = Fingerprint.load_from_file(f_bad_filename)
assert f3 is None
# Trying to load from a file which contains valid data, but
# is not an dictionary, and therefore clearly not something
# that comes from a fingerprint...
f_not_filename = fingerprint_path("not_a_fingerprint")
with open(f_not_filename, "w") as f:
json.dump([1, 2, 3], f)
f4 = Fingerprint.load_from_file(f_not_filename)
assert f4 is None
# Try to load from a file which is missing one of the mandatory
# elements.
for key in ("fingerprint_version", "elements"):
f_key_missing_filename = fingerprint_path("no_%s_key")
# To create the bad file without assuming too much in this test
# how the fingerprint is saved to file, we save a valid fingerprint
# to file, load that file back, remove the key, and then save the
# truncated data again.
f2.save_to_file(f_key_missing_filename)
with open(f_key_missing_filename) as f:
data = json.load(f)
del data[key]
with open(f_key_missing_filename, "w") as f:
json.dump(data, f)
f5 = Fingerprint.load_from_file(f_key_missing_filename)
assert f5 is None
# Try loading a fingerprint whose version number is not recognized
# (typically, and old fingerprint version that we no longer support).
#
# To create the file without assuming too much in this test how
# fingerprint are saved to file, we start with a valid fingerprint
# that we saved to a file, load that file back, adjust the version
# number, and then replace the good fingeprint in that file by
# the modified one.
f_bad_version = fingerprint_path("bad_version")
f2.save_to_file(f_bad_version)
with open(f_bad_version) as f:
data = json.load(f)
data["fingerprint_version"] = "1.0"
data["elements"]["fingerprint_version"] = "1.0"
with open(f_bad_version, "w") as f:
json.dump(data, f)
f = Fingerprint.load_from_file(f_bad_version)
assert f is None