Guide 5. Params

What you're going to learn

In this guide we will focus our attention on the param feature in Testo-lang.

Preconditions

  1. Testo Framework is installed.
  2. Hyper-V is installed.
  3. Ubuntu server 16.04 image is downloaded and located here: C:\iso\ubuntu_server.iso. The location may be different, but in this case the ISO_DIR command-line param has to be adjusted accordingly.
  4. Testo guest additions iso image is downloaded and located in the same folder as Ubuntu Server 16.04 iso-image.
  5. The Host has the Internet access.
  6. (Recommended) Testo-lang syntax highlight for Sublime Text 3 is set up.
  7. (Recommended) Guide 4 is complete.

Introduction

During the previous guides we've written quite a lot of code for our test scripts, and it's not hard to see that there are several string constants that occur several times in the scripts. For example, my-ubuntu-login can be seen multiple times (during Ubuntu installation, then at the login attempts). If we'd decided to change the login to some other value we'd need to search all the file and replace the value several times.

We can also note that the paths to the Ubuntu Server and Guest Additions are absolute, which is not very convenient. If the ISO-images were located elsewhere, we'd need to adjust the test script. All that is certainly brings certain mess to the test scripts.

To solve this problem Testo-lang has the params mechanism. Params basically are global string constants. Let's take a look at them.

What to begin with?

Let's remember how our script looks at the moment:

...

test ubuntu_installation {
	my_ubuntu {
		start
		...
		wait "Hostname:" timeout 5m; press Backspace*36; type "my-ubuntu"; press Enter
		wait "Full name for the new user"; type "my-ubuntu-login"; press Enter
		wait "Username for your account"; press Enter
		wait "Choose a password for the new user"; type "1111"; press Enter
		wait "Re-enter password to verify"; type "1111"; press Enter
		...
		wait "login:" timeout 2m; type "my-ubuntu-login"; press Enter
		wait "Password:"; type "1111"; press Enter
		wait "Welcome to Ubuntu"
	}
}

test ubuntu_prepare: ubuntu_installation {
	my_ubuntu {
		# Enter sudo mode
		type "sudo su"; press Enter
		wait "password for my-ubuntu-login"; type "1111"; press Enter
		wait "root@my-ubuntu"
		...
		wait "login:" timeout 2m; type "my-ubuntu-login"; press Enter
		wait "Password:"; type "1111"; press Enter
		wait "Welcome to Ubuntu"

		# Enter sudo once more
		type "sudo su"; press Enter;
		wait "password for my-ubuntu-login"; type "1111"; press Enter
		wait "root@my-ubuntu"
		...
	}
}
...

We can see a few strings that occur several time during the script: my-ubuntu (hostname), my-ubuntu-login (login) and 1111 (password). Obviously, the more elaborate our script gets, the more such repeated constants will take place - and the easier it will be to make a mistake. So let's try to avoid that and declare three params:

param hostname "my-ubuntu"
param login "my-ubuntu-login"
param password "1111"

