Megatest

Check-in [baf93f49cf]
Login
Overview
Comment:Partially broken implementation of steps data move to testrundat
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | test-specific-db
Files: files | file ages | folders
SHA1: baf93f49cfece3d3501e2efc75c9e539c4dbb6c0
User & Date: mrwellan on 2012-09-18 17:31:34
Other Links: branch diff | manifest | tags
Context
2012-09-18
17:31
Partially broken implementation of steps data move to testrundat check-in: b95aecf28b user: mrwellan tags: test-specific-db
17:31
Partially broken implementation of steps data move to testrundat check-in: baf93f49cf user: mrwellan tags: test-specific-db
02:49
Competed initial implementation of testrundat check-in: 75c8dc4713 user: matt tags: test-specific-db
Changes

Modified common.scm from [7138a29341] to [16ce44f288].

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
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







+












-
+
+
+








(define getenv get-environment-variable)

(define home (getenv "HOME"))
(define user (getenv "USER"))

;; global gletches
(define *db-keys* #f)
(define *configinfo* #f)
(define *configdat*  #f)
(define *toppath*    #f)
(define *already-seen-runconfig-info* #f)
(define *waiting-queue*     (make-hash-table))
(define *test-meta-updated* (make-hash-table))
(define *globalexitstatus*  0) ;; attempt to work around possible thread issues
(define *passnum*           0) ;; when running track calls to run-tests or similar
(define *verbosity*         1)
(define *rpc:listener*      #f) ;; if set up for server communication this will hold the tcp port
(define *runremote*         #f) ;; if set up for server communication this will hold <host port>
(define *last-db-access*    0)  ;; update when db is accessed via server
(define *target*            #f) ;; cache the target here; target is keyval1/keyval2/.../keyvalN
(define *target*            (make-hash-table)) ;; cache the target here; target is keyval1/keyval2/.../keyvalN
(define *keys*              (make-hash-table)) ;; cache the keys here
(define *keyvals*           (make-hash-table))
(define *toptest-paths*     (make-hash-table)) ;; cache toptest path settings here
(define *run-info-cache* (make-hash-table)) ;; run info is stable, no need to reget

(define (get-with-default val default)
  (let ((val (args:get-arg val)))
    (if val val default)))

Modified db.scm from [7749e22ea8] to [0c68fc0a7e].

170
171
172
173
174
175
176





177
178
179
180
181
182
183
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188







+
+
+
+
+







    (if (not dbexists)
	(begin
	  (sqlite3:execute db "PRAGMA synchronous = FULL;")
	  (debug:print 0 "Initialized test database " dbpath)
	  (db:testdb-initialize db)))
    (sqlite3:execute db "PRAGMA synchronous = 0;")
    db))

;; find and open the testdat.db file for an existing test
(define (db:open-test-db-by-test-id db test-id)
  (let* ((test-path (db:test-get-rundir db test-id)))
    (open-test-db test-path)))

(define (db:testdb-initialize db)
  (for-each
   (lambda (sqlcmd)
     (sqlite3:execute db sqlcmd))
   (list "CREATE TABLE IF NOT EXISTS test_rundat (
              id INTEGER PRIMARY KEY,
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
326
327
328
329
330
331
332


333
334
335
336
337
338
339







-
-








(define (db:set-var db var val)
  (sqlite3:execute db "INSERT OR REPLACE INTO metadat (var,val) VALUES (?,?);" var val))

;; use a global for some primitive caching, it is just silly to re-read the db 
;; over and over again for the keys since they never change

(define *db-keys* #f)

(define (db:get-keys db)
  (if *db-keys* *db-keys* 
      (let ((res '()))
	(sqlite3:for-each-row 
	 (lambda (key keytype)
	   (set! res (cons (vector key keytype) res)))
	 db
483
484
485
486
487
488
489



490
491
492
493
494
495
496
497
498
499
500
501
502















503
504
505

506
507
508
509
510
511






512
513
514
515
516
517
518
486
487
488
489
490
491
492
493
494
495













496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514






515
516
517
518
519
520
521
522
523
524
525
526
527







+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



+
-
-
-
-
-
-
+
+
+
+
+
+







	    (set! res (cons (list (key:get-fieldname key) key-val) res)))
	  db qry run-id)))
     keys)
    (reverse res)))

;; get key vals for a given run-id
(define (db:get-key-vals db run-id)
  (let ((mykeyvals (hash-table-ref/default *keyvals* run-id #f)))
    (if mykeyvals 
	mykeyvals
  (let* ((keys (get-keys db))
	 (res  '()))
    (debug:print 6 "keys: " keys " run-id: " run-id)
    (for-each 
     (lambda (key)
       (let ((qry (conc "SELECT " (key:get-fieldname key) " FROM runs WHERE id=?;")))
	 ;; (debug:print 0 "qry: " qry)
	 (sqlite3:for-each-row 
	  (lambda (key-val)
	    (set! res (cons key-val res)))
	  db qry run-id)))
     keys)
    (reverse res)))
	(let* ((keys (get-keys db))
	       (res  '()))
	  (debug:print 6 "keys: " keys " run-id: " run-id)
	  (for-each 
	   (lambda (key)
	     (let ((qry (conc "SELECT " (key:get-fieldname key) " FROM runs WHERE id=?;")))
	       ;; (debug:print 0 "qry: " qry)
	       (sqlite3:for-each-row 
		(lambda (key-val)
		  (set! res (cons key-val res)))
		db qry run-id)))
	   keys)
	  (let ((final-res (reverse res)))
	    (hash-table-set! *keyvals* run-id final-res)
	    final-res)))))

;; The target is keyval1/keyval2..., cached in *target* as it is used often
(define (db:get-target db run-id)
  (let ((mytarg (hash-table-ref/default *target* run-id #f)))
  (if *target*
      *target*
      (let* ((keyvals (rdb:get-key-vals db run-id))
	     (thekey  (string-intersperse (map (lambda (x)(if x x "-na-")) keyvals) "/")))
	(set! *target* thekey)
	thekey)))
    (if mytarg
	mytarg
	(let* ((keyvals (db:get-key-vals db run-id)) ;; (rdb:get-key-vals db run-id))
	       (thekey  (string-intersperse (map (lambda (x)(if x x "-na-")) keyvals) "/")))
	  (hash-table-set! *target* run-id thekey)
	  thekey))))

;;======================================================================
;;  T E S T S
;;======================================================================

;; states and statuses are lists, turn them into ("PASS","FAIL"...) and use NOT IN
;; i.e. these lists define what to NOT show.
550
551
552
553
554
555
556
557

558
559

560
561
562
563
564
565
566

567
568

569
570

571
572

573
574
575
576
577
578
579
559
560
561
562
563
564
565

566
567

568







569


570


571


572
573
574
575
576
577
578
579







-
+

-
+
-
-
-
-
-
-
-
+
-
-
+
-
-
+
-
-
+







     run-id
     ;; (if testpatt testpatt "%")
     ;; (if itempatt itempatt "%"))
     )
    res))

;; this one is a bit broken BUG FIXME
(define (db:delete-test-step-records db run-id test-name itemdat)
(define (db:delete-test-step-records db test-id)
  ;; Breaking it into two queries for better file access interleaving
  (let ((ids '()))
  (let* ((tdb (db:open-test-db-by-test-id db test-id)))
    (sqlite3:for-each-row (lambda (id)
			    (set! ids (cons id ids)))
			  db
			  "SELECT id FROM tests WHERE run_id=? AND testname=? AND item_path=?;"
			  run-id test-name (item-list->path itemdat))
    (for-each (lambda (id)
		(sqlite3:execute db "DELETE FROM test_steps WHERE test_id=?;" id)
    (sqlite3:execute tdb "DELETE FROM test_steps;")
		(thread-sleep! 0.1) ;; give others access to the db
                (sqlite3:execute db "DELETE FROM test_data WHERE test_id=?;" id)
    (sqlite3:execute tdb "DELETE FROM test_data;")
                (thread-sleep! 0.1)) ;; give others access to the db
	      ids)))
    (sqlite3:finalize! tdb)))
;;"DELETE FROM test_steps WHERE test_id in (SELECT id FROM tests WHERE run_id=? AND testname=? AND item_path=?);" 
		   

;; 
(define (db:delete-test-records db test-id)
  (sqlite3:execute db "DELETE FROM test_steps WHERE test_id=?;" test-id)
  (sqlite3:execute db "DELETE FROM test_data  WHERE test_id=?;" test-id)
  (sqlite3:execute db "DELETE FROM tests WHERE id=?;" test-id))

;; set tests with state currstate and status currstatus to newstate and newstatus
670
671
672
673
674
675
676















677
678
679
680
681
682
683
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







;;
(define (db:test-set-rundir! db run-id test-name item-path rundir)
  (sqlite3:execute 
   db 
   "UPDATE tests SET rundir=? WHERE run_id=? AND testname=? AND item_path=?;"
   rundir run-id test-name item-path))

;; 
(define (db:test-get-rundir db test-id)
  (let ((res (hash-table-ref/default *test-paths* test-id #f)))
    (if res
	res
	(begin
	  (sqlite3:for-each-row
	   (lambda (tpath)
	     (set! res tpath))
	   db 
	   "SELECT rundir FROM tests WHERE id=?;"
	   test-id)
	  (hash-table-set! *test-paths* test-id res)
	  res))))

(define (db:test-set-log! db test-id logf)
  (if (string? logf)
      (sqlite3:execute db "UPDATE tests SET final_logf=? WHERE id=?;"
		   logf test-id)
      (debug:print 0 "ERROR: db:test-set-log! called with non-string log file name " logf)))

;;======================================================================
804
805
806
807
808
809
810

811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833























834
835
836
837
838
839
840
819
820
821
822
823
824
825
826























827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856







+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







;; 					    test-id)) ;; run-id test-name item-path minutes cpuload diskfree tmpfree) 
;; 			      *incoming-data*))
;;   (mutex-unlock! *incoming-mutex*)
;;   (if *cache-on*
;;       (debug:print 6 "INFO: *cache-on* is " *cache-on* ", skipping cache write as part of test-update-meta-info")
;;       (db:write-cached-data db)))
;; 

;; (define (db:write-cached-data db)
;;   (let ((meta-stmt (sqlite3:prepare db "UPDATE tests SET cpuload=?,diskfree=?,run_duration=?,state='RUNNING' WHERE id=? AND state NOT IN ('COMPLETED','KILLREQ','KILLED');"))
;; 	(step-stmt (sqlite3:prepare db "INSERT OR REPLACE into test_steps (test_id,stepname,state,status,event_time,comment,logfile) VALUES(?,?,?,?,?,?,?);")) ;; strftime('%s','now')#f)
;; 	(data (sort *incoming-data* (lambda (a b)(< (vector-ref a 1)(vector-ref b 1))))))
;;     (if (> (length data) 0)
;; 	(debug:print 4 "Writing cached data " data))
;;     (mutex-lock! *incoming-mutex*)
;;     (sqlite3:with-transaction 
;;      db
;;      (lambda ()
;;        (for-each (lambda (entry)
;; 		   (case (vector-ref entry 0)
;; 		     ((meta-info)
;; 		      (apply sqlite3:execute meta-stmt (vector-ref entry 2)))
;; 		     ((step-status)
;; 		      (apply sqlite3:execute step-stmt (vector-ref entry 2)))
;; 		     (else
;; 		      (debug:print 0 "ERROR: Queued entry not recognised " entry))))
;; 		 data)))
;;     (sqlite3:finalize! meta-stmt) ;; sqlite is the bottleneck, clear the statements asap?
;;     (sqlite3:finalize! step-stmt)
;;     (set! *incoming-data* '())
;;     (mutex-unlock! *incoming-mutex*)))
;; ==> (define (db:write-cached-data db)
;; ==>   (let ((meta-stmt (sqlite3:prepare db "UPDATE tests SET cpuload=?,diskfree=?,run_duration=?,state='RUNNING' WHERE id=? AND state NOT IN ('COMPLETED','KILLREQ','KILLED');"))
;; ==> 	(step-stmt (sqlite3:prepare db "INSERT OR REPLACE into test_steps (test_id,stepname,state,status,event_time,comment,logfile) VALUES(?,?,?,?,?,?,?);")) ;; strftime('%s','now')#f)
;; ==> 	(data (sort *incoming-data* (lambda (a b)(< (vector-ref a 1)(vector-ref b 1))))))
;; ==>     (if (> (length data) 0)
;; ==> 	(debug:print 4 "Writing cached data " data))
;; ==>     (mutex-lock! *incoming-mutex*)
;; ==>     (sqlite3:with-transaction 
;; ==>      db
;; ==>      (lambda ()
;; ==>        (for-each (lambda (entry)
;; ==> 		   (case (vector-ref entry 0)
;; ==> 		     ((meta-info)
;; ==> 		      (apply sqlite3:execute meta-stmt (vector-ref entry 2)))
;; ==> 		     ((step-status)
;; ==> 		      (apply sqlite3:execute step-stmt (vector-ref entry 2)))
;; ==> 		     (else
;; ==> 		      (debug:print 0 "ERROR: Queued entry not recognised " entry))))
;; ==> 		 data)))
;; ==>     (sqlite3:finalize! meta-stmt) ;; sqlite is the bottleneck, clear the statements asap?
;; ==>     (sqlite3:finalize! step-stmt)
;; ==>     (set! *incoming-data* '())
;; ==>     (mutex-unlock! *incoming-mutex*)))

(define (db:roll-up-pass-fail-counts db run-id test-name item-path status)
  (if (and (not (equal? item-path ""))
	   (or (equal? status "PASS")
	       (equal? status "WARN")
	       (equal? status "FAIL")
	       (equal? status "WAIVED")
1003
1004
1005
1006
1007
1008
1009

1010

1011
1012
1013
1014

1015
1016

1017
1018
1019
1020
1021
1022
1023
1019
1020
1021
1022
1023
1024
1025
1026

1027
1028
1029
1030

1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041







+
-
+



-
+


+







;;======================================================================

(define (db:step-get-time-as-string vec)
  (seconds->time-string (db:step-get-event_time vec)))

;; db-get-test-steps-for-run
(define (db:get-steps-for-test db test-id)
  (let* ((tdb (db:open-test-db-by-test-id db test-id))
  (let ((res '()))
	 (res '()))
    (sqlite3:for-each-row 
     (lambda (id test-id stepname state status event-time logfile)
       (set! res (cons (vector id test-id stepname state status event-time (if (string? logfile) logfile "")) res)))
     db
     tdb
     "SELECT id,test_id,stepname,state,status,event_time,logfile FROM test_steps WHERE test_id=? ORDER BY id ASC;" ;; event_time DESC,id ASC;
     test-id)
    (sqlite3:finalize! tdb)
    (reverse res)))

;; get a pretty table to summarize steps
;;
(define (db:get-steps-table db test-id)
  (let ((steps   (db:get-steps-for-test db test-id)))
    ;; organise the steps for better readability
1126
1127
1128
1129
1130
1131
1132

1133

1134
1135
1136
1137
1138

1139
1140

1141
1142


1143
1144
1145
1146

1147
1148
1149
1150
1151
1152
1153
1144
1145
1146
1147
1148
1149
1150
1151

1152
1153
1154
1155
1156

1157


1158


1159
1160




1161
1162
1163
1164
1165
1166
1167
1168







+
-
+




-
+
-
-
+
-
-
+
+
-
-
-
-
+







	     (if (not ever-seen)
		 (set! result (append (if (null? tests)(list waitontest-name) tests) result)))))
	waitons)
      (delete-duplicates result))))

(define (db:teststep-set-status! db test-id teststep-name state-in status-in item-path comment logfile)
  (debug:print 4 "test-id: " test-id " teststep-name: " teststep-name)
  (let* ((tdb       (db:open-test-db-by-test-id db test-id))
  (let* ((state     (check-valid-items "state" state-in))
	 (state     (check-valid-items "state" state-in))
	 (status    (check-valid-items "status" status-in)))
    (if (or (not state)(not status))
	(debug:print 0 "WARNING: Invalid " (if status "status" "state")
		     " value \"" (if status state-in status-in) "\", update your validvalues section in megatest.config"))
    (mutex-lock! *incoming-mutex*)
    (sqlite3:execute 
    (set! *incoming-data* (cons (vector 'step-status
					(current-seconds)
     tdb
					;; FIXME - this should not update the logfile unless it is specified.
					(list test-id teststep-name state-in status-in (current-seconds) (if comment comment "") (if logfile logfile "")))
     "INSERT OR REPLACE into test_steps (test_id,stepname,state,status,event_time,comment,logfile) VALUES(?,?,?,?,?,?,?);"
     test-id teststep-name state-in status-in (current-seconds) (if comment comment "") (if logfile logfile "")))
				*incoming-data*))
    (mutex-unlock! *incoming-mutex*)
    ;; (if (not *cache-on*)(db:write-cached-data db))
    #t))
    #t)

;;======================================================================
;; Extract ods file from the db
;;======================================================================

;; runspatt is a comma delimited list of run patterns
;; keypatt-alist must contain *all* keys with an associated pattern: '( ("KEY1" "%") .. )

Modified runs.scm from [735502950d] to [ec5f4d2861].

309
310
311
312
313
314
315
316
317


318
319
320
321
322
323
324
309
310
311
312
313
314
315


316
317
318
319
320
321
322
323
324







-
-
+
+







				       (filter
					(lambda (t)
					  (or (not (vector? t))
					      (not (equal? "COMPLETED" (db:test-get-state t)))))
					prereqs-not-met)))
		 (pretty-string (lambda (lst)
				  (map (lambda (t)
					 (if (string? t)
					     t
					 (if (not (vector? t))
					     (conc t)
					     (conc (db:test-get-testname t) ":" (db:test-get-state t) "/" (db:test-get-status t))))
				       lst))))
	    (debug:print 6
			 "itemdat:     " itemdat
			 "\n  items:     " items
			 "\n  item-path: " item-path
			 "\n  waitons:   " waitons)
335
336
337
338
339
340
341
342
343
344



345
346
347
348
349
350
351
335
336
337
338
339
340
341



342
343
344
345
346
347
348
349
350
351







-
-
-
+
+
+







	      (let* ((have-resources  (runs:can-run-more-tests db test-record)) ;; look at the test jobgroup and tot jobs running
		     (prereqs-not-met (db:get-prereqs-not-met db run-id waitons item-path mode: testmode))
		     (fails           (calc-fails prereqs-not-met))
		     (non-completed   (calc-not-completed prereqs-not-met)))
		(debug:print 8 "INFO: have-resources: " have-resources " prereqs-not-met: " 
			     (string-intersperse 
			      (map (lambda (t)
				     (if (string? t)
					 (conc " WARNING: t is a string=" t )
					 (conc (db:test-get-state t)"/"(db:test-get-status t))))
				     (if (not (vector? t))
					 (conc " WARNING: t is not a vector=" t )
					 (conc (db:test-get-state t) "/" (db:test-get-status t))))
				   prereqs-not-met) ", ") " fails: " fails)
		;; 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?
		(cond
		 ((and have-resources
		       (or (null? prereqs-not-met)
			   (and (eq? testmode 'toplevel)