# Functional test that boots a VM and run commands via a SSH session # # Copyright (c) Philippe Mathieu-Daudé # # This work is licensed under the terms of the GNU GPL, version 2 or # later. See the COPYING file in the top-level directory. import os import re import base64 import logging import time from avocado import skipUnless from avocado_qemu import Test from avocado_qemu import wait_for_console_pattern from avocado.utils import process from avocado.utils import archive from avocado.utils import ssh class LinuxSSH(Test): timeout = 150 # Not for 'configure --enable-debug --enable-debug-tcg' KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 ' VM_IP = '127.0.0.1' BASE_URL = 'https://people.debian.org/~aurel32/qemu/' IMAGE_INFO = { 'be': {'base_url': 'mips', 'image_name': 'debian_wheezy_mips_standard.qcow2', 'image_hash': '8987a63270df67345b2135a6b7a4885a35e392d5', 'kernel_hash': { 32: '592e384a4edc16dade52a6cd5c785c637bcbc9ad', 64: 'db6eea7de35d36c77d8c165b6bcb222e16eb91db'} }, 'le': {'base_url': 'mipsel', 'image_name': 'debian_wheezy_mipsel_standard.qcow2', 'image_hash': '7866764d9de3ef536ffca24c9fb9f04ffdb45802', 'kernel_hash': { 32: 'a66bea5a8adaa2cb3d36a1d4e0ccdb01be8f6c2a', 64: '6a7f77245acf231415a0e8b725d91ed2f3487794'} } } CPU_INFO = { 32: {'cpu': 'MIPS 24Kc', 'kernel_release': '3.2.0-4-4kc-malta'}, 64: {'cpu': 'MIPS 20Kc', 'kernel_release': '3.2.0-4-5kc-malta'} } def get_url(self, endianess, path=''): qkey = {'le': 'el', 'be': ''} return '%s/mips%s/%s' % (self.BASE_URL, qkey[endianess], path) def get_image_info(self, endianess): dinfo = self.IMAGE_INFO[endianess] image_url = self.get_url(endianess, dinfo['image_name']) image_hash = dinfo['image_hash'] return (image_url, image_hash) def get_kernel_info(self, endianess, wordsize): minfo = self.CPU_INFO[wordsize] kernel_url = self.get_url(endianess, 'vmlinux-%s' % minfo['kernel_release']) kernel_hash = self.IMAGE_INFO[endianess]['kernel_hash'][wordsize] return kernel_url, kernel_hash @skipUnless(ssh.SSH_CLIENT_BINARY, 'No SSH client available') @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') def setUp(self): super(LinuxSSH, self).setUp() def get_portfwd(self): res = self.vm.command('human-monitor-command', command_line='info usernet') line = res.split('\r\n')[2] port = re.split(r'.*TCP.HOST_FORWARD.*127\.0\.0\.1 (\d+)\s+10\..*', line)[1] self.log.debug("sshd listening on port:" + port) return port def ssh_connect(self, username, password): self.ssh_logger = logging.getLogger('ssh') port = self.get_portfwd() self.ssh_session = ssh.Session(self.VM_IP, port=int(port), user=username, password=password) for i in range(10): try: self.ssh_session.connect() return except: time.sleep(4) pass self.fail("sshd timeout") def ssh_disconnect_vm(self): self.ssh_session.quit() def ssh_command(self, command, is_root=True): self.ssh_logger.info(command) result = self.ssh_session.cmd(command) stdout_lines = [line.rstrip() for line in result.stdout_text.splitlines()] for line in stdout_lines: self.ssh_logger.info(line) stderr_lines = [line.rstrip() for line in result.stderr_text.splitlines()] for line in stderr_lines: self.ssh_logger.warning(line) return stdout_lines, stderr_lines def boot_debian_wheezy_image_and_ssh_login(self, endianess, kernel_path): image_url, image_hash = self.get_image_info(endianess) image_path = self.fetch_asset(image_url, asset_hash=image_hash) self.vm.set_console() kernel_command_line = (self.KERNEL_COMMON_COMMAND_LINE + 'console=ttyS0 root=/dev/sda1') self.vm.add_args('-no-reboot', '-kernel', kernel_path, '-append', kernel_command_line, '-drive', 'file=%s,snapshot=on' % image_path, '-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22', '-device', 'pcnet,netdev=vnet') self.vm.launch() self.log.info('VM launched, waiting for sshd') console_pattern = 'Starting OpenBSD Secure Shell server: sshd' wait_for_console_pattern(self, console_pattern, 'Oops') self.log.info('sshd ready') self.ssh_connect('root', 'root') def shutdown_via_ssh(self): self.ssh_command('poweroff') self.ssh_disconnect_vm() wait_for_console_pattern(self, 'Power down', 'Oops') def ssh_command_output_contains(self, cmd, exp): stdout, _ = self.ssh_command(cmd) for line in stdout: if exp in line: break else: self.fail('"%s" output does not contain "%s"' % (cmd, exp)) def run_common_commands(self, wordsize): self.ssh_command_output_contains( 'cat /proc/cpuinfo', self.CPU_INFO[wordsize]['cpu']) self.ssh_command_output_contains( 'uname -m', 'mips') self.ssh_command_output_contains( 'uname -r', self.CPU_INFO[wordsize]['kernel_release']) self.ssh_command_output_contains( 'cat /proc/interrupts', 'XT-PIC timer') self.ssh_command_output_contains( 'cat /proc/interrupts', 'XT-PIC i8042') self.ssh_command_output_contains( 'cat /proc/interrupts', 'XT-PIC serial') self.ssh_command_output_contains( 'cat /proc/interrupts', 'XT-PIC ata_piix') self.ssh_command_output_contains( 'cat /proc/interrupts', 'XT-PIC eth0') self.ssh_command_output_contains( 'cat /proc/devices', 'input') self.ssh_command_output_contains( 'cat /proc/devices', 'usb') self.ssh_command_output_contains( 'cat /proc/devices', 'fb') self.ssh_command_output_contains( 'cat /proc/ioports', ' : serial') self.ssh_command_output_contains( 'cat /proc/ioports', ' : ata_piix') self.ssh_command_output_contains( 'cat /proc/ioports', ' : piix4_smbus') self.ssh_command_output_contains( 'lspci -d 11ab:4620', 'GT-64120') self.ssh_command_output_contains( 'cat /sys/bus/i2c/devices/i2c-0/name', 'SMBus PIIX4 adapter') self.ssh_command_output_contains( 'cat /proc/mtd', 'YAMON') # Empty 'Board Config' (64KB) self.ssh_command_output_contains( 'md5sum /dev/mtd2ro', '0dfbe8aa4c20b52e1b8bf3cb6cbdf193') def check_mips_malta(self, uname_m, endianess): wordsize = 64 if '64' in uname_m else 32 kernel_url, kernel_hash = self.get_kernel_info(endianess, wordsize) kernel_path = self.fetch_asset(kernel_url, asset_hash=kernel_hash) self.boot_debian_wheezy_image_and_ssh_login(endianess, kernel_path) stdout, _ = self.ssh_command('uname -a') self.assertIn(True, [uname_m + " GNU/Linux" in line for line in stdout]) self.run_common_commands(wordsize) self.shutdown_via_ssh() def test_mips_malta32eb_kernel3_2_0(self): """ :avocado: tags=arch:mips :avocado: tags=endian:big :avocado: tags=device:pcnet32 """ self.check_mips_malta('mips', 'be') def test_mips_malta32el_kernel3_2_0(self): """ :avocado: tags=arch:mipsel :avocado: tags=endian:little :avocado: tags=device:pcnet32 """ self.check_mips_malta('mips', 'le') def test_mips_malta64eb_kernel3_2_0(self): """ :avocado: tags=arch:mips64 :avocado: tags=endian:big :avocado: tags=device:pcnet32 """ self.check_mips_malta('mips64', 'be') def test_mips_malta64el_kernel3_2_0(self): """ :avocado: tags=arch:mips64el :avocado: tags=endian:little :avocado: tags=device:pcnet32 """ self.check_mips_malta('mips64', 'le')