#!/usr/bin/env python3
# group: rw auto
#
# Tests for image block commit.
#
# Copyright (C) 2012 IBM, Corp.
# Copyright (C) 2012 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Test for live block commit
# Derived from Image Streaming Test 030

import time
import os
import iotests
from iotests import qemu_img, qemu_io
import struct
import errno

backing_img = os.path.join(iotests.test_dir, 'backing.img')
mid_img = os.path.join(iotests.test_dir, 'mid.img')
test_img = os.path.join(iotests.test_dir, 'test.img')

class ImageCommitTestCase(iotests.QMPTestCase):
    '''Abstract base class for image commit test cases'''

    def wait_for_complete(self, need_ready=False):
        completed = False
        ready = False
        while not completed:
            for event in self.vm.get_qmp_events(wait=True):
                if event['event'] == 'BLOCK_JOB_COMPLETED':
                    self.assert_qmp_absent(event, 'data/error')
                    self.assert_qmp(event, 'data/type', 'commit')
                    self.assert_qmp(event, 'data/device', 'drive0')
                    self.assert_qmp(event, 'data/offset', event['data']['len'])
                    if need_ready:
                        self.assertTrue(ready, "Expecting BLOCK_JOB_COMPLETED event")
                    completed = True
                elif event['event'] == 'BLOCK_JOB_READY':
                    ready = True
                    self.assert_qmp(event, 'data/type', 'commit')
                    self.assert_qmp(event, 'data/device', 'drive0')
                    self.vm.qmp('block-job-complete', device='drive0')

        self.assert_no_active_block_jobs()
        self.vm.shutdown()

    def run_commit_test(self, top, base, need_ready=False, node_names=False):
        self.assert_no_active_block_jobs()
        if node_names:
            result = self.vm.qmp('block-commit', device='drive0', top_node=top, base_node=base)
        else:
            result = self.vm.qmp('block-commit', device='drive0', top=top, base=base)
        self.assert_qmp(result, 'return', {})
        self.wait_for_complete(need_ready)

    def run_default_commit_test(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0')
        self.assert_qmp(result, 'return', {})
        self.wait_for_complete()

class TestSingleDrive(ImageCommitTestCase):
    # Need some space after the copied data so that throttling is effective in
    # tests that use it rather than just completing the job immediately
    image_len = 2 * 1024 * 1024
    test_len = 1 * 1024 * 256

    def setUp(self):
        iotests.create_image(backing_img, self.image_len)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % backing_img, '-F', 'raw', mid_img)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % mid_img,
                 '-F', iotests.imgfmt, test_img)
        qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', backing_img)
        qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img)
        self.vm = iotests.VM().add_drive(test_img, "node-name=top,backing.node-name=mid,backing.backing.node-name=base", interface="none")
        self.vm.add_device('virtio-scsi')
        self.vm.add_device("scsi-hd,id=scsi0,drive=drive0")
        self.vm.launch()

    def tearDown(self):
        self.vm.shutdown()
        os.remove(test_img)
        os.remove(mid_img)
        os.remove(backing_img)

    def test_commit(self):
        self.run_commit_test(mid_img, backing_img)
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))

    def test_commit_node(self):
        self.run_commit_test("mid", "base", node_names=True)
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))

    @iotests.skip_if_unsupported(['throttle'])
    def test_commit_with_filter_and_quit(self):
        result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg')
        self.assert_qmp(result, 'return', {})

        # Add a filter outside of the backing chain
        result = self.vm.qmp('blockdev-add', driver='throttle', node_name='filter', throttle_group='tg', file='mid')
        self.assert_qmp(result, 'return', {})

        result = self.vm.qmp('block-commit', device='drive0')
        self.assert_qmp(result, 'return', {})

        # Quit immediately, thus forcing a simultaneous cancel of the
        # block job and a bdrv_drain_all()
        result = self.vm.qmp('quit')
        self.assert_qmp(result, 'return', {})

    # Same as above, but this time we add the filter after starting the job
    @iotests.skip_if_unsupported(['throttle'])
    def test_commit_plus_filter_and_quit(self):
        result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg')
        self.assert_qmp(result, 'return', {})

        result = self.vm.qmp('block-commit', device='drive0')
        self.assert_qmp(result, 'return', {})

        # Add a filter outside of the backing chain
        result = self.vm.qmp('blockdev-add', driver='throttle', node_name='filter', throttle_group='tg', file='mid')
        self.assert_qmp(result, 'return', {})

        # Quit immediately, thus forcing a simultaneous cancel of the
        # block job and a bdrv_drain_all()
        result = self.vm.qmp('quit')
        self.assert_qmp(result, 'return', {})

    def test_device_not_found(self):
        result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % mid_img)
        self.assert_qmp(result, 'error/class', 'DeviceNotFound')

    def test_top_same_base(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % backing_img)
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "Can't find '%s' in the backing chain" % backing_img)

    def test_top_invalid(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top='badfile', base='%s' % backing_img)
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', 'Top image file badfile not found')

    def test_base_invalid(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % mid_img, base='badfile')
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "Can't find 'badfile' in the backing chain")

    def test_top_node_invalid(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top_node='badfile', base_node='base')
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "Cannot find device='' nor node-name='badfile'")

    def test_base_node_invalid(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top_node='mid', base_node='badfile')
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "Cannot find device='' nor node-name='badfile'")

    def test_top_path_and_node(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top_node='mid', base_node='base', top='%s' % mid_img)
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "'top-node' and 'top' are mutually exclusive")

    def test_base_path_and_node(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top_node='mid', base_node='base', base='%s' % backing_img)
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "'base-node' and 'base' are mutually exclusive")

    def test_top_is_active(self):
        self.run_commit_test(test_img, backing_img, need_ready=True)
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))

    def test_top_is_default_active(self):
        self.run_default_commit_test()
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', backing_img).find("verification failed"))
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', backing_img).find("verification failed"))

    def test_top_and_base_reversed(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % backing_img, base='%s' % mid_img)
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "Can't find '%s' in the backing chain" % mid_img)

    def test_top_and_base_node_reversed(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top_node='base', base_node='top')
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "'top' is not in this backing file chain")

    def test_top_node_in_wrong_chain(self):
        self.assert_no_active_block_jobs()

        result = self.vm.qmp('blockdev-add', driver='null-co', node_name='null')
        self.assert_qmp(result, 'return', {})

        result = self.vm.qmp('block-commit', device='drive0', top_node='null', base_node='base')
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "'null' is not in this backing file chain")

    # When the job is running on a BB that is automatically deleted on hot
    # unplug, the job is cancelled when the device disappears
    def test_hot_unplug(self):
        if self.image_len == 0:
            return

        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top=mid_img,
                             base=backing_img, speed=(self.image_len // 4))
        self.assert_qmp(result, 'return', {})
        result = self.vm.qmp('device_del', id='scsi0')
        self.assert_qmp(result, 'return', {})

        cancelled = False
        deleted = False
        while not cancelled or not deleted:
            for event in self.vm.get_qmp_events(wait=True):
                if event['event'] == 'DEVICE_DELETED':
                    self.assert_qmp(event, 'data/device', 'scsi0')
                    deleted = True
                elif event['event'] == 'BLOCK_JOB_CANCELLED':
                    self.assert_qmp(event, 'data/device', 'drive0')
                    cancelled = True
                elif event['event'] == 'JOB_STATUS_CHANGE':
                    self.assert_qmp(event, 'data/id', 'drive0')
                else:
                    self.fail("Unexpected event %s" % (event['event']))

        self.assert_no_active_block_jobs()

    # Tests that the insertion of the commit_top filter node doesn't make a
    # difference to query-blockstat
    def test_implicit_node(self):
        if self.image_len == 0:
            return

        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top=mid_img,
                             base=backing_img, speed=(self.image_len // 4))
        self.assert_qmp(result, 'return', {})

        result = self.vm.qmp('query-block')
        self.assert_qmp(result, 'return[0]/inserted/file', test_img)
        self.assert_qmp(result, 'return[0]/inserted/drv', iotests.imgfmt)
        self.assert_qmp(result, 'return[0]/inserted/backing_file', mid_img)
        self.assert_qmp(result, 'return[0]/inserted/backing_file_depth', 2)
        self.assert_qmp(result, 'return[0]/inserted/image/filename', test_img)
        self.assert_qmp(result, 'return[0]/inserted/image/backing-image/filename', mid_img)
        self.assert_qmp(result, 'return[0]/inserted/image/backing-image/backing-image/filename', backing_img)

        result = self.vm.qmp('query-blockstats')
        self.assert_qmp(result, 'return[0]/node-name', 'top')
        self.assert_qmp(result, 'return[0]/backing/node-name', 'mid')
        self.assert_qmp(result, 'return[0]/backing/backing/node-name', 'base')

        self.cancel_and_wait()
        self.assert_no_active_block_jobs()

class TestRelativePaths(ImageCommitTestCase):
    image_len = 1 * 1024 * 1024
    test_len = 1 * 1024 * 256

    dir1 = "dir1"
    dir2 = "dir2/"
    dir3 = "dir2/dir3/"

    test_img = os.path.join(iotests.test_dir, dir3, 'test.img')
    mid_img = "../mid.img"
    backing_img = "../dir1/backing.img"

    backing_img_abs = os.path.join(iotests.test_dir, dir1, 'backing.img')
    mid_img_abs = os.path.join(iotests.test_dir, dir2, 'mid.img')

    def setUp(self):
        try:
            os.mkdir(os.path.join(iotests.test_dir, self.dir1))
            os.mkdir(os.path.join(iotests.test_dir, self.dir2))
            os.mkdir(os.path.join(iotests.test_dir, self.dir3))
        except OSError as exception:
            if exception.errno != errno.EEXIST:
                raise
        iotests.create_image(self.backing_img_abs, TestRelativePaths.image_len)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % self.backing_img_abs,
                 '-F', 'raw', self.mid_img_abs)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % self.mid_img_abs,
                 '-F', iotests.imgfmt, self.test_img)
        qemu_img('rebase', '-u', '-b', self.backing_img,
                 '-F', 'raw', self.mid_img_abs)
        qemu_img('rebase', '-u', '-b', self.mid_img,
                 '-F', iotests.imgfmt, self.test_img)
        qemu_io('-f', 'raw', '-c', 'write -P 0xab 0 524288', self.backing_img_abs)
        qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', self.mid_img_abs)
        self.vm = iotests.VM().add_drive(self.test_img)
        self.vm.launch()

    def tearDown(self):
        self.vm.shutdown()
        os.remove(self.test_img)
        os.remove(self.mid_img_abs)
        os.remove(self.backing_img_abs)
        try:
            os.rmdir(os.path.join(iotests.test_dir, self.dir1))
            os.rmdir(os.path.join(iotests.test_dir, self.dir3))
            os.rmdir(os.path.join(iotests.test_dir, self.dir2))
        except OSError as exception:
            if exception.errno != errno.EEXIST and exception.errno != errno.ENOTEMPTY:
                raise

    def test_commit(self):
        self.run_commit_test(self.mid_img, self.backing_img)
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed"))
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed"))

    def test_device_not_found(self):
        result = self.vm.qmp('block-commit', device='nonexistent', top='%s' % self.mid_img)
        self.assert_qmp(result, 'error/class', 'DeviceNotFound')

    def test_top_same_base(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img, base='%s' % self.mid_img)
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "Can't find '%s' in the backing chain" % self.mid_img)

    def test_top_invalid(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top='badfile', base='%s' % self.backing_img)
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', 'Top image file badfile not found')

    def test_base_invalid(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.mid_img, base='badfile')
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "Can't find 'badfile' in the backing chain")

    def test_top_is_active(self):
        self.run_commit_test(self.test_img, self.backing_img)
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xab 0 524288', self.backing_img_abs).find("verification failed"))
        self.assertEqual(-1, qemu_io('-f', 'raw', '-c', 'read -P 0xef 524288 524288', self.backing_img_abs).find("verification failed"))

    def test_top_and_base_reversed(self):
        self.assert_no_active_block_jobs()
        result = self.vm.qmp('block-commit', device='drive0', top='%s' % self.backing_img, base='%s' % self.mid_img)
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', "Can't find '%s' in the backing chain" % self.mid_img)


