From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 00436C433F5 for ; Mon, 21 Feb 2022 22:43:35 +0000 (UTC) Received: from localhost ([::1]:40000 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1nMHP4-0004Pv-Tn for qemu-devel@archiver.kernel.org; Mon, 21 Feb 2022 17:43:34 -0500 Received: from eggs.gnu.org ([209.51.188.92]:46212) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMHGI-00084C-KB for qemu-devel@nongnu.org; Mon, 21 Feb 2022 17:34:30 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:24430) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1nMHGG-000891-Ex for qemu-devel@nongnu.org; Mon, 21 Feb 2022 17:34:30 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1645482867; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=gBbYUbNWW5IZZx1rnuvbPVZ5RwTIhLfYN+YIIxffZ9A=; b=ZLPY7+lb1/wgeFLk08z80f/jMnvPS/+MgrOh+rEieDODUWhPeNdjO8Oigqf4TeISeyFRqv K9YH5A/5dsr1AG5Y0qGweS3lJq1dMHI68sKIUA1GaUQ/rWE7NeC4nvap4gPiy2S/jYAMkd piuWRy5i/U57NrUCfesNf2AKf4lvsxo= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-453-nnwWZHlEMVqkejCRyiyb0A-1; Mon, 21 Feb 2022 17:34:23 -0500 X-MC-Unique: nnwWZHlEMVqkejCRyiyb0A-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 506522F4C; Mon, 21 Feb 2022 22:34:22 +0000 (UTC) Received: from scv.redhat.com (unknown [10.22.16.166]) by smtp.corp.redhat.com (Postfix) with ESMTP id 41A6A1038AAF; Mon, 21 Feb 2022 22:34:21 +0000 (UTC) From: John Snow To: qemu-devel@nongnu.org Subject: [PATCH v2 04/18] iotests: make qemu_img raise on non-zero rc by default Date: Mon, 21 Feb 2022 17:33:59 -0500 Message-Id: <20220221223413.2123003-5-jsnow@redhat.com> In-Reply-To: <20220221223413.2123003-1-jsnow@redhat.com> References: <20220221223413.2123003-1-jsnow@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=jsnow@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII" Received-SPF: pass client-ip=170.10.129.124; envelope-from=jsnow@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -28 X-Spam_score: -2.9 X-Spam_bar: -- X-Spam_report: (-2.9 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.082, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=unavailable autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Eduardo Habkost , Kevin Wolf , Thomas Huth , Beraldo Leal , qemu-block@nongnu.org, Eric Blake , Hanna Reitz , Cleber Rosa , John Snow Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" re-write qemu_img() as a function that will by default raise a VerboseProcessException (extended from CalledProcessException) on non-zero return codes. This will produce a stack trace that will show the command line arguments and return code from the failed process run. Users that want something more flexible (there appears to be only one) can use check=False and manage the return themselves. However, when the return code is negative, the Exception will be raised no matter what. This is done under the belief that there's no legitimate reason, even in negative tests, to see a crash from a tool. Signed-off-by: John Snow --- tests/qemu-iotests/257 | 8 ++++-- tests/qemu-iotests/iotests.py | 53 +++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/tests/qemu-iotests/257 b/tests/qemu-iotests/257 index fb5359c581e..e7e7a2317e3 100755 --- a/tests/qemu-iotests/257 +++ b/tests/qemu-iotests/257 @@ -241,11 +241,13 @@ def compare_images(image, reference, baseimg=None, expected_match=True): expected_ret = 0 if expected_match else 1 if baseimg: qemu_img("rebase", "-u", "-b", baseimg, '-F', iotests.imgfmt, image) - ret = qemu_img("compare", image, reference) + + sub = qemu_img("compare", image, reference, check=False) + log('qemu_img compare "{:s}" "{:s}" ==> {:s}, {:s}'.format( image, reference, - "Identical" if ret == 0 else "Mismatch", - "OK!" if ret == expected_ret else "ERROR!"), + "Identical" if sub.returncode == 0 else "Mismatch", + "OK!" if sub.returncode == expected_ret else "ERROR!"), filters=[iotests.filter_testfiles]) def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None): diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py index 5617f991da7..546e5cb671b 100644 --- a/tests/qemu-iotests/iotests.py +++ b/tests/qemu-iotests/iotests.py @@ -249,9 +249,49 @@ def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]: return qemu_tool_pipe_and_status('qemu-img', full_args, drop_successful_output=is_create) -def qemu_img(*args: str) -> int: - '''Run qemu-img and return the exit code''' - return qemu_img_pipe_and_status(*args)[1] +def qemu_img(*args: str, check: bool = True, combine_stdio: bool = True + ) -> subprocess.CompletedProcess[str]: + """ + Run qemu_img and return the status code and console output. + + This function always prepends QEMU_IMG_OPTIONS and may further alter + the args for 'create' commands. + + :param args: command-line arguments to qemu-img. + :param check: Enforce a return code of zero. + :param combine_stdio: set to False to keep stdout/stderr separated. + + :raise VerboseProcessError: + When the return code is negative, or on any non-zero exit code + when 'check=True' was provided (the default). This exception has + 'stdout', 'stderr', and 'returncode' properties that may be + inspected to show greater detail. If this exception is not + handled, the command-line, return code, and all console output + will be included at the bottom of the stack trace. + + :return: a CompletedProcess. This object has args, returncode, and + stdout properties. If streams are not combined, it will also + have a stderr property. + """ + full_args = qemu_img_args + qemu_img_create_prepare_args(list(args)) + + subp = subprocess.run( + full_args, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT if combine_stdio else subprocess.PIPE, + universal_newlines=True, + check=False + ) + + if check and subp.returncode or (subp.returncode < 0): + raise VerboseProcessError( + subp.returncode, full_args, + output=subp.stdout, + stderr=subp.stderr, + ) + + return subp + def ordered_qmp(qmsg, conv_keys=True): # Dictionaries are not ordered prior to 3.6, therefore: @@ -266,7 +306,7 @@ def ordered_qmp(qmsg, conv_keys=True): return od return qmsg -def qemu_img_create(*args): +def qemu_img_create(*args: str) -> subprocess.CompletedProcess[str]: return qemu_img('create', *args) def qemu_img_measure(*args): @@ -469,8 +509,9 @@ def qemu_nbd_popen(*args): def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt): '''Return True if two image files are identical''' - return qemu_img('compare', '-f', fmt1, - '-F', fmt2, img1, img2) == 0 + res = qemu_img('compare', '-f', fmt1, + '-F', fmt2, img1, img2, check=False) + return res.returncode == 0 def create_image(name, size): '''Create a fully-allocated raw image with sector markers''' -- 2.34.1