︙ | | |
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
-
+
|
;; PURPOSE.
;;======================================================================
;;======================================================================
;; Test info panel
;;======================================================================
(use format)
(use format fmt)
(require-library iup)
(import (prefix iup iup:))
(use canvas-draw)
(use sqlite3 srfi-1 posix regex regex-case srfi-69)
(import (prefix sqlite3 sqlite3:))
|
︙ | | |
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
|
+
+
+
+
|
(lambda (testdat)
(db:test-get-id testdat)))
)))))
;;======================================================================
;; Test meta panel
;;======================================================================
(define (test-meta-panel-get-description testmeta)
(fmt #f (with-width 40 (wrap-lines (db:testmeta-get-description testmeta)))))
(define (test-meta-panel testmeta store-meta)
(iup:frame
#:title "Test Meta Data" ; #:expand "YES"
(iup:hbox ; #:expand "YES"
(apply iup:vbox ; #:expand "YES"
(append (map (lambda (val)
(iup:label val ; #:expand "HORIZONTAL"
|
︙ | | |
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
|
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
|
-
-
+
+
+
-
+
-
+
+
+
|
(store-meta "reviewed"
(iup:label (db:testmeta-get-reviewed testmeta) #:expand "HORIZONTAL")
(lambda (testmeta)(db:testmeta-get-reviewed testmeta)))
(store-meta "tags"
(iup:label (db:testmeta-get-tags testmeta) #:expand "HORIZONTAL")
(lambda (testmeta)(db:testmeta-get-tags testmeta)))
(store-meta "description"
(iup:label (db:testmeta-get-description testmeta) #:size "x50"); #:expand "HORIZONTAL")
(lambda (testmeta)(db:testmeta-get-description testmeta)))
(iup:label (test-meta-panel-get-description testmeta) #:size "x50"); #:expand "HORIZONTAL")
(lambda (testmeta)
(test-meta-panel-get-description testmeta)))
)))))
;;======================================================================
;; Run info panel
;;======================================================================
(define (run-info-panel keydat testdat runname)
(iup:frame
#:title "Megatest Run Info" ; #:expand "YES"
(iup:hbox ; #:expand "YES"
(apply iup:vbox ; #:expand "YES"
(append (map (lambda (keyval)
(iup:label (conc (car keyval) " ") ; #:expand "HORIZONTAL"
))
keydat)
(list (iup:label "runname "))))
(list (iup:label "runname ")(iup:label "run-id"))))
(apply iup:vbox
(append (map (lambda (keyval)
(iup:label (cadr keyval) #:expand "HORIZONTAL"))
keydat)
(list (iup:label runname)(iup:label "" #:expand "VERTICAL")))))))
(list (iup:label runname)
(iup:label (conc (db:test-get-run_id testdat)))
(iup:label "" #:expand "VERTICAL")))))))
;;======================================================================
;; Host info panel
;;======================================================================
(define (host-info-panel testdat store-label)
(iup:frame
#:title "Remote host and Test Run Info" ; #:expand "YES"
|
︙ | | |
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
|
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
|
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
|
(command-text-box (iup:textbox #:expand "HORIZONTAL" #:font "Courier New, -10"))
(command-launch-button (iup:button "Execute!" #:action (lambda (x)
(let ((cmd (iup:attribute command-text-box "VALUE")))
(system (conc cmd " &"))))))
(run-test (lambda (x)
(iup:attribute-set!
command-text-box "VALUE"
(conc "xterm -geometry 180x20 -e \"megatest -runtests " testname " -target " keystring " :runname " runname
" -itempatt " (if (equal? item-path "")
"%"
item-path)
(conc "xterm -geometry 180x20 -e \"megatest -target " keystring " :runname " runname
" -runtests " (conc testname "/" (if (equal? item-path "")
"%"
item-path))
";echo Press any key to continue;bash -c 'read -n 1 -s'\""))))
(remove-test (lambda (x)
(iup:attribute-set!
command-text-box "VALUE"
(conc "xterm -geometry 180x20 -e \"megatest -remove-runs -target " keystring " :runname " runname " -testpatt " testname " -itempatt "
(if (equal? item-path "")
"%"
item-path)
(conc "xterm -geometry 180x20 -e \"megatest -remove-runs -target " keystring " :runname " runname
" -testpatt " (conc testname "/" (if (equal? item-path "")
"%"
item-path))
" -v;echo Press any key to continue;bash -c 'read -n 1 -s'\"")))))
(cond
((not testdat)(begin (print "ERROR: bad test info for " test-id)(exit 1)))
((not rundat)(begin (print "ERROR: found test info but there is a problem with the run info for " run-id)(exit 1)))
(else
;; (test-set-status! db run-id test-name state status itemdat)
(set! self ;
|
︙ | | |
︙ | | |
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
|
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
|
-
+
-
+
-
+
|
(define (colors-similar? color1 color2)
(let* ((c1 (map string->number (string-split color1)))
(c2 (map string->number (string-split color2)))
(delta (map (lambda (a b)(abs (- a b))) c1 c2)))
(null? (filter (lambda (x)(> x 3)) delta))))
;; keypatts: ( (KEY1 "abc%def")(KEY2 "%") )
(define (update-rundat runnamepatt numruns testnamepatt itemnamepatt keypatts)
(define (update-rundat runnamepatt numruns testnamepatt keypatts)
(let ((modtime (file-modification-time *db-file-path*)))
(if (or (and (> modtime *last-db-update-time*)
(> (current-seconds)(+ *last-db-update-time* 5)))
(> *delayed-update* 0))
(begin
(debug:print 4 "INFO: update-rundat runnamepatt: " runnamepatt " numruns: " numruns " testnamepatt: " testnamepatt " itemnamepatt: " itemnamepatt " keypatts: " keypatts)
(debug:print 4 "INFO: update-rundat runnamepatt: " runnamepatt " numruns: " numruns " testnamepatt: " testnamepatt " keypatts: " keypatts)
(set! *please-update-buttons* #t)
(set! *last-db-update-time* modtime)
(set! *delayed-update* (- *delayed-update* 1))
(let* ((allruns (open-run-close db:get-runs *db* runnamepatt numruns ;; (+ numruns 1) ;; (/ numruns 2))
*start-run-offset* keypatts))
(header (db:get-header allruns))
(runs (db:get-rows allruns))
(result '())
(maxtests 0)
(states (hash-table-keys *state-ignore-hash*))
(statuses (hash-table-keys *status-ignore-hash*)))
(debug:print 6 "update-rundat, got " (length runs) " runs")
(if (> (+ *last-update* 300) (current-seconds)) ;; every five minutes
(begin
(set! *last-update* (current-seconds))
(set! *tot-run-count* (length runs)))) ;; (rdb:get-num-runs *db* runnamepatt))))
(for-each (lambda (run)
(let* ((run-id (db:get-value-by-header run header "id"))
(tests (let ((tsts (open-run-close db:get-tests-for-run *db* run-id testnamepatt itemnamepatt states statuses)))
(tests (let ((tsts (open-run-close db:get-tests-for-run *db* run-id testnamepatt states statuses)))
(if *tests-sort-reverse* (reverse tsts) tsts)))
(key-vals (open-run-close db:get-key-vals *db* run-id)))
(if (> (length tests) maxtests)
(set! maxtests (length tests)))
(if (or (not *hide-empty-runs*) ;; this reduces the data burden when set
(not (null? tests)))
(set! result (cons (vector run tests key-vals) result)))))
|
︙ | | |
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
|
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
|
-
+
-
-
-
-
+
+
+
+
+
|
;; controls (along bottom)
(set! controls
(iup:hbox
(iup:vbox
(iup:frame
#:title "filter test and items"
(iup:hbox
(iup:textbox #:size "60x15" #:fontsize "10" #:value "%"
(iup:textbox #:size "120x15" #:fontsize "10" #:value "%"
#:action (lambda (obj unk val)
(mark-for-update)
(update-search "test-name" val)))
(iup:textbox #:size "60x15" #:fontsize "10" #:value "%"
#:action (lambda (obj unk val)
(mark-for-update)
(update-search "item-name" val)))))
;;(iup:textbox #:size "60x15" #:fontsize "10" #:value "%"
;; #:action (lambda (obj unk val)
;; (mark-for-update)
;; (update-search "item-name" val))
))
(iup:vbox
(iup:hbox
(iup:button "Sort" #:action (lambda (obj)
(set! *tests-sort-reverse* (not *tests-sort-reverse*))
(iup:attribute-set! obj "TITLE" (if *tests-sort-reverse* "+Sort" "-Sort"))
(mark-for-update)))
(iup:button "HideEmpty" #:action (lambda (obj)
|
︙ | | |
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
|
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
|
-
-
+
+
-
-
+
+
|
(vector keycol lftcol header runsvec)))
(if (or (args:get-arg "-rows")
(get-environment-variable "DASHBOARDROWS" ))
(begin
(set! *num-tests* (string->number (or (args:get-arg "-rows")
(get-environment-variable "DASHBOARDROWS"))))
(update-rundat "%" *num-runs* "%" "%" '()))
(set! *num-tests* (min (max (update-rundat "%" *num-runs* "%" "%" '()) 8) 20)))
(update-rundat "%" *num-runs* "%/%" '()))
(set! *num-tests* (min (max (update-rundat "%" *num-runs* "%/%" '()) 8) 20)))
(define *tim* (iup:timer))
(define *ord* #f)
(iup:attribute-set! *tim* "TIME" 300)
(iup:attribute-set! *tim* "RUN" "YES")
;; Move this stuff to db.scm FIXME
;;
(define *last-db-update-time* (file-modification-time (conc *toppath* "/megatest.db")))
(define (db:been-changed)
(> (file-modification-time (conc *toppath* "/megatest.db")) *last-db-update-time*))
(define (db:set-db-update-time)
(set! *last-db-update-time* (file-modification-time (conc *toppath* "/megatest.db"))))
(define (run-update x)
(update-buttons uidat *num-runs* *num-tests*)
;; (if (db:been-changed)
(begin
(update-rundat (hash-table-ref/default *searchpatts* "runname" "%") *num-runs*
(hash-table-ref/default *searchpatts* "test-name" "%")
(hash-table-ref/default *searchpatts* "item-name" "%")
(hash-table-ref/default *searchpatts* "test-name" "%/%")
;; (hash-table-ref/default *searchpatts* "item-name" "%")
(let ((res '()))
(for-each (lambda (key)
(if (not (equal? key "runname"))
(let ((val (hash-table-ref/default *searchpatts* key #f)))
(if val (set! res (cons (list key val) res))))))
*dbkeys*)
res))
|
︙ | | |
︙ | | |
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
-
+
|
((string-match (regexp "no" #t) syncval) 0)
((string-match (regexp "(off|normal|full)" #t) syncval) syncval)
(else
(debug:print 0 "ERROR: synchronous must be 0,1,2,OFF,NORMAL or FULL, you provided: " syncval)
#f))))
(if val
(begin
(debug:print 2 "INFO: Setting pragma synchronous to " val)
(debug:print 4 "INFO: Setting pragma synchronous to " val)
(sqlite3:execute db (conc "PRAGMA synchronous = '" val "';"))))))
(define (open-db) ;; (conc *toppath* "/megatest.db") (car *configinfo*)))
(let* ((dbpath (conc *toppath* "/megatest.db")) ;; fname)
(dbexists (file-exists? dbpath))
(db (sqlite3:open-database dbpath)) ;; (never-give-up-open-db dbpath))
(handler (make-busy-timeout (if (args:get-arg "-override-timeout")
|
︙ | | |
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
|
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
|
-
+
|
(set! res (cons (vector key keytype) res)))
db
"SELECT fieldname,fieldtype FROM keys ORDER BY id DESC;")
(set! *db-keys* res)
res)))
(define (db:get-value-by-header row header field)
;; (debug:print 2 "db:get-value-by-header row: " row " header: " header " field: " field)
(debug:print 4 "INFO: db:get-value-by-header row: " row " header: " header " field: " field)
(if (null? header) #f
(let loop ((hed (car header))
(tal (cdr header))
(n 0))
(if (equal? hed field)
(vector-ref row n)
(if (null? tal) #f (loop (car tal)(cdr tal)(+ n 1)))))))
|
︙ | | |
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
|
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
|
+
-
+
|
;; make a query (fieldname like 'patt1' OR fieldname
(define (db:patt->like fieldname pattstr #!key (comparator " OR "))
(let ((patts (if (string? pattstr)
(string-split pattstr ",")
'("%"))))
(string-intersperse (map (lambda (patt)
(let ((wildtype (if (substring-index "%" patt) "LIKE" "GLOB")))
(conc fieldname " LIKE '" patt "'"))
(conc fieldname " " wildtype " '" patt "'")))
(if (null? patts)
'("")
patts))
comparator)))
;; replace header and keystr with a call to runs:get-std-run-fields
;;
|
︙ | | |
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
|
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
|
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
|
#f))
;; states and statuses are lists, turn them into ("PASS","FAIL"...) and use NOT IN
;; i.e. these lists define what to NOT show.
;; states and statuses are required to be lists, empty is ok
;; not-in #t = above behaviour, #f = must match
(define (db:get-tests-for-run db run-id testpatt itempatt states statuses
(define (db:get-tests-for-run db run-id testpatt states statuses
#!key (not-in #t)
(sort-by #f) ;; 'rundir 'event_time
)
(let* ((res '())
;; if states or statuses are null then assume match all when not-in is false
(states-qry (if (null? states)
#f
(conc " state "
(if not-in "NOT" "")
" IN ('"
(states-str (conc " state in ('" (string-intersperse states "','") "')"))
(statuses-str (conc " status in ('" (string-intersperse statuses "','") "')"))
(state-status-qry (if (or (not (null? states))
(not (null? states)))
(conc " AND " (if not-in "NOT" "") " (" states-str " AND " statuses-str ") ")
""))
(qry (conc "SELECT id,run_id,testname,state,status,event_time,host,cpuload,diskfree,uname,rundir,item_path,run_duration,final_logf,comment "
" FROM tests WHERE run_id=? AND "
(string-intersperse states "','")
"')")))
(statuses-qry (if (null? statuses)
#f
(conc " status "
(if not-in "NOT" "")
" IN ('"
(string-intersperse statuses "','")
"')")))
(tests-match-qry (tests:match->sqlqry testpatt))
(qry (conc "SELECT id,run_id,testname,state,status,event_time,host,cpuload,diskfree,uname,rundir,item_path,run_duration,final_logf,comment "
" FROM tests WHERE run_id=? "
;; testname like ? AND item_path LIKE ? "
(db:patt->like "testname" testpatt) " AND "
(if states-qry (conc " AND " states-qry) "")
(db:patt->like "item_path" itempatt)
state-status-qry
(case sort-by
((rundir) " ORDER BY length(rundir) DESC;")
((event_time) " ORDER BY event_time ASC;")
(else ";"))
(if statuses-qry (conc " AND " statuses-qry) "")
(if tests-match-qry (conc " AND (" tests-match-qry ") ") "")
(case sort-by
((rundir) " ORDER BY length(rundir) DESC;")
((event_time) " ORDER BY event_time ASC;")
(else ";"))
)))
(debug:print 8 "INFO: db:get-tests-for-run qry=" qry)
(sqlite3:for-each-row
(lambda (a . b) ;; id run-id testname state status event-time host cpuload diskfree uname rundir item-path run-duration final-logf comment)
(set! res (cons (apply vector a b) res))) ;; id run-id testname state status event-time host cpuload diskfree uname rundir item-path run-duration final-logf comment) res)))
db
qry
|
︙ | | |
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
|
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
|
-
+
|
;; speed up for common cases with a little logic
(define (db:test-set-state-status-by-id db test-id newstate newstatus newcomment)
(cond
((and newstate newstatus newcomment)
(sqlite3:exectute db "UPDATE tests SET state=?,status=?,comment=? WHERE id=?;" newstate newstatus test-id))
((and newstate newstatus)
(sqlite3:exectute db "UPDATE tests SET state=?,status=? WHERE id=?;" newstate newstatus test-id))
(sqlite3:execute db "UPDATE tests SET state=?,status=? WHERE id=?;" newstate newstatus test-id))
(else
(if newstate (sqlite3:execute db "UPDATE tests SET state=? WHERE id=?;" newstate test-id))
(if newstatus (sqlite3:execute db "UPDATE tests SET status=? WHERE id=?;" newstatus test-id))
(if newcomment (sqlite3:execute db "UPDATE tests SET comment=? WHERE id=?;" newcomment test-id)))))
(define (db:test-set-state-status-by-run-id-testname db run-id test-name item-path status state)
(sqlite3:execute db "UPDATE tests SET state=?,status=?,event_time=strftime('%s','now') WHERE run_id=? AND testname=? AND item_path=?;"
|
︙ | | |
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
|
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
|
-
-
+
+
-
-
-
+
+
+
|
(debug:print 0 "ERROR: db:test-set-log! called with non-string log file name " logf)))
;;======================================================================
;; Misc. test related queries
;;======================================================================
(define (db:test-get-paths-matching db keynames target fnamepatt #!key (res '()))
(let* ((itempatt (if (args:get-arg "-itempatt")(args:get-arg "-itempatt") "%"))
(testpatt (if (args:get-arg "-testpatt")(args:get-arg "-testpatt") "%"))
(let* ((testpatt (if (args:get-arg "-testpatt")(args:get-arg "-testpatt") "%"))
(statepatt (if (args:get-arg ":state") (args:get-arg ":state") "%"))
(statuspatt (if (args:get-arg ":status") (args:get-arg ":status") "%"))
(runname (if (args:get-arg ":runname") (args:get-arg ":runname") "%"))
(keystr (string-intersperse
(map (lambda (key val)
(conc "r." key " like '" val "'"))
keynames
(string-split target "/"))
" AND "))
(testqry (tests:match->sqlqry testpatt))
(qrystr (conc "SELECT t.rundir FROM tests AS t INNER JOIN runs AS r ON t.run_id=r.id WHERE "
keystr " AND r.runname LIKE '" runname "' AND item_path LIKE '" itempatt "' AND testname LIKE '"
testpatt "' AND t.state LIKE '" statepatt "' AND t.status LIKE '" statuspatt
"'ORDER BY t.event_time ASC;")))
keystr " AND r.runname LIKE '" runname "' AND " testqry
" AND t.state LIKE '" statepatt "' AND t.status LIKE '" statuspatt
"' ORDER BY t.event_time ASC;")))
(debug:print 3 "qrystr: " qrystr)
(sqlite3:for-each-row
(lambda (p)
(set! res (cons p res)))
db
qrystr)
(if fnamepatt
|
︙ | | |
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
|
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
|
-
+
|
'()
(let* ((unmet-pre-reqs '())
(result '()))
(for-each
(lambda (waitontest-name)
;; by getting the tests with matching name we are looking only at the matching test
;; and related sub items
(let ((tests (db:get-tests-for-run db run-id waitontest-name #f '() '()))
(let ((tests (db:get-tests-for-run db run-id waitontest-name '() '()))
(ever-seen #f)
(parent-waiton-met #f)
(item-waiton-met #f))
(for-each
(lambda (test)
;; (if (equal? waitontest-name (db:test-get-testname test)) ;; by defintion this had better be true ...
(let* ((state (db:test-get-state test))
|
︙ | | |
︙ | | |
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
|
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
|
-
-
+
+
-
-
+
+
-
-
+
|
Usage: megatest [options]
-h : this help
Launching and managing runs
-runall : run all tests that are not state COMPLETED and status PASS,
CHECK or KILLED
-runtests tst1,tst2 ... : run tests
-remove-runs : remove the data for a run, requires :runname, -testpatt and
-itempatt be set. Optionally use :state and :status
-remove-runs : remove the data for a run, requires :runname and -testpatt
Optionally use :state and :status
-set-state-status X,Y : set state to X and status to Y, requires controls per -remove-runs
-rerun FAIL,WARN... : force re-run for tests with specificed status(s)
-rollup : fill run (set by :runname) with latest test(s) from
prior runs with same keys
-rollup : (currently disabled) fill run (set by :runname) with latest test(s)
from prior runs with same keys
-lock : lock run specified by target and runname
-unlock : unlock run specified by target and runname
Selectors (e.g. use for -runtests, -remove-runs, -set-state-status, -list-runs etc.)
-target key1/key2/... : run for key1, key2, etc.
-reqtarg key1/key2/... : run for key1, key2, etc. but key1/key2 must be in runconfig
-testpatt patt : % is wildcard
-itempatt patt : % is wildcard
-testpatt patt1/patt2,patt3/... : % is wildcard
:runname : required, name for this particular test run
:state : Applies to runs, tests or steps depending on context
:status : Applies to runs, tests or steps depending on context
Test helpers (for use inside tests)
-step stepname
-test-status : set the state and status of a test (use :state and :status)
|
︙ | | |
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
-
-
|
-update-meta : update the tests metadata for all tests
-env2file fname : write the environment to fname.csh and fname.sh
-setvars VAR1=val1,VAR2=val2 : Add environment variables to a run NB// these are
overwritten by values set in config files.
-server -|hostname : start the server (reduces contention on megatest.db), use
- to automatically figure out hostname
-repl : start a repl (useful for extending megatest)
-debug N : increase verbosity to N. (try 10 for lots of noise)
-logging : turn on logging all debug output to logging.db
Spreadsheet generation
-extract-ods fname.ods : extract an open document spreadsheet from the database
-pathmod path : insert path, i.e. path/runame/itempath/logfile.html
will clear the field if no rundir/testname/itempath/logfile
if it contains forward slashes the path will be converted
to windows style
|
︙ | | |
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
-
|
"-rebuild-db"
"-rollup"
"-update-meta"
"-gen-megatest-area"
"-v" ;; verbose 2, more than normal (normal is 1)
"-q" ;; quiet 0, errors/warnings only
"-logging"
)
args:arg-hash
0))
(if (args:get-arg "-h")
(begin
(print help)
|
︙ | | |
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
((args:get-arg "-q") 0)
(else 1)))
(if (not (number? *verbosity*))
(begin
(print "ERROR: Invalid debug value " (args:get-arg "-debug"))
(exit)))
(if (args:get-arg "-logging")(set! *logging* #t))
(if (> *verbosity* 3) ;; we are obviously debugging
(set! open-run-close open-run-close-no-exception-handling))
;; to try and not burden Kim too much...
(if (args:get-arg "-itempatt")
(let ((old-testpatt (args:get-arg "-testpatt")))
(debug:print 0 "ERROR: parameter \"-itempatt\" has been deprecated. For now I will tweak your -testpatt for you")
(hash-table-set! args:arg-hash "-testpatt" (conc old-testpatt "/" (args:get-arg "-itempatt")))
(debug:print 0 " old: " old-testpatt ", new: " (args:get-arg "-testpatt"))
(if (args:get-arg "-runtests")
(begin
(debug:print 0 "NOTE: Also modifying -runtests")
(hash-table-set! args:arg-hash "-runtests" (conc (args:get-arg "-runtests") "/"
(args:get-arg "-itempatt")))))
))
;;======================================================================
;; Misc general calls
;;======================================================================
(if (args:get-arg "-env2file")
(begin
|
︙ | | |
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
|
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
|
-
-
-
-
|
(cond
((not (args:get-arg ":runname"))
(debug:print 0 "ERROR: Missing required parameter for " action ", you must specify the run name pattern with :runname patt")
(exit 2))
((not (args:get-arg "-testpatt"))
(debug:print 0 "ERROR: Missing required parameter for " action ", you must specify the test pattern with -testpatt")
(exit 3))
((not (args:get-arg "-itempatt"))
(print "ERROR: Missing required parameter for " action ", you must specify the items with -itempatt")
(exit 4))
(else
(if (not (car *configinfo*))
(begin
(debug:print 0 "ERROR: Attempted " action "on test(s) but run area config file not found")
(exit 1))
;; put test parameters into convenient variables
(runs:operate-on action
(args:get-arg ":runname")
(args:get-arg "-testpatt")
(args:get-arg "-itempatt")
state: (args:get-arg ":state")
status: (args:get-arg ":status")
new-state-status: (args:get-arg "-set-state-status")))
(set! *didsomething* #t))))
(if (args:get-arg "-remove-runs")
(general-run-call
|
︙ | | |
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
|
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
|
-
-
+
|
;;======================================================================
(if (args:get-arg "-list-runs")
(if (setup-for-run)
(let* ((db #f)
(runpatt (args:get-arg "-list-runs"))
(testpatt (args:get-arg "-testpatt"))
(itempatt (args:get-arg "-itempatt"))
(runsdat (open-run-close db:get-runs db runpatt #f #f '()))
(runs (db:get-rows runsdat))
(header (db:get-header runsdat))
(keys (open-run-close db:get-keys db))
(keynames (map key:get-fieldname keys)))
;; Each run
(for-each
(lambda (run)
(debug:print 1 "Run: "
(string-intersperse (map (lambda (x)
(db:get-value-by-header run header x))
keynames) "/")
"/"
(db:get-value-by-header run header "runname")
" status: " (db:get-value-by-header run header "state"))
(let ((run-id (open-run-close db:get-value-by-header run header "id")))
(let ((tests (open-run-close db:get-tests-for-run db run-id testpatt itempatt '() '())))
(let ((tests (open-run-close db:get-tests-for-run db run-id testpatt '() '())))
;; Each test
(for-each
(lambda (test)
(format #t
" Test: ~25a State: ~15a Status: ~15a Runtime: ~5@as Time: ~22a Host: ~10a\n"
(conc (db:test-get-testname test)
(if (equal? (db:test-get-item-path test) "")
|
︙ | | |
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
|
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
|
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
|
args:arg-hash))))
;;======================================================================
;; Rollup into a run
;;======================================================================
(if (args:get-arg "-rollup")
(begin
(debug:print 0 "ERROR: Rollup is currently not working. If you need it please submit a ticket at http://www.kiatoa.com/fossils/megatest")
(exit 4)))
(general-run-call
"-rollup"
"rollup tests"
(lambda (target runname keys keynames keyvallst)
(runs:rollup-run keys
(keys->alist keys "na")
(args:get-arg ":runname")
user))))
;; (general-run-call
;; "-rollup"
;; "rollup tests"
;; (lambda (target runname keys keynames keyvallst)
;; (runs:rollup-run keys
;; (keys->alist keys "na")
;; (args:get-arg ":runname")
;; user))))
;;======================================================================
;; Lock or unlock a run
;;======================================================================
(if (or (args:get-arg "-lock")(args:get-arg "-unlock"))
(general-run-call
|
︙ | | |
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
|
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
|
-
-
+
|
(begin
(debug:print 0 "ERROR: -target is required.")
(exit 1)))
(if (not (setup-for-run))
(begin
(debug:print 0 "Failed to setup, giving up on -test-paths or -test-files, exiting")
(exit 1)))
(let* ((itempatt (args:get-arg "-itempatt"))
(keys (open-run-close db:get-keys db))
(let* ((keys (open-run-close db:get-keys db))
(keynames (map key:get-fieldname keys))
(paths (open-run-close db:test-get-paths-matching db keynames target (args:get-arg "-test-files"))))
(set! *didsomething* #t)
(for-each (lambda (path)
(print path))
paths)))
;; else do a general-run-call
|
︙ | | |
1
2
3
4
5
6
7
8
9
|
1
2
3
4
5
6
7
8
9
|
-
+
|
;; Copyright 2006-2011, Matthew Welland.
;; Copyright 2006-2012, Matthew Welland.
;;
;; This program is made available under the GNU GPL version 2.0 or
;; greater. See the accompanying file COPYING for details.
;;
;; This program is distributed WITHOUT ANY WARRANTY; without even the
;; implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;; PURPOSE.
|
︙ | | |
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
|
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
|
-
+
-
+
+
+
-
+
+
-
+
+
+
-
+
|
;; runs:get-runs-by-patt
;; get runs by list of criteria
;; register a test run with the db
;;
;; Use: (db-get-value-by-header (db:get-header runinfo)(db:get-row runinfo))
;; to extract info from the structure returned
;;
(define (runs:get-runs-by-patt db keys runnamepatt . params) ;; test-name)
(define (runs:get-runs-by-patt db keys runnamepatt) ;; test-name)
(let* ((keyvallst (keys->vallist keys))
(tmp (runs:get-std-run-fields keys '("id" "runname" "state" "status" "owner" "event_time")))
(keystr (car tmp))
(header (cadr tmp))
(res '())
(key-patt ""))
(key-patt "")
(runwildtype (if (substring-index "%" runnamepatt) "like" "glob"))
(qry-str #f))
(for-each (lambda (keyval)
(let* ((key (vector-ref keyval 0))
(fulkey (conc ":" key))
(patt (args:get-arg fulkey)))
(patt (args:get-arg fulkey))
(wildtype (if (substring-index "%" patt) "like" "glob")))
(if patt
(set! key-patt (conc key-patt " AND " key " like '" patt "'"))
(set! key-patt (conc key-patt " AND " key " " wildtype " '" patt "'"))
(begin
(debug:print 0 "ERROR: searching for runs with no pattern set for " fulkey)
(exit 6)))))
keys)
(set! qry-str (conc "SELECT " keystr " FROM runs WHERE runname " runwildtype " ? " key-patt ";"))
(debug:print 4 "INFO: runs:get-runs-by-patt qry=" qry-str " " runnamepatt)
(sqlite3:for-each-row
(lambda (a . r)
(set! res (cons (list->vector (cons a r)) res)))
db
(conc "SELECT " keystr " FROM runs WHERE runname like ? " key-patt ";")
qry-str
runnamepatt)
(vector header res)))
(define (runs:test-get-full-path test)
(let* ((testname (db:test-get-testname test))
(itempath (db:test-get-item-path test)))
(conc testname (if (equal? itempath "") "" (conc "(" itempath ")")))))
|
︙ | | |
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
|
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
-
-
-
-
-
-
-
-
-
-
+
|
(if (file-exists? runconfigf)
(open-run-close setup-env-defaults db runconfigf run-id *already-seen-runconfig-info* "pre-launch-env-vars")
(debug:print 0 "WARNING: You do not have a run config file: " runconfigf))
;; look up all tests matching the comma separated list of globs in
;; test-patts (using % as wildcard)
(for-each
(lambda (patt)
(let ((tests (glob (conc *toppath* "/tests/" (string-translate patt "%" "*")))))
(set! tests (filter (lambda (test)(file-exists? (conc test "/testconfig"))) tests))
(set! test-names (append test-names
(map (lambda (testp)
(last (string-split testp "/")))
tests)))))
(if test-patts (string-split test-patts ",")(list "%")))
;; now remove duplicates
(set! test-names (tests:get-valid-tests *toppath* test-patts test-names: test-names))
(set! test-names (delete-duplicates test-names))
(debug:print 0 "INFO: test names " test-names)
;; on the first pass or call to run-tests set FAILS to NOT_STARTED if
;; -keepgoing is specified
(if (eq? *passnum* 0)
|
︙ | | |
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
|
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
|
-
+
|
(if (not (null? remtests))
(loop (car remtests)(cdr remtests)))))))
(if (not (null? required-tests))
(debug:print 1 "INFO: Adding " required-tests " to the run queue"))
;; NOTE: these are all parent tests, items are not expanded yet.
(debug:print 4 "INFO: test-records=" (hash-table->alist test-records))
(runs:run-tests-queue run-id runname test-records keyvallst flags)
(runs:run-tests-queue run-id runname test-records keyvallst flags test-patts)
(debug:print 4 "INFO: All done by here")))
(define (runs:calc-fails prereqs-not-met)
(filter (lambda (test)
(and (vector? test) ;; not (string? test))
(equal? (db:test-get-state test) "COMPLETED")
(not (member (db:test-get-status test)
|
︙ | | |
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
|
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
|
-
+
-
|
(conc (db:test-get-testname t) ":" (db:test-get-state t) "/" (db:test-get-status t))))
lst))
(define (runs:make-full-test-name testname itempath)
(if (equal? itempath "") testname (conc testname "/" itempath)))
;; test-records is a hash table testname:item_path => vector < testname testconfig waitons priority items-info ... >
(define (runs:run-tests-queue run-id runname test-records keyvallst flags)
(define (runs:run-tests-queue run-id runname test-records keyvallst flags test-patts)
;; At this point the list of parent tests is expanded
;; NB// Should expand items here and then insert into the run queue.
(debug:print 5 "test-records: " test-records ", keyvallst: " keyvallst " flags: " (hash-table->alist flags))
(let ((sorted-test-names (tests:sort-by-priority-and-waiton test-records))
(item-patts (hash-table-ref/default flags "-itempatt" #f))
(test-registery (make-hash-table))
(num-retries 0)
(max-retries (config-lookup *configdat* "setup" "maxretries")))
(set! max-retries (if (and max-retries (string->number max-retries))(string->number max-retries) 100))
(if (not (null? sorted-test-names))
(let loop ((hed (car sorted-test-names))
(tal (cdr sorted-test-names))
|
︙ | | |
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
|
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
|
-
-
+
-
+
|
(debug:print 4 "INFO: hed=" hed)
;; Don't know at this time if the test have been launched at some time in the past
;; i.e. is this a re-launch?
(debug:print 4 "INFO: run-limits-info = " run-limits-info)
(cond ;; INNER COND #1 for a launchable test
;; Check item path against item-patts
((and (not (patt-list-match item-path item-patts))
(not (equal? item-path "")))
((not (tests:match test-patts (tests:testqueue-get-testname test-record) item-path)) ;; This test/itempath is not to be run
;; else the run is stuck, temporarily or permanently
;; but should check if it is due to lack of resources vs. prerequisites
(debug:print 1 "INFO: Skipping " (tests:testqueue-get-testname test-record) " " item-path " as it doesn't match " item-patts)
(debug:print 1 "INFO: Skipping " (tests:testqueue-get-testname test-record) " " item-path " as it doesn't match " test-patts)
(thread-sleep! *global-delta*)
(if (not (null? tal))
(loop (car tal)(cdr tal) reruns)))
((and (not (hash-table-ref/default test-registery (runs:make-full-test-name test-name item-path) #f))
(and max-concurrent-jobs (> (- max-concurrent-jobs num-running) 5)))
(open-run-close db:tests-register-test #f run-id test-name item-path)
(hash-table-set! test-registery (runs:make-full-test-name test-name item-path) #t)
|
︙ | | |
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
|
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
|
-
+
|
(pp items))
(for-each
(lambda (my-itemdat)
(let* ((new-test-record (let ((newrec (make-tests:testqueue)))
(vector-copy! test-record newrec)
newrec))
(my-item-path (item-list->path my-itemdat)))
(if (patt-list-match my-item-path item-patts) ;; yes, we want to process this item, NOTE: Should not need this check here!
(if (tests:match test-patts hed my-item-path) ;; (patt-list-match my-item-path item-patts) ;; yes, we want to process this item, NOTE: Should not need this check here!
(let ((newtestname (runs:make-full-test-name hed my-item-path))) ;; test names are unique on testname/item-path
(tests:testqueue-set-items! new-test-record #f)
(tests:testqueue-set-itemdat! new-test-record my-itemdat)
(tests:testqueue-set-item_path! new-test-record my-item-path)
(hash-table-set! test-records newtestname new-test-record)
(set! tal (cons newtestname tal)))))) ;; since these are itemized create new test names testname/itempath
items)
|
︙ | | |
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
|
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
|
-
+
-
+
+
+
+
+
-
-
+
+
-
+
+
+
+
-
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
-
+
-
+
+
|
;; fields are passing in through
;; action:
;; 'remove-runs
;; 'set-state-status
;;
;; NB// should pass in keys?
;;
(define (runs:operate-on action runnamepatt testpatt itempatt #!key (state #f)(status #f)(new-state-status #f))
(define (runs:operate-on action runnamepatt testpatt #!key (state #f)(status #f)(new-state-status #f))
(let* ((db #f)
(keys (open-run-close db:get-keys db))
(rundat (open-run-close runs:get-runs-by-patt db keys runnamepatt))
(header (vector-ref rundat 0))
(runs (vector-ref rundat 1))
(states (if state (string-split state ",") '()))
(statuses (if status (string-split status ",") '()))
(state-status (if (string? new-state-status) (string-split new-state-status ",") '(#f #f))))
(debug:print 2 "Header: " header " action: " action " new-state-status: " new-state-status)
(debug:print 4 "INFO: runs:operate-on => Header: " header " action: " action " new-state-status: " new-state-status)
(if (> 2 (length state-status))
(begin
(debug:print 0 "ERROR: the parameter to -set-state-status is a comma delimited string. E.g. COMPLETED,FAIL")
(exit)))
(for-each
(lambda (run)
(let ((runkey (string-intersperse (map (lambda (k)
(db:get-value-by-header run header (vector-ref k 0))) keys) "/"))
(dirs-to-remove (make-hash-table)))
(let* ((run-id (db:get-value-by-header run header "id"))
(run-state (db:get-value-by-header run header "state"))
(tests (if (not (equal? run-state "locked"))
(open-run-close db:get-tests-for-run db (db:get-value-by-header run header "id")
testpatt itempatt states statuses
(open-run-close db:get-tests-for-run db run-id
testpatt states statuses
not-in: #f
sort-by: (case action
((remove-runs) 'rundir)
(else 'event_time)))
'()))
(lasttpath "/does/not/exist/I/hope"))
(debug:print 4 "INFO: runs:operate-on run=" run ", header=" header)
(if (not (null? tests))
(begin
(case action
((remove-runs)
(debug:print 1 "Removing tests for run: " runkey " " (db:get-value-by-header run header "runname")))
((set-state-status)
(debug:print 1 "Modifying state and staus for tests for run: " runkey " " (db:get-value-by-header run header "runname")))
((print-run)
(debug:print 1 "Printing info for run " runkey ", run=" run ", tests=" tests ", header=" header)
action)
(else
(print "INFO: action not recognised " action)))
(for-each
(lambda (test)
(let* ((item-path (db:test-get-item-path test))
(test-name (db:test-get-testname test))
(run-dir (db:test-get-rundir test))
(run-dir (db:test-get-rundir test)) ;; run dir is from the link tree
(real-dir (if (file-exists? run-dir)
(resolve-pathname run-dir)
#f))
(test-id (db:test-get-id test)))
;; (tdb (db:open-test-db run-dir)))
(debug:print 1 " " (db:test-get-testname test) " id: " (db:test-get-id test) " " item-path " action: " action)
(debug:print 4 "INFO: test=" test) ;; " (db:test-get-testname test) " id: " (db:test-get-id test) " " item-path " action: " action)
(case action
((remove-runs) ;; the tdb is for future possible.
(open-run-close db:delete-test-records db #f (db:test-get-id test))
(debug:print 1 "INFO: Attempting to remove dir " run-dir)
(if (and (> (string-length run-dir) 5)
(file-exists? run-dir)) ;; bad heuristic but should prevent /tmp /home etc.
(let* ((realpath (resolve-pathname run-dir)))
(debug:print 1 "INFO: Real path of is " realpath)
(if (file-exists? realpath)
(if (> (system (conc "rm -rf " realpath)) 0)
(debug:print 0 "ERROR: There was a problem removing " realpath " with rm -f"))
(debug:print 0 "WARNING: test run dir " realpath " appears to not exist"))
(if (file-exists? run-dir) ;; the link
(if (symbolic-link? run-dir)
(delete-file run-dir)
(if (directory? run-dir)
(if (> (directory-fold (lambda (f x)(+ 1 x)) 0 run-dir) 0)
(debug:print 0 "WARNING: refusing to remove " run-dir " as it is not empty")
(delete-directory run-dir)) ;; it should be empty by here BUG BUG, add error catch
(debug:print 0 "ERROR: refusing to remove " run-dir " as it is neither a symlink nor a directory")
))))
(debug:print 1 "INFO: Attempting to remove dir " real-dir " and link " run-dir)
(if (and real-dir
(> (string-length real-dir) 5)
(file-exists? real-dir)) ;; bad heuristic but should prevent /tmp /home etc.
(begin ;; let* ((realpath (resolve-pathname run-dir)))
(debug:print 1 "INFO: Recursively removing " real-dir)
(if (file-exists? real-dir)
(if (> (system (conc "rm -rf " real-dir)) 0)
(debug:print 0 "ERROR: There was a problem removing " real-dir " with rm -f"))
(debug:print 0 "WARNING: test run dir " real-dir " appears to not exist")))
(debug:print 0 "WARNING: directory " real-dir " does not exist"))
(if (symbolic-link? run-dir)
(begin
(debug:print 1 "INFO: Removing symlink " run-dir)
(delete-file run-dir))
(if (directory? run-dir)
(if (> (directory-fold (lambda (f x)(+ 1 x)) 0 run-dir) 0)
(debug:print 0 "WARNING: refusing to remove " run-dir " as it is not empty")
(delete-directory run-dir)) ;; it should be empty by here BUG BUG, add error catch
(debug:print 0 "ERROR: refusing to remove " run-dir " as it either doesn't exist or is not a symlink or directory")
)))
(debug:print 0 "WARNING: directory already removed " run-dir)))
((set-state-status)
(debug:print 2 "INFO: new state " (car state-status) ", new status " (cadr state-status))
(open-run-close db:test-set-state-status-by-id db (db:test-get-id test) (car state-status)(cadr state-status) #f)))))
(sort tests (lambda (a b)(let ((dira (db:test-get-rundir a))
tests)))
(dirb (db:test-get-rundir b)))
(if (and (string? dira)(string? dirb))
(> (string-length dira)(string-length dirb))
#f)))))))
;; remove the run if zero tests remain
(if (eq? action 'remove-runs)
(let ((remtests (open-run-close db:get-tests-for-run db (db:get-value-by-header run header "id") #f #f '("DELETED") '("n/a") not-in: #t)))
(let ((remtests (open-run-close db:get-tests-for-run db (db:get-value-by-header run header "id") #f '("DELETED") '("n/a") not-in: #t)))
(if (null? remtests) ;; no more tests remaining
(let* ((dparts (string-split lasttpath "/"))
(runpath (conc "/" (string-intersperse
(take dparts (- (length dparts) 1))
"/"))))
(debug:print 1 "Removing run: " runkey " " (db:get-value-by-header run header "runname") " and related record")
(open-run-close db:delete-run db run-id)
;; This is a pretty good place to purge old DELETED tests
(open-run-close db:delete-tests-for-run db run-id)
(open-run-close db:delete-old-deleted-test-records db)
(open-run-close db:set-var db "DELETED_TESTS" (current-seconds))
;; need to figure out the path to the run dir and remove it if empty
;; (if (null? (glob (conc runpath "/*")))
;; (begin
;; (debug:print 1 "Removing run dir " runpath)
;; (system (conc "rmdir -p " runpath))))
)))))
))
runs)))
runs))
#t)
;;======================================================================
;; Routines for manipulating runs
;;======================================================================
;; Since many calls to a run require pretty much the same setup
;; this wrapper is used to reduce the replication of code
|
︙ | | |
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
|
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
|
-
+
|
;; This could probably be refactored into one complex query ...
(define (runs:rollup-run keys keyvallst runname user) ;; was target, now keyvallst
(debug:print 4 "runs:rollup-run, keys: " keys " keyvallst: " keyvallst " :runname " runname " user: " user)
(let* ((db #f) ;; (keyvalllst (keys:target->keyval keys target))
(new-run-id (open-run-close runs:register-run db keys keyvallst runname "new" "n/a" user))
(prev-tests (open-run-close test:get-matching-previous-test-run-records db new-run-id "%" "%"))
(curr-tests (open-run-close db:get-tests-for-run db new-run-id "%" "%" '() '()))
(curr-tests (open-run-close db:get-tests-for-run db new-run-id "%/%" '() '()))
(curr-tests-hash (make-hash-table)))
(open-run-close db:update-run-event_time db new-run-id)
;; index the already saved tests by testname and itemdat in curr-tests-hash
(for-each
(lambda (testdat)
(let* ((testname (db:test-get-testname testdat))
(item-path (db:test-get-item-path testdat))
|
︙ | | |
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
|
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
|
-
+
|
(new-test-record #f))
;; replace these with insert ... select
(apply sqlite3:execute
db
(conc "INSERT OR REPLACE INTO tests (run_id,testname,state,status,event_time,host,cpuload,diskfree,uname,rundir,item_path,run_duration,final_logf,comment) "
"VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?);")
new-run-id (cddr (vector->list testdat)))
(set! new-testdat (car (open-run-close db:get-tests-for-run db new-run-id testname item-path '() '())))
(set! new-testdat (car (open-run-close db:get-tests-for-run db new-run-id (conc testname "/" item-path) '() '())))
(hash-table-set! curr-tests-hash full-name new-testdat) ;; this could be confusing, which record should go into the lookup table?
;; Now duplicate the test steps
(debug:print 4 "Copying records in test_steps from test_id=" (db:test-get-id testdat) " to " (db:test-get-id new-testdat))
(open-run-close
(lambda ()
(sqlite3:execute
db
|
︙ | | |
︙ | | |
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
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
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
(declare (uses runconfig))
(include "common_records.scm")
(include "key_records.scm")
(include "db_records.scm")
(include "run_records.scm")
(include "test_records.scm")
(define (tests:get-valid-tests testsdir test-patts #!key (test-names '()))
(let ((tests (glob (conc testsdir "/tests/*")))) ;; " (string-translate patt "%" "*")))))
(set! tests (filter (lambda (test)(file-exists? (conc test "/testconfig"))) tests))
(delete-duplicates
(append test-names
(filter (lambda (testname)
(tests:match test-patts testname #f))
(map (lambda (testp)
(last (string-split testp "/")))
tests))))))
;; tests:glob-like-match
(define (tests:glob-like-match patt str)
(let ((like (substring-index "%" patt)))
(let* ((notpatt (equal? (substring-index "~" patt) 0))
(newpatt (if notpatt (substring patt 1) patt))
(finpatt (if like
(string-substitute (regexp "%") ".*" newpatt)
(string-substitute (regexp "\\*") ".*" newpatt)))
(res #f))
;; (print "tests:glob-like-match => notpatt: " notpatt ", newpatt: " newpatt ", finpatt: " finpatt)
(set! res (string-match (regexp finpatt (if like #t #f)) str))
(if notpatt (not res) res))))
;; if itempath is #f then look only at the testname part
;;
(define (tests:match patterns testname itempath)
(if (string? patterns)
(let ((patts (string-split patterns ",")))
(if (null? patts) ;;; no pattern(s) means no match
#f
(let loop ((patt (car patts))
(tal (cdr patts)))
;; (print "loop: patt: " patt ", tal " tal)
(if (string=? patt "")
#f ;; nothing ever matches empty string - policy
(let* ((patt-parts (string-match (regexp "^([^\\/]*)(\\/(.*)|)$") patt))
(test-patt (cadr patt-parts))
(item-patt (cadddr patt-parts)))
;; (print "tests:match => patt-parts: " patt-parts ", test-patt: " test-patt ", item-patt: " item-patt)
(if (and (tests:glob-like-match test-patt testname)
(or (not itempath)
(tests:glob-like-match (if item-patt item-patt "") itempath)))
#t
(if (null? tal)
#f
(loop (car tal)(cdr tal)))))))))))
;; if itempath is #f then look only at the testname part
;;
(define (tests:match->sqlqry patterns)
(if (string? patterns)
(let ((patts (string-split patterns ",")))
(if (null? patts) ;;; no pattern(s) means no match, we will do no query
#f
(let loop ((patt (car patts))
(tal (cdr patts))
(res '()))
;; (print "loop: patt: " patt ", tal " tal)
(let* ((patt-parts (string-match (regexp "^([^\\/]*)(\\/(.*)|)$") patt))
(test-patt (cadr patt-parts))
(item-patt (cadddr patt-parts))
(test-qry (db:patt->like "testname" test-patt))
(item-qry (db:patt->like "item_path" item-patt))
(qry (conc "(" test-qry " AND " item-qry ")")))
;; (print "tests:match => patt-parts: " patt-parts ", test-patt: " test-patt ", item-patt: " item-patt)
(if (null? tal)
(string-intersperse (append (reverse res)(list qry)) " OR ")
(loop (car tal)(cdr tal)(cons qry res)))))))
#f))
;; get the previous record for when this test was run where all keys match but runname
;; returns #f if no such test found, returns a single test record if found
(define (test:get-previous-test-run-record db run-id test-name item-path)
(let* ((keys (db:get-keys db))
(selstr (string-intersperse (map (lambda (x)(vector-ref x 0)) keys) ","))
(qrystr (string-intersperse (map (lambda (x)(conc (vector-ref x 0) "=?")) keys) " AND "))
|
︙ | | |
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
-
+
|
(conc "SELECT id FROM runs WHERE " qrystr " AND id != ?;") (append keyvals (list run-id)))
;; for each run starting with the most recent look to see if there is a matching test
;; if found then return that matching test record
(debug:print 4 "selstr: " selstr ", qrystr: " qrystr ", keyvals: " keyvals ", previous run ids found: " prev-run-ids)
(if (null? prev-run-ids) #f
(let loop ((hed (car prev-run-ids))
(tal (cdr prev-run-ids)))
(let ((results (db:get-tests-for-run db hed test-name item-path '() '())))
(let ((results (db:get-tests-for-run db hed (conc test-name "/" item-path)'() '())))
(debug:print 4 "Got tests for run-id " run-id ", test-name " test-name ", item-path " item-path ": " results)
(if (and (null? results)
(not (null? tal)))
(loop (car tal)(cdr tal))
(if (null? results) #f
(car results))))))))))
|
︙ | | |
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
|
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
-
+
|
;; collect all matching tests for the runs then
;; extract the most recent test and return that.
(debug:print 4 "selstr: " selstr ", qrystr: " qrystr ", keyvals: " keyvals
", previous run ids found: " prev-run-ids)
(if (null? prev-run-ids) '() ;; no previous runs? return null
(let loop ((hed (car prev-run-ids))
(tal (cdr prev-run-ids)))
(let ((results (db:get-tests-for-run db hed test-name item-path '() '())))
(let ((results (db:get-tests-for-run db hed (conc test-name "/" item-path) '() '())))
(debug:print 4 "Got tests for run-id " run-id ", test-name " test-name
", item-path " item-path " results: " (intersperse results "\n"))
;; Keep only the youngest of any test/item combination
(for-each
(lambda (testdat)
(let* ((full-testname (conc (db:test-get-testname testdat) "/" (db:test-get-item-path testdat)))
(stored-test (hash-table-ref/default tests-hash full-testname #f)))
|
︙ | | |
︙ | | |
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
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
|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
|
;;======================================================================
;; P R O C E S S E S
;;======================================================================
(test "cmd-run-with-stderr->list" '("No such file or directory")
(let ((reslst (cmd-run-with-stderr->list "ls" "/tmp/ihadbetternotexist")))
(string-search (regexp "No such file or directory")(car reslst))))
;;======================================================================
;; T E S T M A T C H I N G
;;======================================================================
;; tests:glob-like-match
(test #f '("abc") (tests:glob-like-match "abc" "abc"))
(for-each
(lambda (patt str expected)
(test (conc patt " " str "=>" expected) expected (tests:glob-like-match patt str)))
(list "abc" "~abc" "~abc" "a*c" "a%c")
(list "abc" "abcd" "abc" "ABC" "ABC")
(list '("abc") #t #f #f '("ABC"))
)
;; tests:match
(test #f #t (tests:match "abc/def" "abc" "def"))
(for-each
(lambda (patterns testname itempath expected)
(test (conc patterns " " testname "/" itempath "=>" expected)
expected
(tests:match patterns testname itempath)))
(list "abc" "abc/%" "ab%/c%" "~abc/c%" "abc/~c%" "a,b/c,%/d")
(list "abc" "abc" "abcd" "abc" "abc" "a" )
(list "" "" "cde" "cde" "cde" "" )
(list #t #t #t #f #f #t))
;; db:patt->like
(test #f "testname LIKE 't%'" (db:patt->like "testname" "t%" comparator: " AND "))
(test #f "testname LIKE 't%' AND testname LIKE '%t'" (db:patt->like "testname" "t%,%t" comparator: " AND "))
(test #f "item_path GLOB ''" (db:patt->like "item_path" ""))
;; test:match->sqlqry
(test #f "(testname GLOB 'a' AND item_path GLOB 'b') OR (testname LIKE 'a%' AND item_path LIKE '%') OR (testname GLOB '' AND item_path LIKE 'b%')"
(tests:match->sqlqry "a/b,a%,/b%"))
(test #f "(testname GLOB 'a' AND item_path GLOB 'b') OR (testname LIKE 'a%' AND item_path LIKE '%') OR (testname LIKE '%' AND item_path LIKE 'b%')"
(tests:match->sqlqry "a/b,a%,%/b%"))
;; (exit)
;;======================================================================
;; C O N F I G F I L E S
;;======================================================================
(define conffile #f)
(test "Read a config" #t (hash-table? (read-config "test.config" #f #f)))
|
︙ | | |
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
|
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
|
-
+
-
+
+
+
+
+
+
+
+
+
+
|
(rdb:tests-register-test #f 1 "nada" "")
;; (rdb:flush-queue)
(vector-ref (open-run-close db:get-test-info #f 1 "nada" "") 3)))
(test "get-keys" "SYSTEM" (vector-ref (car (db:get-keys *db*)) 0));; (key:get-fieldname (car (sort (db-get-keys *db*)(lambda (a b)(string>=? (vector-ref a 0)(vector-ref b 0)))))))
(define remargs (args:get-args
'("bar" "foo" ":runname" "bob" ":sysname" "ubuntu" ":fsname" "nfs" ":datapath" "blah/foo" "nada")
'("bar" "foo" ":runname" "bob" ":SYSTEM" "ubuntu" ":RELEASE" "v1.2" ":datapath" "blah/foo" "nada")
(list ":runname" ":state" ":status")
(list "-h")
args:arg-hash
0))
(test "register-run" #t (number? (runs:register-run *db*
(db:get-keys *db*)
'(("SYSTEM" "key1")("OS" "key2"))
'(("SYSTEM" "key1")("RELEASE" "key2"))
"myrun"
"new"
"n/a"
"bob")))
(define keys (db:get-keys *db*))
;;======================================================================
;; D B
;;======================================================================
(test #f "FOO LIKE 'abc%def'" (db:patt->like "FOO" "abc%def"))
(test #f (vector '("SYSTEM" "RELEASE" "id" "runname" "state" "status" "owner" "event_time") '())
(runs:get-runs-by-patt db keys "%"))
(test #f "SYSTEM,RELEASE,id,runname,state,status,owner,event_time" (car (runs:get-std-run-fields keys '("id" "runname" "state" "status" "owner" "event_time"))))
(test #f #t (runs:operate-on 'print "%" "%" "%"))
;;(test "update-test-info" #t (test-update-meta-info *db* 1 "nada"
(setenv "BLAHFOO" "1234")
(unsetenv "NADAFOO")
(test "env temp overrides" "xyz" (let ((prevvals (alist->env-vars '(("BLAHFOO" 4321)("NADAFOO" xyz))))
(result (get-environment-variable "NADAFOO")))
(alist->env-vars prevvals)
|
︙ | | |
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
|
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
|
-
+
-
+
+
+
|
(change-directory test-work-dir)
(test "Add a step" #t
(begin
(db:teststep-set-status! db 2 "step1" "start" 0 "This is a comment" "mylogfile.html")
(sleep 2)
(db:teststep-set-status! db 2 "step1" "end" "pass" "This is a different comment" "finallogfile.html")
(set! test-id (db:test-get-id (car (db:get-tests-for-run db 1 "test1" "" '() '()))))
(set! test-id (db:test-get-id (car (db:get-tests-for-run db 1 "test1" '() '()))))
(number? test-id)))
(test "Get rundir" #t (let ((rundir (db:test-get-rundir-from-test-id db test-id)))
(print "Rundir" rundir)
(string? rundir)))
(test "Create a test db" "../simpleruns/key1/key2/myrun/test1/testdat.db" (let ((tdb (db:open-test-db-by-test-id db test-id)))
(sqlite3#finalize! tdb)
(file-exists? "../simpleruns/key1/key2/myrun/test1/testdat.db")))
(test "Get steps for test" #t (> (length (db:get-steps-for-test db test-id)) 0))
(test "Get nice table for steps" "2s"
(test "Get nice table for steps" "2.0s"
(begin
(vector-ref (hash-table-ref (db:get-steps-table db test-id) "step1") 4)))
;; (exit)
;;======================================================================
;; R E M O T E C A L L S
;;======================================================================
;; start a server process
(set! *verbosity* 10)
|
︙ | | |
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
|
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
|
-
+
|
("COMPLETED" "PASS" #f)
("NOT_STARTED" "FAIL" "Just testing")
("KILLED" "UNKNOWN" "More testing")
("KILLED" "UNKNOWN" "More testing")
))
;; now set all tests to completed
(rdb:flush-queue)
(let ((tests (open-run-close db:get-tests-for-run #f 1 "%" "%" '() '())))
(let ((tests (open-run-close db:get-tests-for-run #f 1 "%" '() '())))
(print "Setting " (length tests) " to COMPLETED/PASS")
(for-each
(lambda (test)
(rdb:test-set-status-state (db:test-get-id test) "COMPLETED" "PASS" "Forced pass"))
tests))
(print "Waiting for server to be done, should be about 20 seconds")
|
︙ | | |