class TestSetSpeed(ImageCommitTestCase):
    image_len = 80 * 1024 * 1024 # MB

    def setUp(self):
        qemu_img('create', backing_img, str(TestSetSpeed.image_len))
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % backing_img, '-F', 'raw', mid_img)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % mid_img,
                 '-F', iotests.imgfmt, test_img)
        qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x1 0 512', test_img)
        qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xef 524288 524288', mid_img)
        self.vm = iotests.VM().add_drive('blkdebug::' + test_img)
        self.vm.launch()

    def tearDown(self):
        self.vm.shutdown()
        os.remove(test_img)
        os.remove(mid_img)
        os.remove(backing_img)

    def test_set_speed(self):
        self.assert_no_active_block_jobs()

        self.vm.pause_drive('drive0')
        result = self.vm.qmp('block-commit', device='drive0', top=mid_img, speed=1024 * 1024)
        self.assert_qmp(result, 'return', {})

        # Ensure the speed we set was accepted
        result = self.vm.qmp('query-block-jobs')
        self.assert_qmp(result, 'return[0]/device', 'drive0')
        self.assert_qmp(result, 'return[0]/speed', 1024 * 1024)

        self.cancel_and_wait(resume=True)

class TestActiveZeroLengthImage(TestSingleDrive):
    image_len = 0

