This crate realizes the execution of tests. The concept of the usage is to define resources which are outputs of bash scripts. These outputs can then be tested either on the machine running the test using clojure tools or on the target node using a bash script.
Resources are outputs of bash scripts that are executed on the tested node. A resource is made up of
- a unique resource-key, which must be used to identify the resource in tests
- a bash script, which creates the resource and the
- output of this script. If we refer to "the output resource" we might write short "the resource" itself.
To ensure uniqueness of resource-keys you should use namespaced keywords like
Aside to the output, there is the transformed output of the script belonging to the resource. See below for more information.
For each phase run a resource directory is created in
/home/pallet/state and for each defined resource with a unique resource-key there will be a corresponding script (.sh) and output (.rc) file.
Resources are defined using
define-resource-from-script by providing a script and resource-key.
Example: Create a resource containing all users and their home directories.
(require '[org.domaindrivenarchitecture.pallet.serverstate.resources :as res]) ; in test-phase: (res/define-resource-from-script ::user-list "cut -d: -f1,6 /etc/passwd")
cut select only the first the sixth entries from the passwd-file. The resource will look like this:
root:/root daemon:/usr/sbin bin:/bin sys:/dev sync:/bin games:/usr/games ...
You might also use the whole file as a resource which means we just create a copy of the file:
(require '[org.domaindrivenarchitecture.pallet.serverstate.resources :as res]) (res/define-resource-from-script ::passwd-file "cat /etc/passwd") ; there are shorthands for creating often used resources like files ; in this case we could write as well: (res/define-resource-from-file ::passwd-file "/etc/passwd")
Having a large string as resource might not be very convenient to work with. You can specify a transform-fn when defining resource to parse the result. If no transformer is supplied the output and the transformed output both refer to the raw output string.
Example: Transforming the user-list in a clojure structure
; our transform functions takes the output of the script ; splits on lines and the ':' delimiter. ; then all empty entries are filtered (defn transform-user-list [output] (filter #(= 2 (count %)) (map #(clojure.string/split % #":") (clojure.string/split-lines output)))) ; use this when defining the resource in test-phase (require '[org.domaindrivenarchitecture.pallet.serverstate.resources :as res]) (res/define-resource-from-script ::user-list "cut -d: -f1,6 /etc/passwd" :transform-fn transform-user-list)
Tests: Local in clojure
Doing a local test in clojure means there are no further actions performed on the target node when performing the test. This means you can only access a previous defined resource for the test.
Such a test is a plain clojure function getting the (by default transformed) resource as argument. The function must evaluate to
nil if the test failed and can have any other result if the test passes.
Use outputs to stdout (e.g.
println) if you like to have any outputs in the test results.
To enable the test, use
testclj-resource from the test package. You can choose to use the transformed output (default) or the raw string output.
Example: Checking for the existence of a user using the previous defined
(defn test-palletuser-existing "Tests if there is a pallet user in the user-list. Here user-list must be a vector of entries where every entry is a vector containing username and homefolder as string. e.g: [ [\"root\" \"/root\"] ... ] " [user-list] (println "Testing if user pallet exists.") (= 1 (count (filter #(= (first %) "pallet") user-list)))) ; In test-phase: (require '[org.domaindrivenarchitecture.pallet.serverstate.tests :as tests]) (tests/testclj-resource ::user-list test-palletuser-existing)
Tests: Bash on the remote node
You might as well perform some tests, that require more information than the resources itself. Regarding our user-list example this might be a test to ensure all home directories are existing.
Remote tests in bash are scripts (in plaintext or pallet stevedore notation) that receive the specified resource as input and signal with their exit code if the test passed. Hereby passed means exit code 0 and a failure is indicated by any other exit code. To define such a test use
testnode-resource from the test package.
Example: To get the idea -- the syntax is
; In test-phase: (require '[org.domaindrivenarchitecture.pallet.serverstate.tests :as tests]) (require '[pallet.stevedore :refer :all]) (tests/testnode-resource ::some-resource "echo I always pass && exit 0")
Example: Check if all home directories are existing
; In test-phase: (require '[org.domaindrivenarchitecture.pallet.serverstate.tests :as tests]) (require '[pallet.stevedore :refer :all]) (tests/testnode-resource ::user-list (script (set! exitcode 0) (while ("read" line) (set! user @((pipe (println @line) ("cut -f1 -d:")))) (set! homedir @((pipe (println @line) ("cut -f2 -d:")))) (if (not (directory? @homedir)) (do (println "Home" @homedir "of user" @user "does not exist!") (set! exitcode 1)))) ("exit" @exitcode)))
Results can be created by applying
test-results to the pallet session after
integration folder for a complete example.
Predefined resources and tests
Apt package manager
Published under apache2.0 license