From a3ac6300923039901d185ed5a5f57d59fa99a6a5 Mon Sep 17 00:00:00 2001 From: aszlig Date: Thu, 31 Mar 2016 09:26:58 +0200 Subject: [PATCH] nixos/tests: Add a test for keyboard layouts I had the basic version of this laying around for some while but didn't continue on it. Originally it was for testing support for the Neo layout introduced back then (8cd6d53). We only test the first three Neo layers, because the last three layers are largely comprised of special characters and in addition to that the support for the VT keymap seems to be limited compared to the Xorg keymap. Yesterday @NicolasPetton on IRC had troubles with the Colemak layout (IRC logs: http://nixos.org/irc/logs/log.20160330, starting at 16:08) and I found that test again, so I went for improving and adding to . While the original problem seemed to be related to GDM, we can still add another subtest that checks whether GDM correctly applies the keyboard layout. However I don't have a clue how to properly configure the keyboard layout on GDM, at least not within the NixOS configuration. The main goal of this test is not to test a complete set of all key mappings but to check whether the keymap is loaded and working at all. It also serves as an example for NixOS keyboard configurations. The list of keyboard layouts is by no means complete, so everybody is free to add their own to the test or improve the existing ones. Signed-off-by: aszlig --- nixos/release.nix | 1 + nixos/tests/keymap.nix | 160 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 161 insertions(+) create mode 100644 nixos/tests/keymap.nix diff --git a/nixos/release.nix b/nixos/release.nix index d190733d5c13..8a01b2685a78 100644 --- a/nixos/release.nix +++ b/nixos/release.nix @@ -219,6 +219,7 @@ in rec { tests.ipv6 = callTest tests/ipv6.nix {}; tests.jenkins = callTest tests/jenkins.nix {}; tests.kde4 = callTest tests/kde4.nix {}; + tests.keymap = callSubTests tests/keymap.nix {}; tests.initrdNetwork = callTest tests/initrd-network.nix {}; tests.kubernetes = hydraJob (import tests/kubernetes.nix { system = "x86_64-linux"; }); tests.latestKernel.login = callTest tests/login.nix { latestKernel = true; }; diff --git a/nixos/tests/keymap.nix b/nixos/tests/keymap.nix new file mode 100644 index 000000000000..55a0e7603882 --- /dev/null +++ b/nixos/tests/keymap.nix @@ -0,0 +1,160 @@ +{ system ? builtins.currentSystem }: + +with import ../lib/testing.nix { inherit system; }; + +let + testReader = pkgs.writeScript "test-input-reader" '' + #!${pkgs.stdenv.shell} + readInput() { + touch /tmp/reader.ready + echo "Waiting for '$1' to be typed" + read -r -n1 c + if [ "$c" = "$2" ]; then + echo "SUCCESS: Got back '$c' as expected." + echo 0 >&2 + else + echo "FAIL: Expected '$2' but got '$c' instead." + echo 1 >&2 + fi + } + + main() { + error=0 + while [ $# -gt 0 ]; do + ret="$((readInput "$2" "$3" | systemd-cat -t "$1") 2>&1)" + if [ $ret -ne 0 ]; then error=1; fi + shift 3 + done + return $error + } + + main "$@"; echo -n $? > /tmp/reader.exit + ''; + + mkReaderInput = testname: { qwerty, expect }: with pkgs.lib; let + lq = length qwerty; + le = length expect; + msg = "`qwerty' (${lq}) and `expect' (${le}) lists" + + " need to be of the same length!"; + result = flatten (zipListsWith (a: b: [testname a b]) qwerty expect); + in if lq != le then throw msg else result; + + mkKeyboardTest = layout: { extraConfig ? {}, tests }: with pkgs.lib; let + readerInput = flatten (mapAttrsToList mkReaderInput tests); + perlStr = val: "'${escape ["'" "\\"] val}'"; + perlReaderInput = concatMapStringsSep ", " perlStr readerInput; + in makeTest { + name = "keymap-${layout}"; + + machine.i18n.consoleKeyMap = mkOverride 900 layout; + machine.services.xserver.layout = mkOverride 900 layout; + machine.imports = [ ./common/x11.nix extraConfig ]; + + testScript = '' + sub waitCatAndDelete ($) { + return $machine->succeed( + "for i in \$(seq 600); do if [ -e '$_[0]' ]; then ". + "cat '$_[0]' && rm -f '$_[0]' && exit 0; ". + "fi; sleep 0.1; done; echo timed out after 60 seconds >&2; exit 1" + ); + }; + + sub mkTest ($$) { + my ($desc, $cmd) = @_; + + my @testdata = (${perlReaderInput}); + my $shellTestdata = join ' ', map { "'".s/'/'\\'''/gr."'" } @testdata; + + subtest $desc, sub { + $machine->succeed("$cmd ${testReader} $shellTestdata &"); + while (my ($testname, $qwerty, $expect) = splice(@testdata, 0, 3)) { + waitCatAndDelete "/tmp/reader.ready"; + $machine->sendKeys($qwerty); + }; + my $exitcode = waitCatAndDelete "/tmp/reader.exit"; + die "tests for $desc failed" if $exitcode ne 0; + }; + } + + $machine->waitForX; + + mkTest "VT keymap", "openvt -sw --"; + mkTest "Xorg keymap", "DISPLAY=:0 xterm -fullscreen -e"; + ''; + }; + +in pkgs.lib.mapAttrs mkKeyboardTest { + azerty = { + tests = { + azqw.qwerty = [ "q" "w" ]; + azqw.expect = [ "a" "z" ]; + altgr.qwerty = [ "alt_r-2" "alt_r-3" "alt_r-4" "alt_r-5" "alt_r-6" ]; + altgr.expect = [ "~" "#" "{" "[" "|" ]; + }; + + extraConfig.i18n.consoleKeyMap = "azerty/fr"; + extraConfig.services.xserver.layout = "fr"; + }; + + colemak = { + tests = { + homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ]; + homerow.expect = [ "a" "r" "s" "t" "n" "e" "i" "o" ]; + }; + + extraConfig.i18n.consoleKeyMap = "en-latin9"; + extraConfig.services.xserver.layout = "us"; + extraConfig.services.xserver.xkbVariant = "colemak"; + }; + + dvorak = { + tests = { + homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ]; + homerow.expect = [ "a" "o" "e" "u" "h" "t" "n" "s" ]; + symbols.qwerty = [ "q" "w" "e" "minus" "equal" ]; + symbols.expect = [ "'" "," "." "[" "]" ]; + }; + }; + + dvp = { + tests = { + homerow.qwerty = [ "a" "s" "d" "f" "j" "k" "l" "semicolon" ]; + homerow.expect = [ "a" "o" "e" "u" "h" "t" "n" "s" ]; + numbers.qwerty = map (x: "shift-${x}") + [ "1" "2" "3" "4" "5" "6" "7" "8" "9" "0" "minus" ]; + numbers.expect = [ "%" "7" "5" "3" "1" "9" "0" "2" "4" "6" "8" ]; + symbols.qwerty = [ "1" "2" "3" "4" "5" "6" "7" "8" "9" "0" "minus" ]; + symbols.expect = [ "&" "[" "{" "}" "(" "=" "*" ")" "+" "]" "!" ]; + }; + + extraConfig.services.xserver.layout = "us"; + extraConfig.services.xserver.xkbVariant = "dvp"; + }; + + neo = { + tests = { + layer1.qwerty = [ "f" "j" ]; + layer1.expect = [ "e" "n" ]; + layer2.qwerty = [ "shift-f" "shift-j" "shift-6" ]; + layer2.expect = [ "E" "N" "$" ]; + layer3.qwerty = [ "caps_lock-d" "caps_lock-f" ]; + layer3.expect = [ "{" "}" ]; + }; + + extraConfig.services.xserver.layout = "de"; + extraConfig.services.xserver.xkbVariant = "neo"; + }; + + qwertz = { + tests = { + zy.qwerty = [ "z" "y" ]; + zy.expect = [ "y" "z" ]; + altgr.qwerty = map (x: "alt_r-${x}") + [ "q" "less" "7" "8" "9" "0" ]; + altgr.expect = [ "@" "|" "{" "[" "]" "}" ]; + }; + + extraConfig.i18n.consoleKeyMap = "de"; + extraConfig.services.xserver.layout = "de"; + }; +}