class TestReopenOverlay(ImageCommitTestCase):
    image_len = 1024 * 1024
    img0 = os.path.join(iotests.test_dir, '0.img')
    img1 = os.path.join(iotests.test_dir, '1.img')
    img2 = os.path.join(iotests.test_dir, '2.img')
    img3 = os.path.join(iotests.test_dir, '3.img')

    def setUp(self):
        iotests.create_image(self.img0, self.image_len)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % self.img0, '-F', 'raw', self.img1)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % self.img1,
                 '-F', iotests.imgfmt, self.img2)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % self.img2,
                 '-F', iotests.imgfmt, self.img3)
        qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xab 0 128K', self.img1)
        self.vm = iotests.VM().add_drive(self.img3)
        self.vm.launch()

    def tearDown(self):
        self.vm.shutdown()
        os.remove(self.img0)
        os.remove(self.img1)
        os.remove(self.img2)
        os.remove(self.img3)

    # This tests what happens when the overlay image of the 'top' node
    # needs to be reopened in read-write mode in order to update the
    # backing image string.
    def test_reopen_overlay(self):
        self.run_commit_test(self.img1, self.img0)

class TestErrorHandling(iotests.QMPTestCase):
    image_len = 2 * 1024 * 1024

    def setUp(self):
        iotests.create_image(backing_img, self.image_len)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % backing_img,
                 '-F', 'raw', mid_img)
        qemu_img('create', '-f', iotests.imgfmt,
                 '-o', 'backing_file=%s' % mid_img,
                 '-F', iotests.imgfmt, test_img)

        qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x11 0 512k', mid_img)
        qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0x22 0 512k', test_img)

        self.vm = iotests.VM()
        self.vm.launch()

        self.blkdebug_file = iotests.file_path("blkdebug.conf")

    def tearDown(self):
        self.vm.shutdown()
        os.remove(test_img)
        os.remove(mid_img)
        os.remove(backing_img)

    def blockdev_add(self, **kwargs):
        result = self.vm.qmp('blockdev-add', **kwargs)
        self.assert_qmp(result, 'return', {})

    def add_block_nodes(self, base_debug=None, mid_debug=None, top_debug=None):
        self.blockdev_add(node_name='base-file', driver='file',
                          filename=backing_img)
        self.blockdev_add(node_name='mid-file', driver='file',
                          filename=mid_img)
        self.blockdev_add(node_name='top-file', driver='file',
                          filename=test_img)

        if base_debug:
            self.blockdev_add(node_name='base-dbg', driver='blkdebug',
                              image='base-file', inject_error=base_debug)
        if mid_debug:
            self.blockdev_add(node_name='mid-dbg', driver='blkdebug',
                              image='mid-file', inject_error=mid_debug)
        if top_debug:
            self.blockdev_add(node_name='top-dbg', driver='blkdebug',
                              image='top-file', inject_error=top_debug)

        self.blockdev_add(node_name='base-fmt', driver='raw',
                          file=('base-dbg' if base_debug else 'base-file'))
        self.blockdev_add(node_name='mid-fmt', driver=iotests.imgfmt,
                          file=('mid-dbg' if mid_debug else 'mid-file'),
                          backing='base-fmt')
        self.blockdev_add(node_name='top-fmt', driver=iotests.imgfmt,
                          file=('top-dbg' if top_debug else 'top-file'),
                          backing='mid-fmt')

    def run_job(self, expected_events, error_pauses_job=False):
        match_device = {'data': {'device': 'job0'}}
        events = [
            ('BLOCK_JOB_COMPLETED', match_device),
            ('BLOCK_JOB_CANCELLED', match_device),
            ('BLOCK_JOB_ERROR', match_device),
            ('BLOCK_JOB_READY', match_device),
        ]

        completed = False
        log = []
        while not completed:
            ev = self.vm.events_wait(events, timeout=5.0)
            if ev['event'] == 'BLOCK_JOB_COMPLETED':
                completed = True
            elif ev['event'] == 'BLOCK_JOB_ERROR':
                if error_pauses_job:
                    result = self.vm.qmp('block-job-resume', device='job0')
                    self.assert_qmp(result, 'return', {})
            elif ev['event'] == 'BLOCK_JOB_READY':
                result = self.vm.qmp('block-job-complete', device='job0')
                self.assert_qmp(result, 'return', {})
            else:
                self.fail("Unexpected event: %s" % ev)
            log.append(iotests.filter_qmp_event(ev))

        self.maxDiff = None
        self.assertEqual(expected_events, log)

    def event_error(self, op, action):
        return {
            'event': 'BLOCK_JOB_ERROR',
            'data': {'action': action, 'device': 'job0', 'operation': op},
            'timestamp': {'microseconds': 'USECS', 'seconds': 'SECS'}
        }

    def event_ready(self):
        return {
            'event': 'BLOCK_JOB_READY',
            'data': {'device': 'job0',
                     'len': 524288,
                     'offset': 524288,
                     'speed': 0,
                     'type': 'commit'},
            'timestamp': {'microseconds': 'USECS', 'seconds': 'SECS'},
        }

    def event_completed(self, errmsg=None, active=True):
        max_len = 524288 if active else self.image_len
        data = {
            'device': 'job0',
            'len': max_len,
            'offset': 0 if errmsg else max_len,
            'speed': 0,
            'type': 'commit'
        }
        if errmsg:
            data['error'] = errmsg

        return {
            'event': 'BLOCK_JOB_COMPLETED',
            'data': data,
            'timestamp': {'microseconds': 'USECS', 'seconds': 'SECS'},
        }

    def blkdebug_event(self, event, is_raw=False):
        if event:
            return [{
                'event': event,
                'sector': 512 if is_raw else 1024,
                'once': True,
            }]
        return None

    def prepare_and_start_job(self, on_error, active=True,
                              top_event=None, mid_event=None, base_event=None):

        top_debug = self.blkdebug_event(top_event)
        mid_debug = self.blkdebug_event(mid_event)
        base_debug = self.blkdebug_event(base_event, True)

        self.add_block_nodes(top_debug=top_debug, mid_debug=mid_debug,
                             base_debug=base_debug)

        result = self.vm.qmp('block-commit', job_id='job0', device='top-fmt',
                             top_node='top-fmt' if active else 'mid-fmt',
                             base_node='mid-fmt' if active else 'base-fmt',
                             on_error=on_error)
        self.assert_qmp(result, 'return', {})

    def testActiveReadErrorReport(self):
        self.prepare_and_start_job('report', top_event='read_aio')
        self.run_job([
            self.event_error('read', 'report'),
            self.event_completed('Input/output error')
        ])

        self.vm.shutdown()
        self.assertFalse(iotests.compare_images(test_img, mid_img),
                         'target image matches source after error')

    def testActiveReadErrorStop(self):
        self.prepare_and_start_job('stop', top_event='read_aio')
        self.run_job([
            self.event_error('read', 'stop'),
            self.event_ready(),
            self.event_completed()
        ], error_pauses_job=True)

        self.vm.shutdown()
        self.assertTrue(iotests.compare_images(test_img, mid_img),
                        'target image does not match source after commit')

    def testActiveReadErrorIgnore(self):
        self.prepare_and_start_job('ignore', top_event='read_aio')
        self.run_job([
            self.event_error('read', 'ignore'),
            self.event_ready(),
            self.event_completed()
        ])

        # For commit, 'ignore' actually means retry, so this will succeed
        self.vm.shutdown()
        self.assertTrue(iotests.compare_images(test_img, mid_img),
                        'target image does not match source after commit')

    def testActiveWriteErrorReport(self):
        self.prepare_and_start_job('report', mid_event='write_aio')
        self.run_job([
            self.event_error('write', 'report'),
            self.event_completed('Input/output error')
        ])

        self.vm.shutdown()
        self.assertFalse(iotests.compare_images(test_img, mid_img),
                         'target image matches source after error')

    def testActiveWriteErrorStop(self):
        self.prepare_and_start_job('stop', mid_event='write_aio')
        self.run_job([
            self.event_error('write', 'stop'),
            self.event_ready(),
            self.event_completed()
        ], error_pauses_job=True)

        self.vm.shutdown()
        self.assertTrue(iotests.compare_images(test_img, mid_img),
                        'target image does not match source after commit')

    def testActiveWriteErrorIgnore(self):
        self.prepare_and_start_job('ignore', mid_event='write_aio')
        self.run_job([
            self.event_error('write', 'ignore'),
            self.event_ready(),
            self.event_completed()
        ])

        # For commit, 'ignore' actually means retry, so this will succeed
        self.vm.shutdown()
        self.assertTrue(iotests.compare_images(test_img, mid_img),
                        'target image does not match source after commit')

    def testIntermediateReadErrorReport(self):
        self.prepare_and_start_job('report', active=False, mid_event='read_aio')
        self.run_job([
            self.event_error('read', 'report'),
            self.event_completed('Input/output error', active=False)
        ])

        self.vm.shutdown()
        self.assertFalse(iotests.compare_images(mid_img, backing_img, fmt2='raw'),
                         'target image matches source after error')

    def testIntermediateReadErrorStop(self):
        self.prepare_and_start_job('stop', active=False, mid_event='read_aio')
        self.run_job([
            self.event_error('read', 'stop'),
            self.event_completed(active=False)
        ], error_pauses_job=True)

        self.vm.shutdown()
        self.assertTrue(iotests.compare_images(mid_img, backing_img, fmt2='raw'),
                        'target image does not match source after commit')

    def testIntermediateReadErrorIgnore(self):
        self.prepare_and_start_job('ignore', active=False, mid_event='read_aio')
        self.run_job([
            self.event_error('read', 'ignore'),
            self.event_completed(active=False)
        ])

        # For commit, 'ignore' actually means retry, so this will succeed
        self.vm.shutdown()
        self.assertTrue(iotests.compare_images(mid_img, backing_img, fmt2='raw'),
                        'target image does not match source after commit')

    def testIntermediateWriteErrorReport(self):
        self.prepare_and_start_job('report', active=False, base_event='write_aio')
        self.run_job([
            self.event_error('write', 'report'),
            self.event_completed('Input/output error', active=False)
        ])

        self.vm.shutdown()
        self.assertFalse(iotests.compare_images(mid_img, backing_img, fmt2='raw'),
                         'target image matches source after error')

    def testIntermediateWriteErrorStop(self):
        self.prepare_and_start_job('stop', active=False, base_event='write_aio')
        self.run_job([
            self.event_error('write', 'stop'),
            self.event_completed(active=False)
        ], error_pauses_job=True)

        self.vm.shutdown()
        self.assertTrue(iotests.compare_images(mid_img, backing_img, fmt2='raw'),
                        'target image does not match source after commit')

    def testIntermediateWriteErrorIgnore(self):
        self.prepare_and_start_job('ignore', active=False, base_event='write_aio')
        self.run_job([
            self.event_error('write', 'ignore'),
            self.event_completed(active=False)
        ])

        # For commit, 'ignore' actually means retry, so this will succeed
        self.vm.shutdown()
        self.assertTrue(iotests.compare_images(mid_img, backing_img, fmt2='raw'),
                        'target image does not match source after commit')