test ubuntu_installation {
    ...

Param declarations must be placed at the same level as virtual machines and tests declarations (e.g. globally). You can't declare params inside tests or other virtual entities declarations.

It is prohibited to re-declare params.

Now inside our tests we can reference the params we've just declared:

...

test ubuntu_installation {
    my_ubuntu {
        start
        ...
        wait "Hostname:" timeout 5m; press Backspace*36; type "${hostname}"; press Enter
        wait "Full name for the new user"; type "${login}"; press Enter
        wait "Username for your account"; press Enter
        wait "Choose a password for the new user"; type "${password}"; press Enter
        wait "Re-enter password to verify"; type "${password}"; press Enter
        ...
        wait "login:" timeout 2m; type "${login}"; press Enter
        wait "Password:"; type "${password}"; press Enter
        wait "Welcome to Ubuntu"
    }
}

test ubuntu_prepare: ubuntu_installation {
    my_ubuntu {
        # Enter sudo mode
        type "sudo su"; press Enter
        wait "password for ${login}"; type "${password}"; press Enter
        wait "root@${hostname}"
        ...
        wait "login:" timeout 2m; type "${login}"; press Enter
        wait "Password:"; type "${password}"; press Enter
        wait "Welcome to Ubuntu"

        # Enter sudo once more
        type "sudo su"; press Enter;
        wait "password for ${login}"; type "${password}"; press Enter
        wait "root@${hostname}"
        ...
    }
}
...

Now our test script looks much neater and easier to read. Additionally, if we'd decided to change our login, hostname or password we'd need to change the value in just one place.

Passing params as command line arguments

And still there is one not-so-pretty thing in our test script: we have to specify full absolute paths to the ISO-images in the virtual machine declaration and in the plug dvd action when installing guest additions.

Of course, we could have declared a param iso_dir "/opt/iso", but that would not fix the problem: our script would have still be bound to the exact iso-images placement. Obviously, this is not a good thing.

But, fortunately, in Testo-lang you can not only specify params statically inside test scripts, but pass them as command-line arguments as well. Let's try that:

machine my_ubuntu {
    cpus: 1
    ram: 512Mb
    disk main: {
        size: 5Gb
    }
    iso: "${ISO_DIR}\\ubuntu_server.iso"
}
...
test ubuntu_install_guest_additions: ubuntu_prepare {
    my_ubuntu {
        plug dvd "${ISO_DIR}\\testo-guest-additions.iso"
        ...
    }
}

We changed our test script in such a manner that the paths to the Ubuntu Server and Guest Additions iso-images now contain a reference to the ISO_DIR param (you could also take a note that params are referencable inside the virtual machine declarations too). But we haven't declared the ISO_DIR param anywhere. If we tried to run the test script now, the same way we're used to, we would see an error:

C:\Users\Testo> testo run params.testo --stop_on_fail --test_spec ubuntu_guest_additions_demo
C:/Users/Testo/testo/params.testo:6:1: In the virtual machine "my_ubuntu" declaration
C:/Users/Testo/testo/params.testo:12:7: Error while resolving "${ISO_DIR}\ubuntu_server.iso"
- param "ISO_DIR" is not defined
C:\Users\Testo>

Since the ISO_DIR param hasn't been declared, Testo can't resolve the reference to it and generates an error. So we'll try to pass the param ISO_DIR through a command line argument:

C:\Users\Testo> testo run params.testo --stop_on_fail --test_spec ubuntu_guest_additions_demo --param ISO_DIR C:\iso

If the iso-images location changes for some reason (for example, the script is run on another computer), all we'll have to do is to change one command-line argument value when running the script, the script itself doesn't need to be modified.

If you've completed the guide 3 and run the script the way it was at the end of the previous guide, then now (after the new run) you'll see the next output:

C:\Users\Testo> testo run params.testo --stop_on_fail --test_spec ubuntu_guest_additions_demo --param ISO_DIR C:\iso
UP-TO-DATE TESTS:
ubuntu_installation
ubuntu_prepare
ubuntu_install_guest_additions
ubuntu_guest_additions_demo
PROCESSED TOTAL 4 TESTS IN 0h:0m:0s
UP-TO-DATE: 4
RUN SUCCESSFULLY: 0
FAILED: 0
C:\Users\Testo>

Which means no tests were run. The reason is that all the tests are cached now, and there is no need to run them again. We will focus on caching mechanism in Testo-lang in the next guide, in which we'll provide a detailed explanation about how the tests managed to remain cached, despite the seemingly large changes in them.

But right now to make sure that out test script is still funcitonal, we need to run the interpeter with thw new command-line argument --invalidate, which resets the cache of the specified tests.

C:\Users\Testo> testo run params.testo --stop_on_fail --test_spec ubuntu_guest_additions_demo --param ISO_DIR C:\iso --invalidate *
TESTS TO RUN:
ubuntu_installation
ubuntu_prepare
ubuntu_install_guest_additions
ubuntu_guest_additions_demo
[ 0%] Preparing the environment for test ubuntu_installation
[ 0%] Restoring snapshot initial for virtual machine my_ubuntu
[ 0%] Running test ubuntu_installation
[ 0%] Starting virtual machine my_ubuntu
[ 0%] Waiting "Install Ubuntu Server" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Choose the language" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Select your location" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Detect keyboard layout?" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Country of origin for the keyboard" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Keyboard layout" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Hostname:" for 5m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key BACKSPACE 36 times in virtual machine my_ubuntu
[ 0%] Typing "my-ubuntu" with interval 30ms in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Full name for the new user" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Typing "my-ubuntu-login" with interval 30ms in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Username for your account" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Choose a password for the new user" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Typing "1111" with interval 30ms in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Re-enter password to verify" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Typing "1111" with interval 30ms in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Use weak password?" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key LEFT in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Encrypt your home directory?" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Is this time zone correct?" for 2m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Partitioning method" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Select disk to partition" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Write the changes to disks and configure LVM?" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key LEFT in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Amount of volume group to use for guided partitioning" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Force UEFI installation?" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key LEFT in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Write the changes to disks?" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key LEFT in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "HTTP proxy information" for 3m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "How do you want to manage upgrades" for 6m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Choose software to install" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Installation complete" for 30m with interval 1s in virtual machine my_ubuntu
[ 0%] Unplugging dvd from virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "login:" for 2m with interval 1s in virtual machine my_ubuntu
[ 0%] Typing "my-ubuntu-login" with interval 30ms in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Password:" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Typing "1111" with interval 30ms in virtual machine my_ubuntu
[ 0%] Pressing key ENTER in virtual machine my_ubuntu
[ 0%] Waiting "Welcome to Ubuntu" for 1m with interval 1s in virtual machine my_ubuntu
[ 0%] Taking snapshot ubuntu_installation for virtual machine my_ubuntu
[ 25%] Test ubuntu_installation PASSED in 0h:7m:14s
[ 25%] Preparing the environment for test ubuntu_prepare
[ 25%] Running test ubuntu_prepare
[ 25%] Typing "sudo su" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "password for my-ubuntu-login" for 1m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "1111" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "root@my-ubuntu" for 1m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "dhclient -r eth0 && dhclient eth0 && echo Result is $?" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Typing "clear && apt update && echo Result is $?" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "Result is 0" for 1m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "clear && apt install -y linux-azure && echo Result is $?" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "Result is 0" for 15m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "reboot" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "login:" for 2m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "my-ubuntu-login" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "Password:" for 1m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "1111" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "Welcome to Ubuntu" for 1m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "sudo su" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "password for my-ubuntu-login" for 1m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "1111" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "root@my-ubuntu" for 1m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "clear && modprobe hv_sock && echo Result is $?" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "Result is 0" for 1m with interval 1s in virtual machine my_ubuntu
[ 25%] Typing "clear && lsmod | grep hv" with interval 30ms in virtual machine my_ubuntu
[ 25%] Pressing key ENTER in virtual machine my_ubuntu
[ 25%] Waiting "hv_sock" for 1m with interval 1s in virtual machine my_ubuntu
[ 25%] Taking snapshot ubuntu_prepare for virtual machine my_ubuntu
[ 50%] Test ubuntu_prepare PASSED in 0h:5m:36s
[ 50%] Preparing the environment for test ubuntu_install_guest_additions
[ 50%] Running test ubuntu_install_guest_additions
[ 50%] Plugging dvd C:/iso/testo-guest-additions-hyperv.iso into virtual machine my_ubuntu
[ 50%] Typing "mount /dev/cdrom /media" with interval 30ms in virtual machine my_ubuntu
[ 50%] Pressing key ENTER in virtual machine my_ubuntu
[ 50%] Waiting "mounting read-only" for 1m with interval 1s in virtual machine my_ubuntu
[ 50%] Typing "clear && dpkg -i /media/*.deb && echo Result is $?" with interval 30ms in virtual machine my_ubuntu
[ 50%] Pressing key ENTER in virtual machine my_ubuntu
[ 50%] Waiting "Result is 0" for 1m with interval 1s in virtual machine my_ubuntu
[ 50%] Typing "clear && umount /media && echo Result is $?" with interval 30ms in virtual machine my_ubuntu
[ 50%] Pressing key ENTER in virtual machine my_ubuntu
[ 50%] Waiting "Result is 0" for 1m with interval 1s in virtual machine my_ubuntu
[ 50%] Sleeping in virtual machine my_ubuntu for 2s
[ 50%] Unplugging dvd from virtual machine my_ubuntu
[ 50%] Taking snapshot ubuntu_install_guest_additions for virtual machine my_ubuntu
[ 75%] Test ubuntu_install_guest_additions PASSED in 0h:0m:15s
[ 75%] Preparing the environment for test ubuntu_guest_additions_demo
[ 75%] Running test ubuntu_guest_additions_demo
[ 75%] Executing bash command in virtual machine my_ubuntu with timeout 10m
+ echo Hello world
Hello world
+ echo from bash
from bash
[ 75%] Executing python3 command in virtual machine my_ubuntu with timeout 10m
Hello from python3!
[ 75%] Taking snapshot ubuntu_guest_additions_demo for virtual machine my_ubuntu
[100%] Test ubuntu_guest_additions_demo PASSED in 0h:0m:2s
PROCESSED TOTAL 4 TESTS IN 0h:13m:9s
UP-TO-DATE: 0
RUN SUCCESSFULLY: 4
FAILED: 0
C:\Users\Testo>

Conclusions

You can make your test scripts more flexible and neater with params.

First, you can "rename" frequently used string constants so you can navigate through them easily.

Second, you can control the test scripts run with the command-line arguments, not changing the test scripts themselves.

You can find the complete test scripts for this guide here.