1+ import glob
12import os
23import platform
34import re
@@ -159,6 +160,9 @@ def test_file_contents(self):
159160 seen_sizes = []
160161 seen_exports = []
161162
163+ # Second wasm files are also emitted sometimes.
164+ seen_second_sizes = []
165+
162166 # The number of struct.news appears in the metrics report like this:
163167 #
164168 # StructNew : 18
@@ -179,23 +183,16 @@ def test_file_contents(self):
179183 with open (flags_file ) as f :
180184 self .assertEqual (f .read (), '--wasm-staging' )
181185
182- # The fuzz files begin with
183- #
184- # var binary = new Uint8Array([..binary data as numbers..]);
185- #
186- with open (fuzz_file ) as f :
187- first_line = f .readline ().strip ()
188- start = 'var binary = new Uint8Array(['
189- end = ']);'
190- self .assertTrue (first_line .startswith (start ))
191- self .assertTrue (first_line .endswith (end ))
192- numbers = first_line [len (start ):- len (end )]
193-
194- # Convert to binary, and see that it is a valid file.
195- numbers_array = [int (x ) for x in numbers .split (',' )]
196- binary_file = os .path .join (temp_dir .name , 'file.wasm' )
197- with open (binary_file , 'wb' ) as f :
198- f .write (bytes (numbers_array ))
186+ # Extract the wasm file(s) from the JS. Make sure to not notice
187+ # stale files.
188+ for f in glob .glob ('extracted*' ):
189+ os .unlink (f )
190+ extractor = shared .in_binaryen ('scripts' , 'clusterfuzz' , 'extract_wasms.py' )
191+ subprocess .check_call ([sys .executable , extractor , fuzz_file , 'extracted' ])
192+
193+ # One wasm file must always exist, and must be valid.
194+ binary_file = 'extracted.0.wasm'
195+ assert os .path .exists (binary_file )
199196 metrics = subprocess .check_output (
200197 shared .WASM_OPT + ['-all' , '--metrics' , binary_file , '-q' ], text = True )
201198
@@ -215,6 +212,19 @@ def test_file_contents(self):
215212 self .assertEqual (len (exports ), 1 )
216213 seen_exports .append (int (exports [0 ]))
217214
215+ # Sometimes a second wasm file should exist, and it must be valid
216+ # too.
217+ second_binary_file = 'extracted.1.wasm'
218+ if os .path .exists (second_binary_file ):
219+ subprocess .check_call (
220+ shared .WASM_OPT + ['-all' , second_binary_file , '-q' ])
221+
222+ # Note its size (we leave detailed metrics for the first one;
223+ # they are generated by the same logic in run.py, so just
224+ # verifying some valid second wasms are emitted, of random
225+ # sizes, is enough).
226+ seen_second_sizes .append (os .path .getsize (second_binary_file ))
227+
218228 print ()
219229
220230 print ('struct.news are distributed as ~ mean 15, stddev 24, median 10' )
@@ -247,17 +257,35 @@ def test_file_contents(self):
247257
248258 print ()
249259
260+ # Second files appear in ~ 1/3 of testcases.
261+ print ('number of second wasms should be around 33 +- 8' )
262+ print (f'number of second wasms: { len (seen_second_sizes )} ' )
263+ assert seen_second_sizes , 'must see at least one second wasm'
264+ print ('second sizes are distributed as ~ mean 2933, stddev 2011, median 2510' )
265+ print (f'mean sizes: { statistics .mean (seen_second_sizes )} ' )
266+ print (f'stdev sizes: { statistics .stdev (seen_second_sizes )} ' )
267+ print (f'median sizes: { statistics .median (seen_second_sizes )} ' )
268+ # Relax the assert on the max seen second size compared to the max seen
269+ # primary size, as we see fewer of these. 500 is still proof of an
270+ # interesting wasm file.
271+ self .assertGreaterEqual (max (seen_second_sizes ), 500 )
272+ self .assertGreater (statistics .stdev (seen_second_sizes ), 0 )
273+
274+ print ()
275+
250276 # To check for interesting JS file contents, we'll note how many times
251277 # we build and run the wasm.
252278 seen_builds = []
253279 seen_calls = []
280+ seen_second_builds = []
254281
255282 for i in range (1 , N + 1 ):
256283 fuzz_file = os .path .join (temp_dir .name , f'fuzz-binaryen-{ i } .js' )
257284 with open (fuzz_file ) as f :
258285 js = f .read ()
259286 seen_builds .append (js .count ('build(binary);' ))
260287 seen_calls .append (js .count ('callExports();' ))
288+ seen_second_builds .append (js .count ('build(secondBinary);' ))
261289
262290 # There is always one build and one call (those are in the default
263291 # fuzz_shell.js), and we add a couple of operations, each with equal
@@ -284,6 +312,17 @@ def test_file_contents(self):
284312
285313 print ()
286314
315+ # Second wasm files are more rarely added, only 1/3 of the time or so,
316+ # but over 100 samples we are still overwhelmingly likely to see one.
317+ print ('JS second builds are distributed as ~ mean 1.8, stddev 2.2, median 1' )
318+ print (f'mean JS second builds: { statistics .mean (seen_second_builds )} ' )
319+ print (f'stdev JS second builds: { statistics .stdev (seen_second_builds )} ' )
320+ print (f'median JS second builds: { statistics .median (seen_second_builds )} ' )
321+ self .assertGreaterEqual (max (seen_second_builds ), 2 )
322+ self .assertGreater (statistics .stdev (seen_second_builds ), 0 )
323+
324+ print ()
325+
287326 # "zzz" in test name so that this runs last. If it runs first, it can be
288327 # confusing as it appears next to the logging of which bundle we use (see
289328 # setUpClass).
0 commit comments