source: test/pyregfi-smoketest.py @ 278

Last change on this file since 278 was 265, checked in by tim, 13 years ago

fixes for smoketest script
added 1.0 targets for release

  • Property svn:executable set to *
File size: 10.0 KB
RevLine 
[213]1#!/usr/bin/env python3
[197]2
3import sys
[213]4import gc
[225]5import io
[215]6import time
[228]7import threading
[197]8import pyregfi
9
[225]10
[197]11
[232]12pyregfi.setLogMask((pyregfi.LOG_TYPES.INFO, pyregfi.LOG_TYPES.WARN, pyregfi.LOG_TYPES.ERROR))
[197]13
[213]14# Uses the HiveIterator to walk all keys
15# Gathers various (meaningless) statistics to exercise simple attribute access
16# and to hopefully smoke out any bugs that can be identified by changing stats
[225]17def iterTallyNames(hive, fh):
[213]18    key_count = 0
19    key_lens = 0
20    key_rawlens = 0
21    value_count = 0
22    value_lens = 0
23    value_rawlens = 0
[197]24
[213]25    for k in hive:
26        key_count += 1
27        if k.name != None:
28            key_lens += len(k.name)
29        if k.name_raw != None:
30            key_rawlens += len(k.name_raw)
[199]31
[213]32        for v in k.values:
33            value_count += 1
34            if v.name != None:
35                value_lens += len(v.name)
36            if v.name_raw != None:
37                value_rawlens += len(v.name_raw)
[200]38
[214]39    print("  Counts: keys=%d, values=%d" % (key_count, value_count))
40    print("  Total name length: keys=%d, values=%d" % (key_lens, value_lens))
41    print("  Total raw name lengths: keys=%d, values=%d" % (key_rawlens, value_rawlens))
[200]42
[209]43
[252]44# walks up parents to obtain path, rather than using downward links like iterator
[220]45def getCurrentPath(key):
46    if key == None:
47        return ''
48    path = []
49    p = key
50    while p != None:
51        path.append(p.name)
52        p = p.get_parent()
53    path.reverse()
54    del path[0]
55
56    return path
57
[215]58# For each key in the hive, this traverses the parent links up to the root,
59# recording the path as it goes, and then uses the subtree/descend method
60# to find the same key again, verifying it is the same.  This test is currently
61# very slow because no key caching is used.
[225]62def iterParentWalk(hive, fh):
[215]63    i = 1
64    for k in hive:
65        path = getCurrentPath(k)
66        try:
67            hive_iter = hive.subtree(path)
68            if hive_iter.current_key() != k:
69                print("WARNING: k != current_key for path '%s'." % path)
70            else:
71                i += 1
72        except Exception as e:
[252]73            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path,e.args,e))
[215]74    print("   Successfully tested paths on %d keys." % i)
[209]75
[215]76
[216]77# Uses the HiveIterator to walk all keys
78# Gathers various (meaningless) statistics about data/data_raw attributes
[225]79def iterTallyData(hive, fh):
[216]80    data_stat = 0.0
81    dataraw_stat = 0.0
82   
83    for k in hive:
84        for v in k.values:
[219]85            d = v.fetch_data()
[216]86            if d == None:
87                data_stat += 0.1
88            elif hasattr(d, "__len__"):
89                data_stat += len(d)
90            else:
91                data_stat += d/2.0**64
92
[219]93            d = v.fetch_raw_data()
[216]94            if d == None:
95                dataraw_stat += 0.1
96            else:
97                dataraw_stat += len(d)
98
99    print("  Data stat: %f" % data_stat)
100    print("  Raw data stat: %f" % dataraw_stat)
101
102
[217]103recurseKey_stat = 0.0
104recurseValue_stat = 0.0
105def checkValues(key):
106    global recurseKey_stat
107    global recurseValue_stat
[255]108    recurseKey_stat += (key.mtime - key.max_bytes_subkeyname) * key.flags
[217]109    for v in key.values:
110        recurseValue_stat += (v.data_off - v.data_size) / (1.0 + v.flags) + v.data_in_offset
[255]111        try:
112            value = key.values[v.name]
113            if v != value:
114                print("WARNING: iterator value '%s' does not match dictionary value '%s'." 
115                      % (v.name, value.name))
116        except Exception as e:
117                print("WARNING: iterator value name '%s' is not retrievable via value list\n"
118                      % (v.name,))
119       
[216]120
[217]121def recurseTree(cur, operation):
122    for k in cur.subkeys:
123        key = cur.subkeys[k.name]
124        if k != key:
125            print("WARNING: iterator subkey '%s' does not match dictionary subkey '%s'." 
126                  % (k.name, key.name))
127        del key
128        operation(k)
129        recurseTree(k, operation)
130
131# Retrieves all keys by recursion, rather than the iterator, and validates
132# list dictionary access.  Also builds nonsensical statistics as an excuse
133# to access various base structure attributes.
[225]134def recurseKeyTally(hive, fh):
[218]135    checkValues(hive.root)
136    recurseTree(hive.root, checkValues)
[217]137    print("  Key stat: %f" % recurseKey_stat)
138    print("  Value stat: %f" % recurseValue_stat)
139
140
[219]141# Iterates hive gathering stats about security and classname records
[225]142def iterFetchRelated(hive, fh):
[219]143    security_stat = 0.0
144    classname_stat = 0.0
145    modified_stat = 0.0
146
147    for k in hive:
148        cn = k.fetch_classname()
149        if cn == None:
150            classname_stat += 0.000001
151        elif type(cn) == bytearray:
152            classname_stat += len(cn)/2**32
153        else:
154            classname_stat += len(cn)
155
156        modified_stat += k.modified
157       
158    print("  Security stat: %f" % security_stat)
159    print("  Classname stat: %f" % classname_stat)
160    print("  Modified stat: %f" % modified_stat)
161
[220]162
163
[225]164def iterIterWalk(hive, fh):
[220]165    sk_stat = 0.0
166    v_stat = 0.0
167    iter = pyregfi.HiveIterator(hive)
168    for k in iter:
[252]169        path = iter.current_path()
[220]170        try:
[252]171            hive_iter = hive.subtree(path[1:])
[220]172            sk = hive_iter.first_subkey()
173            while sk != None:
174                ssk = hive_iter.find_subkey(sk.name)
[252]175                if ssk != None:
[262]176                    if ssk.name != None:
177                        sk_stat += len(ssk.name)
[252]178                else:
179                    print("WARNING: ssk was None")
[220]180                sk = hive_iter.next_subkey()
181
182            v = hive_iter.first_value()
183            while v != None:
184                vv = hive_iter.find_value(v.name)
[252]185                if vv != None:
[262]186                    if vv.name != None:
187                        v_stat += len(vv.name)
[252]188                else:
189                    print("WARNING: vv was None")
[220]190                v = hive_iter.next_value()
191
192        except Exception as e:
[252]193            print("WARNING: Could not descend to path '%s'.\nError:\n %s\n%s" % (path[1:],e.args,e))
[220]194    print("   Subkey stat: %f" % sk_stat)
195    print("   Value stat: %f" % v_stat)
196
197
[225]198def iterCallbackIO(hive, fh):
199    fh.seek(0)
200    new_fh = io.BytesIO(fh.read())
201    new_hive = pyregfi.Hive(new_fh)
[265]202    stat = 0
[225]203    for k in new_hive:
[265]204        stat += 1
205    print(%d keys found" % stat)
[220]206
[228]207
208def threadIterMain(iter):
209    x = 0
210    try:
211        for k in iter:
212            #x += len(k.name) + len(k.subkeys)
213            pass
214    except Exception as e:
215        print("%s dying young: %s" % (threading.current_thread().name, repr(e)))
216        # Exceptions are thrown on iteration because python state gets out of
217        # whack.  That's fine, because we're really just interested in finding
218        # segfaults.  People should not use iterators without locks, but it
219        # should at least not segfault on them.
220        pass
221    print("%s finished" % threading.current_thread().name)
222
223def iterMultithread(hive, fh):
224    num_threads = 10
225    iter = pyregfi.HiveIterator(hive)
226    threads = []
227    for t in range(0,num_threads):
228        threads.append(threading.Thread(target=threadIterMain, args=(iter,)))
229    for t in threads:
230        t.start()
231    for t in threads:
232        t.join()
[253]233
234
235def loopSecurity(hive, fh):
[262]236    cur = hive.root.fetch_security()
[265]237    first = cur
238    stat = 0
[262]239    while True:
240        stat += len(cur.descriptor.owner)
241        stat += len(cur.descriptor.group)
242        if cur.descriptor.sacl:
243            stat += len(cur.descriptor.sacl)
244        if cur.descriptor.dacl:
245            stat += len(cur.descriptor.dacl)
246       
247        nxt = cur.next_security()
[265]248        if first == nxt:
[262]249            break
[265]250        cur = nxt
251    print("  Security stat: %d" % stat)
[253]252
[265]253
[253]254def iterSecurity(hive, fh):
255    stat = 0
256    for k in hive:
257        security = k.fetch_security()
258        stat += security.ref_count
259        stat += len(security.descriptor.owner)
260        stat += len(security.descriptor.group)
261        if security.descriptor.sacl:
262            for ace in security.descriptor.sacl:
263                stat += ace.flags
264                if ace.object:
265                    stat += ace.object.int
266                if ace.inherited_object:
267                    stat += ace.inherited_object.int
[228]268
[253]269        if security.descriptor.dacl:
270            for ace in security.descriptor.dacl:
271                stat += ace.flags
272                if ace.object:
273                    stat += ace.object.int
274                if ace.inherited_object:
275                    stat += ace.inherited_object.int
276    print("  Security stat: %d" % stat)
277
[255]278
[227]279tests = {
280    "iterTallyNames":iterTallyNames,
281    "iterParentWalk":iterParentWalk,
282    "iterTallyData":iterTallyData,
283    "recurseKeyTally":recurseKeyTally,
284    "iterFetchRelated":iterFetchRelated,
285    "iterIterWalk":iterIterWalk,
286    "iterCallbackIO":iterCallbackIO,
[228]287    "iterMultithread":iterMultithread,
[253]288    "loopSecurity":loopSecurity,
289    "iterSecurity":iterSecurity,
[227]290    }
[209]291
[227]292def usage():
[262]293    sys.stderr.write("USAGE: pyregfi-smoketest.py { test1[,test2[,...]] | * } hive1 [hive2 ...]\n")
[227]294    sys.stderr.write("\tAvailable tests:\n")
295    for t in tests.keys():
296        sys.stderr.write("\t\t%s\n" % t)
[215]297
298
[227]299if len(sys.argv) < 3:
300    usage()
301    sys.exit(1)
[220]302
[262]303if sys.argv[1] == '*':
304    selected_tests = tests.keys()
305else:
306    selected_tests = sys.argv[1].split(',')
307    for st in selected_tests:
308        if st not in tests:
309            usage()
310            sys.stderr.write("ERROR: %s not a valid test type\n\n" % st)
311            sys.exit(1)
[220]312
[213]313files = []
[227]314for f in sys.argv[2:]:
[224]315    files.append((f, open(f,"rb")))
[213]316
317
[215]318start_time = time.time()
[213]319for hname,fh in files:
[255]320    #hive = pyregfi.Hive(fh)
321    hive = pyregfi.openHive(hname)
[227]322    for tname in selected_tests:
323        t = tests[tname]
[215]324        teststart = time.time()
[213]325        tstr = "'%s' on '%s'" % (tname,hname)
326        print("##BEGIN %s:" % tstr)
[225]327        t(hive, fh)
[215]328        print("##END %s; runtime=%f; messages:" % (tstr, time.time() - teststart))
[232]329        print(pyregfi.getLogMessages())
[213]330        print
[215]331        sys.stdout.flush()
[224]332    fh.close()
[213]333
[215]334hive = None
[213]335files = None
336tests = None
337gc.collect()
[215]338print("### Tests Completed, runtime: %f ###" % (time.time() -  start_time))
[214]339#print(gc.garbage)
Note: See TracBrowser for help on using the repository browser.