summary refs log tree commit diff
path: root/nixos/lib/test-driver
diff options
context:
space:
mode:
authorMaximilian Bosch <maximilian@mbosch.me>2017-12-19 15:19:38 +0100
committerMaximilian Bosch <maximilian@mbosch.me>2018-01-02 20:14:27 +0100
commite538e00404a7a79bde1465924a3f60f05648794e (patch)
tree64b0b39259c11ac74fa85a871c6166bcf063aa00 /nixos/lib/test-driver
parentb256afac58b80adde2605eac434a04b9a23bbe95 (diff)
downloadnixpkgs-e538e00404a7a79bde1465924a3f60f05648794e.tar
nixpkgs-e538e00404a7a79bde1465924a3f60f05648794e.tar.gz
nixpkgs-e538e00404a7a79bde1465924a3f60f05648794e.tar.bz2
nixpkgs-e538e00404a7a79bde1465924a3f60f05648794e.tar.lz
nixpkgs-e538e00404a7a79bde1465924a3f60f05648794e.tar.xz
nixpkgs-e538e00404a7a79bde1465924a3f60f05648794e.tar.zst
nixpkgs-e538e00404a7a79bde1465924a3f60f05648794e.zip
test-driver: support testing user units
It is quite complicated to test services using the test-driver when
declaring user services with `systemd.user.services` such as many
X11-based services like `xautolock.service`.

This change adds an optional `$user` parameter to each systemd-related
function in the test-driver and runs `systemctl --user` commands using
`su -l $user -c ...` and sets the `XDG_RUNTIME_DIR` variable
accordingly and a new function named `systemctl` which is able to run a
systemd command with or without a specified user.

The change can be confirmed with a simple VM declaration like this:

```
import ./nixos/tests/make-test.nix ({ pkgs, lib }:

with lib;

{
  name = "systemd-user-test";

  nodes.machine = {
    imports = [ ./nixos/tests/common/user-account.nix ];

    services.xserver.enable = true;
    services.xserver.displayManager.auto.enable = true;
    services.xserver.displayManager.auto.user = "bob";
    services.xserver.xautolock.enable = true;
  };

  testScript = ''
    $machine->start;
    $machine->waitForX;

    $machine->waitForUnit("xautolock.service", "bob");
    $machine->stopJob("xautolock.service", "bob");
    $machine->startJob("xautolock.service", "bob");
    $machine->systemctl("list-jobs --no-pager", "bob");
    $machine->systemctl("show 'xautolock.service' --no-pager", "bob");
  '';
})
```
Diffstat (limited to 'nixos/lib/test-driver')
-rw-r--r--nixos/lib/test-driver/Machine.pm28
1 files changed, 19 insertions, 9 deletions
diff --git a/nixos/lib/test-driver/Machine.pm b/nixos/lib/test-driver/Machine.pm
index a01c3c336a1..78598b3efb4 100644
--- a/nixos/lib/test-driver/Machine.pm
+++ b/nixos/lib/test-driver/Machine.pm
@@ -362,8 +362,8 @@ sub mustFail {
 
 
 sub getUnitInfo {
-    my ($self, $unit) = @_;
-    my ($status, $lines) = $self->execute("systemctl --no-pager show '$unit'");
+    my ($self, $unit, $user) = @_;
+    my ($status, $lines) = $self->systemctl("--no-pager show \"$unit\"", $user);
     return undef if $status != 0;
     my $info = {};
     foreach my $line (split '\n', $lines) {
@@ -373,6 +373,16 @@ sub getUnitInfo {
     return $info;
 }
 
+sub systemctl {
+    my ($self, $q, $user) = @_;
+    if ($user) {
+        $q =~ s/'/\\'/g;
+        return $self->execute("su -l $user -c \$'XDG_RUNTIME_DIR=/run/user/`id -u` systemctl --user $q'");
+    }
+
+    return $self->execute("systemctl $q");
+}
+
 # Fail if the given systemd unit is not in the "active" state.
 sub requireActiveUnit {
     my ($self, $unit) = @_;
@@ -387,16 +397,16 @@ sub requireActiveUnit {
 
 # Wait for a systemd unit to reach the "active" state.
 sub waitForUnit {
-    my ($self, $unit) = @_;
+    my ($self, $unit, $user) = @_;
     $self->nest("waiting for unit ‘$unit’", sub {
         retry sub {
-            my $info = $self->getUnitInfo($unit);
+            my $info = $self->getUnitInfo($unit, $user);
             my $state = $info->{ActiveState};
             die "unit ‘$unit’ reached state ‘$state’\n" if $state eq "failed";
             if ($state eq "inactive") {
                 # If there are no pending jobs, then assume this unit
                 # will never reach active state.
-                my ($status, $jobs) = $self->execute("systemctl list-jobs --full 2>&1");
+                my ($status, $jobs) = $self->systemctl("list-jobs --full 2>&1", $user);
                 if ($jobs =~ /No jobs/) {  # FIXME: fragile
                     # Handle the case where the unit may have started
                     # between the previous getUnitInfo() and
@@ -430,14 +440,14 @@ sub waitForFile {
 }
 
 sub startJob {
-    my ($self, $jobName) = @_;
-    $self->execute("systemctl start $jobName");
+    my ($self, $jobName, $user) = @_;
+    $self->systemctl("start $jobName", $user);
     # FIXME: check result
 }
 
 sub stopJob {
-    my ($self, $jobName) = @_;
-    $self->execute("systemctl stop $jobName");
+    my ($self, $jobName, $user) = @_;
+    $self->systemctl("stop $jobName", $user);
 }