# Record/replay test that boots a complete Linux system via a cloud image
#
# Copyright (c) 2020 ISP RAS
#
# Author:
#  Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
#
# 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 logging
import time

from avocado import skipUnless
from avocado_qemu import BUILD_DIR
from avocado.utils import cloudinit
from avocado.utils import network
from avocado.utils import vmimage
from avocado.utils import datadrainer
from avocado.utils.path import find_command
from avocado_qemu.linuxtest import LinuxTest

class ReplayLinux(LinuxTest):
    """
    Boots a Linux system, checking for a successful initialization
    """

    timeout = 1800
    chksum = None
    hdd = 'ide-hd'
    cd = 'ide-cd'
    bus = 'ide'

    def setUp(self):
        # LinuxTest does many replay-incompatible things, but includes
        # useful methods. Do not setup LinuxTest here and just
        # call some functions.
        super(LinuxTest, self).setUp()
        self._set_distro()
        self.boot_path = self.download_boot()
        self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
                                                      self.name)
        ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
        self.cloudinit_path = self.prepare_cloudinit(ssh_pubkey)

    def vm_add_disk(self, vm, path, id, device):
        bus_string = ''
        if self.bus:
            bus_string = ',bus=%s.%d' % (self.bus, id,)
        vm.add_args('-drive', 'file=%s,snapshot=on,id=disk%s,if=none' % (path, id))
        vm.add_args('-drive',
            'driver=blkreplay,id=disk%s-rr,if=none,image=disk%s' % (id, id))
        vm.add_args('-device',
            '%s,drive=disk%s-rr%s' % (device, id, bus_string))

    def vm_add_cdrom(self, vm, path, id, device):
        vm.add_args('-drive', 'file=%s,id=disk%s,if=none,media=cdrom' % (path, id))

    def launch_and_wait(self, record, args, shift):
        self.require_netdev('user')
        vm = self.get_vm()
        vm.add_args('-smp', '1')
        vm.add_args('-m', '1024')
        vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
                    '-device', 'virtio-net,netdev=vnet')
        vm.add_args('-object', 'filter-replay,id=replay,netdev=vnet')
        if args:
            vm.add_args(*args)
        self.vm_add_disk(vm, self.boot_path, 0, self.hdd)
        self.vm_add_cdrom(vm, self.cloudinit_path, 1, self.cd)
        logger = logging.getLogger('replay')
        if record:
            logger.info('recording the execution...')
            mode = 'record'
        else:
            logger.info('replaying the execution...')
            mode = 'replay'
        replay_path = os.path.join(self.workdir, 'replay.bin')
        vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
                    (shift, mode, replay_path))

        start_time = time.time()

        vm.set_console()
        vm.launch()
        console_drainer = datadrainer.LineLogger(vm.console_socket.fileno(),
                                    logger=self.log.getChild('console'),
                                    stop_check=(lambda : not vm.is_running()))
        console_drainer.start()
        if record:
            while not self.phone_server.instance_phoned_back:
                self.phone_server.handle_request()
            vm.shutdown()
            logger.info('finished the recording with log size %s bytes'
                % os.path.getsize(replay_path))
        else:
            vm.event_wait('SHUTDOWN', self.timeout)
            vm.wait()
            logger.info('successfully finished the replay')
        elapsed = time.time() - start_time
        logger.info('elapsed time %.2f sec' % elapsed)
        return elapsed

    def run_rr(self, args=None, shift=7):
        t1 = self.launch_and_wait(True, args, shift)
        t2 = self.launch_and_wait(False, args, shift)
        logger = logging.getLogger('replay')
        logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))

@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
class ReplayLinuxX8664(ReplayLinux):
    """
    :avocado: tags=arch:x86_64
    :avocado: tags=accel:tcg
    """

    chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'

    def test_pc_i440fx(self):
        """
        :avocado: tags=machine:pc
        """
        self.run_rr(shift=1)

    def test_pc_q35(self):
        """
        :avocado: tags=machine:q35
        """
        self.run_rr(shift=3)

@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
class ReplayLinuxX8664Virtio(ReplayLinux):
    """
    :avocado: tags=arch:x86_64
    :avocado: tags=virtio
    :avocado: tags=accel:tcg
    """

    hdd = 'virtio-blk-pci'
    cd = 'virtio-blk-pci'
    bus = None

    chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'

    def test_pc_i440fx(self):
        """
        :avocado: tags=machine:pc
        """
        self.run_rr(shift=1)

    def test_pc_q35(self):
        """
        :avocado: tags=machine:q35
        """
        self.run_rr(shift=3)

@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
class ReplayLinuxAarch64(ReplayLinux):
    """
    :avocado: tags=accel:tcg
    :avocado: tags=arch:aarch64
    :avocado: tags=machine:virt
    :avocado: tags=cpu:max
    """

    chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49'

    hdd = 'virtio-blk-device'
    cd = 'virtio-blk-device'
    bus = None

    def get_common_args(self):
        return ('-bios',
                os.path.join(BUILD_DIR, 'pc-bios', 'edk2-aarch64-code.fd'),
                "-cpu", "max,lpa2=off",
                '-device', 'virtio-rng-pci,rng=rng0',
                '-object', 'rng-builtin,id=rng0')

    def test_virt_gicv2(self):
        """
        :avocado: tags=machine:gic-version=2
        """

        self.run_rr(shift=3,
                    args=(*self.get_common_args(),
                          "-machine", "virt,gic-version=2"))

    def test_virt_gicv3(self):
        """
        :avocado: tags=machine:gic-version=3
        """

        self.run_rr(shift=3,
                    args=(*self.get_common_args(),
                          "-machine", "virt,gic-version=3"))