class TestCommitWithFilters(iotests.QMPTestCase):
    img0 = os.path.join(iotests.test_dir, '0.img')
    img1 = os.path.join(iotests.test_dir, '1.img')
    img2 = os.path.join(iotests.test_dir, '2.img')
    img3 = os.path.join(iotests.test_dir, '3.img')

    def do_test_io(self, read_or_write):
        for index, pattern_file in enumerate(self.pattern_files):
            result = qemu_io('-f', iotests.imgfmt,
                             '-c',
                             f'{read_or_write} -P {index + 1} {index}M 1M',
                             pattern_file)
            self.assertFalse('Pattern verification failed' in result)

    def setUp(self):
        qemu_img('create', '-f', iotests.imgfmt, self.img0, '64M')
        qemu_img('create', '-f', iotests.imgfmt, self.img1, '64M')
        qemu_img('create', '-f', iotests.imgfmt, self.img2, '64M')
        qemu_img('create', '-f', iotests.imgfmt, self.img3, '64M')

        # Distributions of the patterns in the files; this is checked
        # by tearDown() and should be changed by the test cases as is
        # necessary
        self.pattern_files = [self.img0, self.img1, self.img2, self.img3]

        self.do_test_io('write')

        self.vm = iotests.VM().add_device('virtio-scsi,id=vio-scsi')
        self.vm.launch()

        result = self.vm.qmp('object-add', qom_type='throttle-group', id='tg')
        self.assert_qmp(result, 'return', {})

        result = self.vm.qmp('blockdev-add', **{
                'node-name': 'top-filter',
                'driver': 'throttle',
                'throttle-group': 'tg',
                'file': {
                    'node-name': 'cow-3',
                    'driver': iotests.imgfmt,
                    'file': {
                        'driver': 'file',
                        'filename': self.img3
                    },
                    'backing': {
                        'node-name': 'cow-2',
                        'driver': iotests.imgfmt,
                        'file': {
                            'driver': 'file',
                            'filename': self.img2
                        },
                        'backing': {
                            'node-name': 'cow-1',
                            'driver': iotests.imgfmt,
                            'file': {
                                'driver': 'file',
                                'filename': self.img1
                            },
                            'backing': {
                                'node-name': 'bottom-filter',
                                'driver': 'throttle',
                                'throttle-group': 'tg',
                                'file': {
                                    'node-name': 'cow-0',
                                    'driver': iotests.imgfmt,
                                    'file': {
                                        'driver': 'file',
                                        'filename': self.img0
                                    }
                                }
                            }
                        }
                    }
                }
            })
        self.assert_qmp(result, 'return', {})

    def tearDown(self):
        self.vm.shutdown()
        self.do_test_io('read')

        os.remove(self.img3)
        os.remove(self.img2)
        os.remove(self.img1)
        os.remove(self.img0)

    # Filters make for funny filenames, so we cannot just use
    # self.imgX to get them
    def get_filename(self, node):
        return self.vm.node_info(node)['image']['filename']

    def test_filterless_commit(self):
        result = self.vm.qmp('block-commit',
                             job_id='commit',
                             device='top-filter',
                             top_node='cow-2',
                             base_node='cow-1')
        self.assert_qmp(result, 'return', {})
        self.wait_until_completed(drive='commit')

        self.assertIsNotNone(self.vm.node_info('cow-3'))
        self.assertIsNone(self.vm.node_info('cow-2'))
        self.assertIsNotNone(self.vm.node_info('cow-1'))

        # 2 has been comitted into 1
        self.pattern_files[2] = self.img1

    def test_commit_through_filter(self):
        result = self.vm.qmp('block-commit',
                             job_id='commit',
                             device='top-filter',
                             top_node='cow-1',
                             base_node='cow-0')
        self.assert_qmp(result, 'return', {})
        self.wait_until_completed(drive='commit')

        self.assertIsNotNone(self.vm.node_info('cow-2'))
        self.assertIsNone(self.vm.node_info('cow-1'))
        self.assertIsNone(self.vm.node_info('bottom-filter'))
        self.assertIsNotNone(self.vm.node_info('cow-0'))

        # 1 has been comitted into 0
        self.pattern_files[1] = self.img0

    def test_filtered_active_commit_with_filter(self):
        # Add a device, so the commit job finds a parent it can change
        # to point to the base node (so we can test that top-filter is
        # dropped from the graph)
        result = self.vm.qmp('device_add', id='drv0', driver='scsi-hd',
                             bus='vio-scsi.0', drive='top-filter')
        self.assert_qmp(result, 'return', {})

        # Try to release our reference to top-filter; that should not
        # work because drv0 uses it
        result = self.vm.qmp('blockdev-del', node_name='top-filter')
        self.assert_qmp(result, 'error/class', 'GenericError')
        self.assert_qmp(result, 'error/desc', 'Node top-filter is in use')

        result = self.vm.qmp('block-commit',
                             job_id='commit',
                             device='top-filter',
                             base_node='cow-2')
        self.assert_qmp(result, 'return', {})
        self.complete_and_wait(drive='commit')

        # Try to release our reference to top-filter again
        result = self.vm.qmp('blockdev-del', node_name='top-filter')
        self.assert_qmp(result, 'return', {})

        self.assertIsNone(self.vm.node_info('top-filter'))
        self.assertIsNone(self.vm.node_info('cow-3'))
        self.assertIsNotNone(self.vm.node_info('cow-2'))

        # Check that drv0 is now connected to cow-2
        blockdevs = self.vm.qmp('query-block')['return']
        drv0 = next(dev for dev in blockdevs if dev['qdev'] == 'drv0')
        self.assertEqual(drv0['inserted']['node-name'], 'cow-2')

        # 3 has been comitted into 2
        self.pattern_files[3] = self.img2

    def test_filtered_active_commit_without_filter(self):
        result = self.vm.qmp('block-commit',
                             job_id='commit',
                             device='top-filter',
                             top_node='cow-3',
                             base_node='cow-2')
        self.assert_qmp(result, 'return', {})
        self.complete_and_wait(drive='commit')

        self.assertIsNotNone(self.vm.node_info('top-filter'))
        self.assertIsNone(self.vm.node_info('cow-3'))
        self.assertIsNotNone(self.vm.node_info('cow-2'))

        # 3 has been comitted into 2
        self.pattern_files[3] = self.img2

