elisp-vcs/dvc/lisp/tests/xmtn-tests.el
2009-10-10 08:02:43 +02:00

658 lines
30 KiB
EmacsLisp

;;; xmtn-tests.el --- Automated regression tests for xmtn
;; Copyright (C) 2006, 2007 Christian M. Ohler
;; Author: Christian M. Ohler
;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;;
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this file; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
;; Boston, MA 02110-1301 USA.
;;; Commentary:
;; Automated regression tests for xmtn.
;;; Code:
;;; There are some notes on the design of xmtn in
;;; docs/xmtn-readme.txt.
;; These tests require elunit.el from
;; http://dev.technomancy.us/phil/wiki/ElUnit .
(eval-and-compile
(require 'cl)
(require 'elunit)
(require 'elp) ;; elp-elapsed-time is a 'defsubst', so we require elp at load time, not run time.
(require 'xmtn-match)
(require 'xmtn-dvc)
(require 'dvc-tests-utils "tests/dvc-tests-utils.el"))
(defun xmtn-tests--keypair-string ()
"[keypair xmtn-test]
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDFE8/sRvdvN5+F5aFVpXeJpz0eKAzhYdWB
uW3L0C1tWnLk+HzYV13ewKMtFzwkoTeITTX5q372zH2XSIcUR2jBCArQf8Ru40886nLwG7zU
G1cI3B86akQknDUn3t9C1jEHXlBJiPLwaWrcmMFhoA+PnE49gopudw4q6Yhg1YCOqwIDAQAB#
MIICyTBDBgkqhkiG9w0BBQ0wNjAeBgkqhkiG9w0BBQwwEQQIccoCNMR2fIYCAggAAgEYMBQG
CCqGSIb3DQMHBAgjnJz0whELeQSCAoDEzuBbQf7hf43ULUZR7gFBrXilg+KBgItlA0Mz6jmI
0+LzoHhJiU3rnyR1MsXkf7uCBFje5Uqj53vUrnrBbxgGBFHwOw1Kic+lbDtvAKlNLPPPl9h8
W9QrQYhEg9VsmYBUvxZnyw5Kmafpmh1wC/fRSchDmWyhUeJHtkZhnUgcG9OFi6z8JT64/VGw
ZhB46Q2dGLrygjHRArA8FIOX5dlGzyRNfa0w5dVWZED7IcQVCoBLwLiEb9woK+fyEuK12fM+
23U8/sAO74MMOoyvs+OoloPtgniHuRdc/1RV9CS9k64mnzJdOnhR/GxQIL36LZcNrHvnM9Nn
xrK2yDkuk39JcLDJlFPZok7vluEn1GCKKGce3Z2LP6VPTJAqBHgt1fTMBAT5bc7rbVQxzVEU
56anNOMR1T9MRnbX5u5Hpj5mNIqbWX+g3YCIgKIJXbtD57GixPP4s/mP2EcAAeZvWiGeTF6Z
GyNq8USmlEjXpMrIWqLk+f6OzDyvk05sTQByRlKwOGzgbyNnWsetKC97wFfsBExNKhKeFFTV
6HOehUEPHIrikNaLed52czpqaKcQ67uVfdWXs3drwS7V0RRtTdcAzy0u95bERPrRpCY3tq/a
CGp3K4RF00eJQLBa94D9LYIEMBk4evfKCijcId0b4kzIQS1SI1sytnt+P1zPQaV5yAetOOD/
fuHfnYU27Mqis5V23xo1ibjDS1fa3/E6XK2P+Y3rHuyjQ/QbFlcBwj0vjv8yqwRWOe5y6Msd
f6S7jhNd76i/o3K/DmnpnI1N8RODAd77uejpe8K0xthzk2q02VtrBXA7jpY7oSaIaKJPov6v
YPFoLxe1V5oOyoe3ap0H
[end]")
(defun xmtn-tests--default-rc-file ()
;; Monotone versions up to and including 0.33 don't allow empty
;; passphrases.
"function get_passphrase(keypair_id) return \"a\" end")
;;; This is preferable over seperate set-up and tear-down functions
;;; since it allows us to make use of `unwind-protect' and dynamic
;;; bindings.
(defun xmtn-tests--call-with-test-environment (xmtn--body)
(lexical-let ((body xmtn--body))
(lexical-let ((temp-dir nil))
(unwind-protect
(progn
(setq temp-dir (file-name-as-directory
(xmtn--make-temp-file "xmtn-tests-" t)))
(lexical-let ((key-dir (concat temp-dir "keys/"))
(rc-file (concat temp-dir "rc")))
(let* ((default-directory temp-dir)
(dvc-test-mode t)
(xmtn-additional-arguments
`("--db" ,(concat temp-dir "a.mtn")
"--keydir" ,key-dir
"--norc"
"--rcfile" ,rc-file)))
(make-directory key-dir)
(with-temp-file (concat key-dir "xmtn-tests")
(insert (xmtn-tests--keypair-string) ?\n))
(with-temp-file rc-file
(insert (xmtn-tests--default-rc-file) ?\n))
(xmtn--run-command-sync nil '("db" "init"))
(xmtn--run-command-sync nil '("setup"
"--branch" "invalid.xmtn-tests"
"workspace"))
(let ((default-directory (concat temp-dir "workspace/")))
(funcall body
:root default-directory)))))
(when temp-dir
(dired-delete-file temp-dir 'always))))))
(defun xmtn-tests--call-with-test-history (xmtn--body)
(lexical-let ((body xmtn--body))
(xmtn-tests--call-with-test-environment
(function*
(lambda (&key ((:root xmtn--root)))
(lexical-let ((root xmtn--root)
(file-name "file-1")
revision-1
revision-2)
(with-temp-file file-name (insert "a\n"))
(xmtn--add-files root (list file-name))
(xmtn--run-command-sync root `("commit" "--message=commit 1"))
(setq revision-1 (xmtn--get-base-revision-hash-id root))
(with-temp-file file-name (insert "b\n"))
(xmtn--run-command-sync root `("commit" "--message=commit 2"))
(setq revision-2 (xmtn--get-base-revision-hash-id root))
(funcall body
:root root
:file-name file-name
:revision-1 revision-1
:revision-2 revision-2)))))))
(defmacro* xmtn-tests--with-test-environment ((&rest keys) &body body)
(declare (indent 1) (debug (sexp body)))
`(xmtn-tests--call-with-test-environment (function* (lambda (,@keys) ,@body))))
(defmacro* xmtn-tests--with-test-history ((&rest keys) &body body)
(declare (indent 1) (debug (sexp body)))
`(xmtn-tests--call-with-test-history (function* (lambda (,@keys) ,@body))))
(defsuite xmtn
(xmtn--match
(progn
(assert (xmtn-match--match-variable-p '$x ?$))
(assert (xmtn-match--match-variable-p '@x ?@))
(assert (not (xmtn-match--match-variable-p "$x" ?$)))
(assert (not (xmtn-match--match-variable-p 'x ?$)))
(assert (xmtn-match--contains-match-variable-p '$x ?$))
(assert (xmtn-match--contains-match-variable-p '(a b $x c) ?$))
(assert (xmtn-match--contains-match-variable-p '[a $y $z c] ?$))
(assert (xmtn-match--contains-match-variable-p '(nil . $y) ?$))
(assert (xmtn-match--contains-match-variable-p '((() $a)) ?$))
(assert (not (xmtn-match--contains-match-variable-p 'x ?$)))
(assert (not (xmtn-match--contains-match-variable-p '(a . b) ?$)))
(assert (not (xmtn-match--contains-match-variable-p nil ?$)))
(assert (not (xmtn-match--contains-match-variable-p '((() ())) ?$)))
(assert (not (xmtn-match--contains-match-variable-p nil ?$)))
(assert (equal (xmtn-match '(a b)
(($y $y) nil)
($z z))
'(a b)))
(assert (equal (xmtn-match '(a a)
(($y $y) y))
'a))
(assert (equal (xmtn-match '(a b)
($z z)
($z nil))
'(a b)))
(assert (xmtn-match nil ([t $y] y) ($z t)))
(assert (xmtn-match [foo bar] ([foo $y] y)))
(assert (xmtn-match [foo bar] ((a . b) nil) ([foo bar] t)))
(assert (xmtn-match nil (nil t)))))
(xmtn--version-case
(flet ((xmtn--latest-mtn-release () ;flet has dynamic scope in Emacs Lisp
'(2 5 "y")))
(let* ((xmtn-executable 'xmtn-dummy)
(xmtn--*command-version-cached-for-executable* xmtn-executable))
(let ((xmtn--*cached-command-version* '(2 5 "x")))
(assert
(xmtn--version-case
((and (= 2 5) (>= 2 5) (or (= 2 4) (<= 3 0))
(<= 2 6) (/= 1 5) (not (/= 2 5))
(not (>= 2 6))
(not (<= 2 4))
(not (< 2 5))
(not (< 2 4))) t)
(t nil)))
(assert
(not (ignore-errors
(xmtn--version-case
(nil t)))))
(assert (xmtn--version-case ((mainline> 2 4) t) (t nil)))
(assert (xmtn--version-case ((mainline> 2 5) t) (t nil)))
(assert (xmtn--version-case ((mainline> 2 6) nil) (t t))))
(let ((xmtn--*cached-command-version* '(2 5 "y")))
(assert (xmtn--version-case ((mainline> 2 4) t) (t nil)))
(assert (xmtn--version-case ((mainline> 2 5) nil) (t t)))
(assert (xmtn--version-case ((mainline> 2 6) nil) (t t))))
(let ((xmtn--*cached-command-version* '(1 5 "w")))
(assert (xmtn--version-case ((mainline> 2 4) nil) (t t)))
(assert (xmtn--version-case ((mainline> 2 5) nil) (t t)))
(assert (xmtn--version-case ((mainline> 1 4) t) (t nil)))
(assert (xmtn--version-case ((mainline> 1 5) nil) (t t))))
(let ((xmtn--*cached-command-version* '(2 6 "z")))
(assert (xmtn--version-case ((mainline> 2 4) t) (t nil)))
(assert (xmtn--version-case ((mainline> 2 5) t) (t nil)))
(assert (xmtn--version-case ((mainline> 2 6) nil) (t t)))))))
(log
(save-window-excursion
(xmtn-tests--with-test-history (&key &allow-other-keys)
;; The test is simply that this doesn't crash.
(dvc-log)
(dvc-revlist-show-item))))
(file-diff
;; The test is simply that this doesn't crash.
(save-window-excursion
(xmtn-tests--with-test-history (&key file-name &allow-other-keys)
(find-file file-name)
(unwind-protect
(progn
(insert "x")
(save-excursion
(call-interactively #'dvc-file-diff)))
(revert-buffer t t)))))
(diff
;; The test is simply that this doesn't crash.
(save-window-excursion
(xmtn-tests--with-test-history (&key file-name &allow-other-keys)
(find-file file-name)
(let ((buffer (current-buffer)))
(unwind-protect
(progn
(insert "x")
(write-region (point-min) (point-max)
file-name nil 'no-message nil nil)
(set-buffer-modified-p nil)
(call-interactively #'dvc-diff))
(dvc-tests-wait-async)
(with-current-buffer buffer
(set-buffer-modified-p nil)
(kill-buffer buffer)))))))
(automate-buffer-numbering
(xmtn-tests--with-test-history (&key root &allow-other-keys)
(xmtn-automate-with-session (session root)
(xmtn-automate-with-command (handle-1 session '("graph") :may-kill-p t)
(sleep-for 0.5)
(xmtn-automate-terminate-processes-in-root root)
(xmtn-automate-with-command (handle-2 session '("graph")
:may-kill-p nil)
(assert (not (equal (xmtn-automate-command-buffer handle-1)
(xmtn-automate-command-buffer handle-2))))
(xmtn-automate-command-wait-until-finished handle-2))))))
(automate-several-commands
(xmtn-tests--with-test-history (&key root &allow-other-keys)
;; The test is simply that this doesn't crash.
(xmtn-automate-with-session (session root)
(xmtn-automate-with-command (cmd session '("graph") :may-kill-p nil))
(xmtn-automate-with-command (cmd session '("graph") :may-kill-p nil))
(xmtn-automate-with-command (cmd session '("graph") :may-kill-p nil))
(xmtn-automate-with-command (cmd session '("graph") :may-kill-p nil))
(xmtn-automate-with-command (cmd session '("graph") :may-kill-p t))
(xmtn-automate-with-command (cmd session '("graph") :may-kill-p t)
;;(xmtn-automate-command-wait-until-finished cmd)
))
;; Try to delay deletion of our temp workspace until process has
;; terminated.
(sleep-for 1)))
(non-ascii-file-name
(let ((umlaut (string (make-char 'latin-iso8859-1 #xe4)))) ; umlaut a
(xmtn-tests--with-test-environment (&key root)
(let ((file-name umlaut))
(let ((file-name-coding-system 'utf-8)) ; not sure about this...
(with-temp-file file-name ; create empty file
(progn)))
(xmtn--add-files root (list file-name))
(let ((manifest (xmtn--get-manifest root `(local-tree ,root))))
(xmtn-match manifest
(((dir "") (file $file-name-here $hash-id $attributes))
(assert (equal file-name-here file-name) t)
(assert (endp attributes)))))
;; Check whether xmtn-automate encodes the file name
;; correctly when passing it to monotone. The actual command
;; doesn't matter as much as the fact that monotone receives
;; it correctly.
(xmtn--with-automate-command-output-basic-io-parser
(next-stanza root (xmtn--version-case
((mainline> 0 35) `("get_attributes" ,file-name))
(t `("attributes" ,file-name))))
(xmtn-match (funcall next-stanza)
((("format_version" (string "1")))))
(assert (null (funcall next-stanza)) t))))))
(non-ascii-file-contents
(let ((umlaut (string (make-char 'latin-iso8859-1 #xe4)))) ; umlaut a
(xmtn-tests--with-test-environment (&key root)
(let ((file-name "foo")
(contents (concat umlaut "\n"))
(coding-system 'iso-8859-1-unix))
(with-temp-file file-name
(setq buffer-file-coding-system coding-system)
(insert contents))
(xmtn--add-files root (list file-name))
(xmtn--run-command-sync root (list "commit" "--message=commit foo"))
(let ((content-id "77785e6fd883a5e27a62bc6f26365e1b37e1900f"))
(assert (equal (xmtn--file-contents-as-string root content-id)
(encode-coding-string contents coding-system))
t))))))
(non-ascii-cert-value
(let ((umlaut (string (make-char 'latin-iso8859-1 #xe4)))) ; umlaut a
(xmtn-tests--with-test-history (&key root revision-2 &allow-other-keys)
(let ((cert-name "test-cert")
(cert-value umlaut))
(xmtn--run-command-sync root `("cert" "--"
,revision-2
,cert-name ,cert-value))
(let ((certs (xmtn--list-parsed-certs root revision-2)))
(let ((matching-certs (remove* cert-name certs
:key #'third
:test-not #'equal)))
(xmtn-match matching-certs
((($email ok $cert-name-here $cert-value-here t))
(assert (equal cert-name-here cert-name) t)
(assert (equal cert-value-here cert-value) t)))))))))
(dvc-file-diff-with-non-ascii-contents
(save-window-excursion
(let ((umlaut (string (make-char 'latin-iso8859-1 #xe4)))) ; umlaut a
(xmtn-tests--with-test-environment (&key root)
(let ((file-name "foo")
(contents (concat umlaut "\n"))
(coding-system 'utf-8-unix))
(with-temp-file file-name
(setq buffer-file-coding-system coding-system)
(insert contents))
(xmtn--add-files root (list file-name))
(xmtn--run-command-sync root (list "commit" "--message=commit foo"))
(with-temp-buffer
(let ((coding-system-for-read coding-system))
(insert-file-contents file-name t))
(dvc-file-diff file-name)
(assert (eql (point-min) (point-max)))))))))
(buffer-file-coding-system-in-dvc-dvc-file-diff
(save-window-excursion
(let ((umlaut (string (make-char 'latin-iso8859-1 #xe4)))) ; umlaut a
(xmtn-tests--with-test-environment (&key root)
(let ((file-name "foo")
(contents (concat umlaut "\n"))
(coding-system-1 'utf-8-unix)
(coding-system-2 'iso-8859-1-unix))
(with-temp-file file-name
(setq buffer-file-coding-system coding-system-1)
(insert contents))
(xmtn--add-files root (list file-name))
(xmtn--run-command-sync root (list "commit" "--message=commit foo"))
(with-temp-buffer
(insert-file-contents file-name t)
(setq buffer-file-coding-system coding-system-2)
(let ((coding-system-for-read coding-system-1))
(dvc-file-diff file-name))
(assert (not (eql (point-min) (point-max))))))))))
(file-diff-after-rename
(xmtn-tests--with-test-history (&key root ((:file-name file-name-1))
revision-2
&allow-other-keys)
(let ((file-name-2 "bar"))
(xmtn--run-command-sync root
(xmtn--version-case
((>= 0 34)
`("mv" "--" ,file-name-1 ,file-name-2))
(t
`("mv" "-e" "--" ,file-name-1 ,file-name-2))))
(with-temp-buffer
(xmtn--revision-get-file-helper file-name-2 revision-2)
(assert (equal (buffer-substring (point-min) (point-max))
"b\n")
t)))))
(diff-from-revlog
(save-window-excursion
(xmtn-tests--with-test-history (&key &allow-other-keys)
(unwind-protect
(progn
(dvc-changelog)
(dvc-revision-next)
(dvc-revlist-diff))
(dvc-tests-wait-async)))))
(stdio-command-options
(xmtn--version-case
((>= 0 31)
(xmtn-tests--with-test-history (&key root file-name
revision-1 revision-2
&allow-other-keys)
(let ((root default-directory))
(assert
(equal
(xmtn-automate-simple-command-output-lines
root `(("revision" ,revision-1
"revision" ,revision-2)
"content_diff" ,file-name))
'("============================================================"
"--- file-1 3f786850e387550fdab836ed7e6dc881de23001b"
"+++ file-1 89e6c98d92887913cadf06b2adb97f26cde4849b"
"@@ -1 +1 @@"
"-a"
"+b"))
t))))
(t
(xmtn-tests--with-test-history (&key root file-name
revision-1 revision-2)
(assert (not (ignore-errors
(message "%S" (xmtn-automate-simple-command-output-lines
root `(("revision" ,revision-1
"revision" ,revision-2)
"content_diff" ,file-name)))
t)))))))
(xmtn-dvc-command-version
;; Should not error.
(xmtn-dvc-command-version))
(dvc-file-diff-write-file-hooks
(save-window-excursion
(xmtn-tests--with-test-history (&key file-name &allow-other-keys)
(find-file file-name)
(unwind-protect
(progn
(let ((write-file-hooks (list (lambda ()
(assert nil)))))
(insert "x")
(save-excursion
(call-interactively #'dvc-file-diff))))
(revert-buffer t t)))))
(get-content-changed-closure
(save-window-excursion
(xmtn-tests--with-test-history (&key root file-name revision-1 revision-2
&allow-other-keys)
(let ((other-file-name (concat file-name "2"))
(renamed-file-name (concat file-name "x"))
revision-3 revision-4 revision-5)
(progn
(with-temp-file other-file-name (insert "a\n"))
(xmtn--add-files root (list other-file-name))
(xmtn--run-command-sync root `("commit" "--message=commit"))
(setq revision-3 (xmtn--get-base-revision-hash-id root)))
(progn
(xmtn--run-command-sync root
(xmtn--version-case
((>= 0 34)
`("mv" "--" ,file-name ,renamed-file-name))
(t
`("mv" "-e" "--" ,file-name
,renamed-file-name))))
(xmtn--run-command-sync root `("commit" "--message=commit"))
(setq revision-4 (xmtn--get-base-revision-hash-id root)))
(progn
(with-temp-file renamed-file-name (insert "c\n"))
(xmtn--run-command-sync root `("commit" "--message=commit"))
(setq revision-5 (xmtn--get-base-revision-hash-id root)))
(flet ((check (file start-rev expected-results)
(let ((actual (xmtn--get-content-changed-closure
root `(revision ,start-rev) file)))
(unless (null (set-exclusive-or expected-results
actual
:test #'equal))
(error "file=%S start-rev=%s expected=%S actual=%S; revisions=%S"
file start-rev expected-results actual
(list revision-1 revision-2 revision-3 revision-4
revision-5))))))
(check file-name revision-1 `((,revision-1 ,file-name)))
;; Some of these checks fail with mtn 0.30; not
;; investigated further.
;;
;; 0.30 reports ((1 file))
(check file-name revision-2 `((,revision-1 ,file-name)
(,revision-2 ,file-name)))
;; 0.30 reports ((1 file))
(check file-name revision-3 `((,revision-1 ,file-name)
(,revision-2 ,file-name)))
;; 0.30 reports ((1 file) (4 renamed))
(check renamed-file-name revision-4 `((,revision-1 ,file-name)
(,revision-2 ,file-name)))
;; 0.30 reports ((1 file) (4 renamed))
(check renamed-file-name revision-5 `((,revision-1 ,file-name)
(,revision-2 ,file-name)
(,revision-5
,renamed-file-name)))
(check other-file-name revision-3 `((,revision-3 ,other-file-name)))
(check other-file-name revision-4 `((,revision-3 ,other-file-name)))
(check other-file-name revision-5 `((,revision-3 ,other-file-name)))
)))))
(locale
;; The test is simply that this doesn't crash.
(let ((process-environment (list* "LC_MESSAGES=de_DE" process-environment))
(xmtn--*cached-command-version* nil))
;; Unfortunately, in my configuration, I don't seem to be able to
;; get monotone to print non-English messages at all. So, for
;; me, this doesn't actually fail even without the appropriate
;; changes to `xmtn--call-with-environment-for-subprocess'.
(xmtn-check-command-version)))
(xmtn--file-registered-p
(xmtn-tests--with-test-history (&key root file-name &allow-other-keys)
(assert (xmtn--file-registered-p root file-name))
(assert (not (xmtn--file-registered-p root "nonexistent-file")))))
(dvc-status-add
(save-window-excursion
(xmtn-tests--with-test-environment
(&key &allow-other-keys)
;; add and commit an unknown file, using dvc-status keystrokes
(with-temp-file "unknown" (insert "unknown - to be added\n"))
(with-temp-file "unknown-marked" (insert "unknown, marked\n"))
(dvc-status)
(dvc-tests-wait-async)
(assert (looking-at " unknown unknown"))
(execute-kbd-macro (vector dvc-key-add))
(dvc-tests-wait-async)
(assert (looking-at " added unknown"))
(forward-line)
(assert (looking-at " unknown unknown-marked"))
(execute-kbd-macro (vector dvc-key-mark dvc-key-add))
;; FIXME: checking for the mark doesn't work; something about the fontification of the line.
(dvc-tests-wait-async)
(execute-kbd-macro (vector dvc-key-unmark))
(assert (looking-at " added unknown-marked"))
;; FIXME: commit hangs when run from this test, in xmtn--insert-log-edit-hints, which runs stuff asynchronously
;; (execute-kbd-macro (vector dvc-key-commit))
;; (dvc-tests-wait-async)
;; (debug)
;; (execute-kbd-macro (vector "C-c" "C-c"))
;; this works
(dvc-log-edit)
(dvc-tests-wait-async)
(dvc-log-edit-done)
(dvc-tests-wait-async)
;; currently need dvc-status-refresh to see results of the
;; commit; eventually dvc-status will edit the ewoc directly
(dvc-status-refresh)
(dvc-tests-wait-async)
(assert (looking-at "$"))
)))
)
(defvar xmtn-tests--profile-history (list))
(defun xmtn-tests--profile ()
(interactive)
(unless (not xmtn--*enable-assertions*)
(unless (y-or-n-p "Assertions appear to be enabled. Continue anyway? ")
(error "Aborted")))
(let ((command
(read-from-minibuffer "Profile xmtn command: "
nil read-expression-map t
'xmtn-tests--profile-history))
(reps 20))
(elp-instrument-package "xmtn-")
(elp-instrument-package "dvc-")
(elp-instrument-package "process-")
(elp-instrument-package "ewoc-")
(elp-instrument-function 'accept-process-output)
(elp-instrument-function 'buffer-substring-no-properties)
(elp-reset-all)
(setq elp-reset-after-results nil)
;; FIXME: Maybe use benchmark.el.
(let ((gc-cons-threshold (max gc-cons-threshold 100000000))
(run-time 0)
(gc-time 0))
(assert (garbage-collect))
(loop for rep from 1
repeat reps
do
(with-temp-message (format "Profiling, repetition %s of %s..."
rep reps)
(save-excursion
(save-window-excursion
(let ((start-time (current-time)))
(eval command)
(let ((end-time (current-time)))
(incf run-time (elp-elapsed-time start-time
end-time))))))
(assert (let ((start-time (current-time)))
(prog1
(garbage-collect)
(let ((end-time (current-time)))
(incf gc-time (elp-elapsed-time start-time
end-time))))))))
(elp-results)
(setq truncate-lines t)
(goto-char (point-min))
(insert (format "Command: %S\n" command))
(insert (format "Repetitions: %s\n" reps))
(insert "\n")
(insert (format "Wall time (excluding gc): %s\n" run-time))
(insert (format "GC time (bogus): %s\n" gc-time))
(insert "\n"))
(elp-restore-all))
(message "Profiling finished"))
(defun xmtn-tests--time ()
(interactive)
(unless (not xmtn--*enable-assertions*)
(unless (y-or-n-p "Assertions appear to be enabled. Continue anyway? ")
(error "Aborted")))
(let ((command
(read-from-minibuffer "Time xmtn command: "
nil read-expression-map t
'xmtn-tests--profile-history))
(reps 10)) ;; FIXME: dies on rep 30 on Windows MinGW
;; Run command once before starting timing to get everything in cache
(eval command)
(let ((run-time 0))
(assert (garbage-collect))
(loop for rep from 1
repeat reps
do
(with-temp-message (format "Timing, repetition %s of %s..."
rep reps)
(save-excursion
(save-window-excursion
(let ((start-time (current-time)))
(eval command)
(let ((end-time (current-time)))
(incf run-time (elp-elapsed-time start-time
end-time))))))))
(switch-to-buffer-other-window (get-buffer-create
"*xmtn timing results*"))
(erase-buffer)
(setq truncate-lines t)
(goto-char (point-min))
(insert (format "Command: %S\n" command))
(insert (format "Repetitions: %s\n" reps))
(insert "\n")
(insert (format "Wall time (including gc): %s\n" run-time))
(insert "\n")))
(message "Timing finished"))
(defun xmtn-tests--parse-basic-io-inventory-benchmark (mtn-executable tree)
(let ((default-directory tree)
(xmtn-executable mtn-executable)
(xmtn--*cached-command-version* nil))
(xmtn-automate-with-session (session (dvc-tree-root))
(xmtn-automate-with-command (handle session '("inventory"))
(xmtn-automate-command-wait-until-finished handle)
(xmtn-automate-command-check-for-and-report-error handle)
(xmtn-basic-io-with-stanza-parser (parser (xmtn-automate-command-buffer
handle))
(let ((changed 0)
(total 0)
(unknown 0)
(ignored 0))
(loop for stanza = (funcall parser)
while stanza
do (incf total)
do (let ((status (second (assoc "status" stanza))))
(xmtn-match status
((string "known"))
((string "missing"))
((string "unknown") (incf unknown))
((string "ignored") (incf ignored)))
(let ((changes (second (assoc "changes" stanza))))
(unless (null changes)
(incf changed)))))
(message "total=%s changed=%s ignored=%s unknown=%s"
total changed ignored unknown)))))))
(provide 'xmtn-tests)
;;; xmtn-tests.el ends here