29
29
import pathlib
30
30
import platform
31
31
import typing
32
+ import math
32
33
33
34
import invoke .context
34
35
import pytest
35
36
36
37
test_data_path = pathlib .Path (__file__ ).resolve ().parent .joinpath ("testdata" )
38
+ size_comparison_tolerance = 0.03 # Maximum allowed archive size difference ratio
37
39
38
40
39
41
def test_all (run_command , working_dir ):
@@ -77,6 +79,7 @@ def test_all(run_command, working_dir):
77
79
golden_logs_parent_path = test_data_path .joinpath ("test_all" , "golden" , "logs" , "generate" ),
78
80
logs_subpath = pathlib .Path ("github.com" , "arduino-libraries" , "SpacebrewYun" , "index.html" ),
79
81
)
82
+ check_db (configuration = configuration )
80
83
check_index (configuration = configuration )
81
84
82
85
# Run the engine again
@@ -95,6 +98,7 @@ def test_all(run_command, working_dir):
95
98
golden_logs_parent_path = test_data_path .joinpath ("test_all" , "golden" , "logs" , "update" ),
96
99
logs_subpath = pathlib .Path ("github.com" , "arduino-libraries" , "SpacebrewYun" , "index.html" ),
97
100
)
101
+ check_db (configuration = configuration )
98
102
check_index (configuration = configuration )
99
103
100
104
@@ -104,9 +108,9 @@ def check_libraries(configuration):
104
108
Keyword arguments:
105
109
configuration -- dictionary defining the libraries-repository-engine configuration
106
110
"""
111
+ # Check against the index
107
112
with pathlib .Path (configuration ["LibrariesIndex" ]).open (mode = "r" , encoding = "utf-8" ) as libraries_index_file :
108
113
libraries_index = json .load (fp = libraries_index_file )
109
-
110
114
for release in libraries_index ["libraries" ]:
111
115
release_archive_path = pathlib .Path (
112
116
configuration ["LibrariesFolder" ],
@@ -119,6 +123,21 @@ def check_libraries(configuration):
119
123
120
124
assert release ["checksum" ] == "SHA-256:" + hashlib .sha256 (release_archive_path .read_bytes ()).hexdigest ()
121
125
126
+ # Check against the db
127
+ with pathlib .Path (configuration ["LibrariesDB" ]).open (mode = "r" , encoding = "utf-8" ) as library_db_file :
128
+ library_db = json .load (fp = library_db_file )
129
+ for release in library_db ["Releases" ]:
130
+ release_archive_path = pathlib .Path (
131
+ configuration ["LibrariesFolder" ],
132
+ release ["URL" ].removeprefix (configuration ["BaseDownloadUrl" ]),
133
+ )
134
+
135
+ assert release_archive_path .exists ()
136
+
137
+ assert release ["Size" ] == release_archive_path .stat ().st_size
138
+
139
+ assert release ["Checksum" ] == "SHA-256:" + hashlib .sha256 (release_archive_path .read_bytes ()).hexdigest ()
140
+
122
141
123
142
def check_logs (configuration , golden_logs_parent_path , logs_subpath ):
124
143
"""Run tests to determine whether the engine's logs are as expected.
@@ -145,34 +164,111 @@ def check_logs(configuration, golden_logs_parent_path, logs_subpath):
145
164
assert logs == golden_logs
146
165
147
166
167
+ def check_db (configuration ):
168
+ """Run tests to determine whether the generated library database is as expected.
169
+
170
+ Keyword arguments:
171
+ configuration -- dictionary defining the libraries-repository-engine configuration
172
+ """
173
+ checksum_placeholder = "CHECKSUM_PLACEHOLDER"
174
+
175
+ # Load generated db
176
+ with pathlib .Path (configuration ["LibrariesDB" ]).open (mode = "r" , encoding = "utf-8" ) as db_file :
177
+ db = json .load (fp = db_file )
178
+ for release in db ["Releases" ]:
179
+ # The checksum values in the db will be different on every run, so it's necessary to replace them with a
180
+ # placeholder before comparing to the golden master
181
+ release ["Checksum" ] = checksum_placeholder
182
+
183
+ # Load golden index
184
+ golden_db_template = test_data_path .joinpath ("test_all" , "golden" , "db.json" ).read_text (encoding = "utf-8" )
185
+ # Fill in mutable content
186
+ golden_db_string = string .Template (template = golden_db_template ).substitute (
187
+ base_download_url = configuration ["BaseDownloadUrl" ],
188
+ checksum_placeholder = checksum_placeholder ,
189
+ git_clones_folder = configuration ["GitClonesFolder" ],
190
+ )
191
+ golden_db = json .loads (golden_db_string )
192
+
193
+ # Compare db against golden master
194
+ # Order of entries in the db is arbitrary so a simply equality assertion is not possible
195
+ assert len (db ["Libraries" ]) == len (golden_db ["Libraries" ])
196
+ for library in db ["Libraries" ]:
197
+ assert library in golden_db ["Libraries" ]
198
+
199
+ assert len (db ["Releases" ]) == len (golden_db ["Releases" ])
200
+ for release in db ["Releases" ]:
201
+ # Find the golden master for the release
202
+ golden_release = None
203
+ for golden_release_candidate in golden_db ["Releases" ]:
204
+ if (
205
+ golden_release_candidate ["LibraryName" ] == release ["LibraryName" ]
206
+ and golden_release_candidate ["Version" ] == release ["Version" ]
207
+ ):
208
+ golden_release = golden_release_candidate
209
+ break
210
+
211
+ assert golden_release is not None # Matching golden release was found
212
+
213
+ # Small variation in size could result from compression algorithm changes, so we allow a tolerance
214
+ assert "Size" in release
215
+ assert math .isclose (release ["Size" ], golden_release ["Size" ], rel_tol = size_comparison_tolerance )
216
+ # Remove size data so a direct comparison of the remaining data can be made against the golden master
217
+ del release ["Size" ]
218
+ del golden_release ["Size" ]
219
+
220
+ assert release == golden_release
221
+
222
+
148
223
def check_index (configuration ):
149
224
"""Run tests to determine whether the generated library index is as expected.
150
225
151
226
Keyword arguments:
152
227
configuration -- dictionary defining the libraries-repository-engine configuration
153
228
"""
229
+ checksum_placeholder = "CHECKSUM_PLACEHOLDER"
230
+
154
231
# Load generated index
155
232
with pathlib .Path (configuration ["LibrariesIndex" ]).open (mode = "r" , encoding = "utf-8" ) as library_index_file :
156
233
library_index = json .load (fp = library_index_file )
157
234
for release in library_index ["libraries" ]:
158
- # The checksum values in the index will be different on every run, so it's necessary to remove them before
159
- # comparing to the golden index
160
- del release ["checksum" ]
235
+ # The checksum values in the index will be different on every run, so it's necessary to replace them with a
236
+ # placeholder before comparing to the golden index
237
+ release ["checksum" ] = checksum_placeholder
161
238
162
239
# Load golden index
163
240
golden_library_index_template = test_data_path .joinpath ("test_all" , "golden" , "library_index.json" ).read_text (
164
241
encoding = "utf-8"
165
242
)
166
243
# Fill in mutable content
167
244
golden_library_index_string = string .Template (template = golden_library_index_template ).substitute (
168
- base_download_url = configuration ["BaseDownloadUrl" ]
245
+ base_download_url = configuration ["BaseDownloadUrl" ], checksum_placeholder = checksum_placeholder
169
246
)
170
247
golden_library_index = json .loads (golden_library_index_string )
171
248
172
249
# Order of releases in the index is arbitrary so a simply equality assertion is not possible
173
250
assert len (library_index ["libraries" ]) == len (golden_library_index ["libraries" ])
174
251
for release in library_index ["libraries" ]:
175
- assert release in golden_library_index ["libraries" ]
252
+ # Find the golden master for the release
253
+ golden_release = None
254
+ for golden_release_candidate in golden_library_index ["libraries" ]:
255
+ if (
256
+ golden_release_candidate ["name" ] == release ["name" ]
257
+ and golden_release_candidate ["version" ] == release ["version" ]
258
+ ):
259
+ golden_release = golden_release_candidate
260
+ break
261
+
262
+ assert golden_release is not None # Matching golden release was found
263
+
264
+ # Small variation in size could result from compression algorithm changes, so we allow a tolerance
265
+ assert "size" in release
266
+ assert math .isclose (release ["size" ], golden_release ["size" ], rel_tol = size_comparison_tolerance )
267
+ # Remove size data so a direct comparison of the remaining data can be made against the golden master
268
+ del release ["size" ]
269
+ del golden_release ["size" ]
270
+
271
+ assert release == golden_release
176
272
177
273
178
274
# The engine's Git code struggles to get a clean checkout of releases under some circumstances.
0 commit comments