class TestCommitWithOverriddenBacking(iotests.QMPTestCase):
    img_base_a = os.path.join(iotests.test_dir, 'base_a.img')
    img_base_b = os.path.join(iotests.test_dir, 'base_b.img')
    img_top = os.path.join(iotests.test_dir, 'top.img')

    def setUp(self):
        qemu_img('create', '-f', iotests.imgfmt, self.img_base_a, '1M')
        qemu_img('create', '-f', iotests.imgfmt, self.img_base_b, '1M')
        qemu_img('create', '-f', iotests.imgfmt, '-b', self.img_base_a,
                 '-F', iotests.imgfmt, self.img_top)

        self.vm = iotests.VM()
        self.vm.launch()

        # Use base_b instead of base_a as the backing of top
        result = self.vm.qmp('blockdev-add', **{
                                'node-name': 'top',
                                'driver': iotests.imgfmt,
                                'file': {
                                    'driver': 'file',
                                    'filename': self.img_top
                                },
                                'backing': {
                                    'node-name': 'base',
                                    'driver': iotests.imgfmt,
                                    'file': {
                                        'driver': 'file',
                                        'filename': self.img_base_b
                                    }
                                }
                            })
        self.assert_qmp(result, 'return', {})

    def tearDown(self):
        self.vm.shutdown()
        os.remove(self.img_top)
        os.remove(self.img_base_a)
        os.remove(self.img_base_b)

    def test_commit_to_a(self):
        # Try committing to base_a (which should fail, as top's
        # backing image is base_b instead)
        result = self.vm.qmp('block-commit',
                             job_id='commit',
                             device='top',
                             base=self.img_base_a)
        self.assert_qmp(result, 'error/class', 'GenericError')

    def test_commit_to_b(self):
        # Try committing to base_b (which should work, since that is
        # actually top's backing image)
        result = self.vm.qmp('block-commit',
                             job_id='commit',
                             device='top',
                             base=self.img_base_b)
        self.assert_qmp(result, 'return', {})

        self.vm.event_wait('BLOCK_JOB_READY')
        self.vm.qmp('block-job-complete', device='commit')
        self.vm.event_wait('BLOCK_JOB_COMPLETED')

if __name__ == '__main__':
    iotests.main(supported_fmts=['qcow2', 'qed'],
                 supported_protocols=['file'])
