From nobody Sat Sep 27 19:19:59 2025 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 06BA1303C91 for ; Tue, 26 Aug 2025 09:13:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199628; cv=none; b=Kv19jxjHLX5+lHAaB5k/Qrwfx5H4ZBWqUsNhoJAOKzmp5PsjQGLKKIDFGp/B9jC5Z2nNLa4yvJeZsDz1VA7kkxyQ24wkeyiFBFRyhUfDolE44SsQzm9lqaHJVRkld2GQ1RFdRrsYpoMmrt5YIu7rkLTRx9HBfwiIW+3euYnRtT0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199628; c=relaxed/simple; bh=pD4XLTg0DldHukyFdaH/5tCPbfyEuITBPgA9nptPuIs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=iiF5SQj1HimHWjD90AZTZ/2y1G5FrabFu7rRqz8kRIqy+SRdJm8Xgs706Hb0FtAx+wlMZ1p0pIEo4wrmrieGs8NlM4rISUdyebsxiA1dMtx8b3AUWOYg5z37SNtjOKP6V5awY3ab0RbEZdtf2DeFWGUuNSXSYvIl7MtW1e1NHsg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Ewb5bsJg; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Ewb5bsJg" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-771f28ed113so1114225b3a.0 for ; Tue, 26 Aug 2025 02:13:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1756199626; x=1756804426; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Z06H7nQAXuGVWeGBmy7rHwPZSCBDj75F7L0FEZo0y1s=; b=Ewb5bsJg7v5I8LPD/DDkPTVsnY7ekoQSmDMcNoLT/xpje1tYxWf9suaDoBcQZidKJw jtYRYE4zCRQVrV3txNqzqKmSfJ4BOQX2TpEbDHukl0Rz7ZnD7Xc0/SD38Q/aElR+wE2V bE/w1aDz7f6b7Dao5CPtWTfiyF0VM/Cr2IaFAIAq9Pe7Y5iVvLglxA9yCFv66GF4CvM0 s4VDI7/cdZbdKFd8S4GuopxmC61+C4viNA+Qi3Y6fOvr/tBfyel6oYuYVKBb7VrFWjo0 6K7GnRdRagoLorV4bZtRng4tH1iGhHB1S9A+nmMltUo9jdzAwdjCVynORVwxe6IQgQIP Y85Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756199626; x=1756804426; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Z06H7nQAXuGVWeGBmy7rHwPZSCBDj75F7L0FEZo0y1s=; b=sfFQlCg+fe1tdTEu2G5wOhTIW/mhBplGVn5SFw54PrtqyJfLPKKXg+23QkKdRQpA6h UmtqSGK0Z2dHK2/EZUNVqOFVvXpaeFSvV4fMofx8GuSFX3vNN7Qd912eTU/MjyazGFk0 RBPqZCGX7FhVL7agK7/qm0xJI+kr3ITU0nqX03WksumWbIcdTu9lukE/e9wKAOOykJvM 0PGGgmRQITF4CUQFvsBMULGqobgErv8pvLiziKZeWEL6JEJ6BWk+CvrJUsHoomeJ7Cea c4rCoGNxjT2zxYaJbIXH/iUZunGUqCgGoXYHO52Wpj38Kswp19IxcwOW0qhdVVaUO0XO zosQ== X-Forwarded-Encrypted: i=1; AJvYcCXZf9QMkNGh8JPQodIgeM7lWVFDp4idd8EqP56JykFNlcMMZ52pSqIGb2o+OnZbUF20gLStWm+7nYXkWVc=@vger.kernel.org X-Gm-Message-State: AOJu0Yxkz/BVmu+LIE0fxiX0ThipCEluNPRYyEbDFuOeEq6Tp6kjdTUo XxSsbTkS39Ax0/r3wiyvIGA4A8zQqx4B9Y9kD6fAfE15IHFPGbUGTct891UsxwOCw6c8Mh0iCa0 amk82nnYFRjnxiw== X-Google-Smtp-Source: AGHT+IFv6OGkkYcCqgD5ALA5r0X9nZMsDa3qbm/600rcJO0vkLNs5ciUkvjSFY6CyLtsEnsS+a8iY6JjNwchPA== X-Received: from pfx51.prod.google.com ([2002:a05:6a00:a473:b0:771:e00d:cee]) (user=davidgow job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:4b56:b0:76e:7ae9:e869 with SMTP id d2e1a72fcca58-7702fb00068mr18610618b3a.25.1756199626242; Tue, 26 Aug 2025 02:13:46 -0700 (PDT) Date: Tue, 26 Aug 2025 17:13:31 +0800 In-Reply-To: <20250826091341.1427123-1-davidgow@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250826091341.1427123-1-davidgow@google.com> X-Mailer: git-send-email 2.51.0.261.g7ce5a0a67e-goog Message-ID: <20250826091341.1427123-2-davidgow@google.com> Subject: [PATCH v4 1/7] kunit: Add parent kunit for parameterized test context From: David Gow To: Marie Zhussupova , marievictoria875@gmail.com, rmoar@google.com, shuah@kernel.org, brendan.higgins@linux.dev Cc: mark.rutland@arm.com, elver@google.com, dvyukov@google.com, lucas.demarchi@intel.com, thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, kasan-dev@googlegroups.com, intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Stephen Rothwell , David Gow Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marie Zhussupova Currently, KUnit parameterized tests lack a mechanism to share resources across parameter runs because the same `struct kunit` instance is cleaned up and reused for each run. This patch introduces parameterized test context, enabling test users to share resources between parameter runs. It also allows setting up resources that need to be available for all parameter runs only once, which is helpful in cases where setup is expensive. To establish a parameterized test context, this patch adds a parent pointer field to `struct kunit`. This allows resources added to the parent `struct kunit` to be shared and accessible across all parameter runs. In kunit_run_tests(), the default `struct kunit` created is now designated to act as the parameterized test context whenever a test is parameterized. Subsequently, a new `struct kunit` is made for each parameter run, and its parent pointer is set to the `struct kunit` that holds the parameterized test context. Reviewed-by: David Gow Reviewed-by: Rae Moar Signed-off-by: Marie Zhussupova Signed-off-by: David Gow Acked-by: Mark Rutland --- No changes in v4: v3: https://lore.kernel.org/linux-kselftest/20250815103604.3857930-2-mariev= ic@google.com/ Changes in v3: v2: https://lore.kernel.org/all/20250811221739.2694336-2-marievic@google.co= m/ - Commit message formatting. Changes in v2: v1: https://lore.kernel.org/all/20250729193647.3410634-2-marievic@google.co= m/ - Descriptions of the parent pointer in `struct kunit` were changed to be more general, as it could be used to share resources not only between parameter runs but also between test cases in the future. - When printing parameter descriptions using test.param_index was changed to param_test.param_index. - kunit_cleanup(&test) in kunit_run_tests() was moved inside the parameterized test check. - The comments and the commit message were changed to reflect the parameterized testing terminology. See the patch series cover letter change log for the definitions. --- include/kunit/test.h | 8 ++++++-- lib/kunit/test.c | 34 ++++++++++++++++++++-------------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/include/kunit/test.h b/include/kunit/test.h index d958ee53050e..9766403afd56 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -268,14 +268,18 @@ struct kunit_suite_set { * * @priv: for user to store arbitrary data. Commonly used to pass data * created in the init function (see &struct kunit_suite). + * @parent: reference to the parent context of type struct kunit that can + * be used for storing shared resources. * * Used to store information about the current context under which the test * is running. Most of this data is private and should only be accessed - * indirectly via public functions; the one exception is @priv which can be - * used by the test writer to store arbitrary data. + * indirectly via public functions; the two exceptions are @priv and @pare= nt + * which can be used by the test writer to store arbitrary data and access= the + * parent context, respectively. */ struct kunit { void *priv; + struct kunit *parent; =20 /* private: internal use only. */ const char *name; /* Read only after initialization! */ diff --git a/lib/kunit/test.c b/lib/kunit/test.c index d2bfa331a2b1..587b5c51db58 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -647,6 +647,7 @@ int kunit_run_tests(struct kunit_suite *suite) struct kunit_case *test_case; struct kunit_result_stats suite_stats =3D { 0 }; struct kunit_result_stats total_stats =3D { 0 }; + const void *curr_param; =20 /* Taint the kernel so we know we've run tests. */ add_taint(TAINT_TEST, LOCKDEP_STILL_OK); @@ -679,37 +680,42 @@ int kunit_run_tests(struct kunit_suite *suite) } else { /* Get initial param. */ param_desc[0] =3D '\0'; - test.param_value =3D test_case->generate_params(NULL, param_desc); + /* TODO: Make generate_params try-catch */ + curr_param =3D test_case->generate_params(NULL, param_desc); test_case->status =3D KUNIT_SKIPPED; kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT "KTAP version 1\n"); kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT "# Subtest: %s", test_case->name); =20 - while (test.param_value) { - kunit_run_case_catch_errors(suite, test_case, &test); + while (curr_param) { + struct kunit param_test =3D { + .param_value =3D curr_param, + .param_index =3D ++test.param_index, + .parent =3D &test, + }; + kunit_init_test(¶m_test, test_case->name, test_case->log); + kunit_run_case_catch_errors(suite, test_case, ¶m_test); =20 if (param_desc[0] =3D=3D '\0') { snprintf(param_desc, sizeof(param_desc), - "param-%d", test.param_index); + "param-%d", param_test.param_index); } =20 - kunit_print_ok_not_ok(&test, KUNIT_LEVEL_CASE_PARAM, - test.status, - test.param_index + 1, + kunit_print_ok_not_ok(¶m_test, KUNIT_LEVEL_CASE_PARAM, + param_test.status, + param_test.param_index, param_desc, - test.status_comment); + param_test.status_comment); =20 - kunit_update_stats(¶m_stats, test.status); + kunit_update_stats(¶m_stats, param_test.status); =20 /* Get next param. */ param_desc[0] =3D '\0'; - test.param_value =3D test_case->generate_params(test.param_value, para= m_desc); - test.param_index++; - test.status =3D KUNIT_SUCCESS; - test.status_comment[0] =3D '\0'; - test.priv =3D NULL; + curr_param =3D test_case->generate_params(curr_param, param_desc); } + /* TODO: Put this kunit_cleanup into a try-catch. */ + kunit_cleanup(&test); } =20 kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE); --=20 2.51.0.261.g7ce5a0a67e-goog From nobody Sat Sep 27 19:19:59 2025 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 975092FC01D for ; Tue, 26 Aug 2025 09:13:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199630; cv=none; b=tG0PY05Ua16nEndfx8CHFUQF6MMEAQUSUtRwktcmrkiZhR9GqpU87sDTcWvD8QJl3qAqEgU3Dg22RQsRSuKZdiy6ZyFIvyVw1ROK+U4nyzlpHlzm2n5RPD5EX1/D2dq7LSCscKL2msl3KYBxZ0Pj3s3/8Ag/fL9HYhDj4N1ViHA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199630; c=relaxed/simple; bh=wGgvEBopG7WMewdUpXEs8e+lMZNdr6DC+bP2gJlld6w=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=lHEo992c+KZUHpwNkssG1gVsppXX6658KIoUJ6n/g+9IisbkHTLPNQ+WaqpQZc9Pnduwlgeradn/lqU63Lem5c4NwTQ4N4fJSJ/B9K4dUoZQ3+9ONLAvZzkwlhrC/lS4/no/yDJ+t6WiJd0wnU6QKx+0yCWwGuMwRLhOREN0IXM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=OvbFbj+z; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="OvbFbj+z" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-2464dc09769so85481905ad.0 for ; Tue, 26 Aug 2025 02:13:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1756199628; x=1756804428; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=QTTACq/njMLngdxpMSOXC5XIjUnoWbM4E4SA6Lndzr0=; b=OvbFbj+zYqST0wa9T53VqJvgBIirWqEkKjOmwiZpnAGF1tO7x5LBaiqqlTXy+PvsuY D8MTBuQTU8lt9Bg0neE5hOABU4AkiFSITYKTxGPBX+mDxrTZhJBknkHdP9z951w8j36G dokN6DaNuASgDN2Q06jJBoOwx9m+RL8MEcGDl3kvNlLuDDNpOwbO9Y85K2hCAiwgabck J8e/hk0cmPd54mEPvJNhnk3n9Fz3nNIMuCSrXPqGqxh8kEVg/rSzudl+clQRKMjVAuU/ RZS2XMaL2chvCElqY86lHY3tc6YhBEyZDgEVCRp+6nrLznKu7FuNSWBpUA5yDVAxiyBW PQyQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756199628; x=1756804428; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=QTTACq/njMLngdxpMSOXC5XIjUnoWbM4E4SA6Lndzr0=; b=FqNi/fF/TKijaGMqA8aDk2N9HufJ3YG9UhxNIUmOmvXrrTQ2/isO2rCW3xkyvgy939 AAyQz3Mswp/vbbd5dKBBEwtfeFcgdI3iZPGlWELs3pGdMpSxpy6HLgqLMFgZKeZeJsol Dai29Lqv0XzijD5wKhhzlq5RGCs05bsBED9J+ipe0R8xCoDtdYbQ2IHjKRZxo+/x+yfz vDgikT2XDmwRsLXBAlFsCheJZDyvwC4cXizR4VWdXMbYiuqCLiUQnsJ4ppFIFE5gKrE+ 1CrMvfowDnkelwKIAd9mKWsoVVs+sGdeaeljNUO+J/ofSrzsYfJ9kmngHp/Fm7y2eD73 qGqA== X-Forwarded-Encrypted: i=1; AJvYcCXm45HBehnmB3CBG/82P6ArapYk3I7nvnUQJaN7VOzA8J2otKLJrIXwnG1w2dNMMnybY1am4Q/n5/QcycM=@vger.kernel.org X-Gm-Message-State: AOJu0Yymvv5eTKCKYaOCCiX7Dz+gYuvslPHCi0yiYVJ07Wl1Xr2AJScb Caaxdr1ehJ6/VYt5IrjMIzg2QEbwikF8BbmQyGNf0EFup3nsL5HN1s4WBTVbgG/NHI6LjzRrQAG 2eTvtP/06cpz71Q== X-Google-Smtp-Source: AGHT+IE+/6MMrkJ74E5uKO4Fuz0dZBNo3Mw+DWRHhhpD3bwunApBgF7++zob2WkBdMyiTfsv7vnhKVDOwX2G5Q== X-Received: from plpj12.prod.google.com ([2002:a17:903:3d8c:b0:246:1edd:3919]) (user=davidgow job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:ccc4:b0:248:79d4:939e with SMTP id d9443c01a7336-24879d49812mr6538095ad.39.1756199627892; Tue, 26 Aug 2025 02:13:47 -0700 (PDT) Date: Tue, 26 Aug 2025 17:13:32 +0800 In-Reply-To: <20250826091341.1427123-1-davidgow@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250826091341.1427123-1-davidgow@google.com> X-Mailer: git-send-email 2.51.0.261.g7ce5a0a67e-goog Message-ID: <20250826091341.1427123-3-davidgow@google.com> Subject: [PATCH v4 2/7] kunit: Introduce param_init/exit for parameterized test context management From: David Gow To: Marie Zhussupova , marievictoria875@gmail.com, rmoar@google.com, shuah@kernel.org, brendan.higgins@linux.dev Cc: mark.rutland@arm.com, elver@google.com, dvyukov@google.com, lucas.demarchi@intel.com, thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, kasan-dev@googlegroups.com, intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Stephen Rothwell , David Gow Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marie Zhussupova Add (*param_init) and (*param_exit) function pointers to `struct kunit_case`. Users will be able to set them via the new KUNIT_CASE_PARAM_WITH_INIT() macro. param_init/exit will be invoked by kunit_run_tests() once before and once after the parameterized test, respectively. They will receive the `struct kunit` that holds the parameterized test context; facilitating init and exit for shared state. This patch also sets param_init/exit to None in rust/kernel/kunit.rs. Reviewed-by: Rae Moar Reviewed-by: David Gow Signed-off-by: Marie Zhussupova Signed-off-by: David Gow Acked-by: Mark Rutland --- No changes in v4: v3: https://lore.kernel.org/linux-kselftest/20250815103604.3857930-3-mariev= ic@google.com/ Changes in v3: v2: https://lore.kernel.org/all/20250811221739.2694336-3-marievic@google.co= m/ - kunit_init_parent_param_test() now sets both the `struct kunit_case` and the `struct kunit` statuses as failed if the parameterized test init failed. The failure message was also changed to include the failure code, mirroring the kunit_suite init failure message. - A check for parameter init failure was added in kunit_run_tests(). So, if the init failed, the framework will skip the parameter runs and update the param_test statistics to count that failure. - Commit message formatting. Changes in v2: v1: https://lore.kernel.org/all/20250729193647.3410634-3-marievic@google.co= m/ - param init/exit were set to None in rust/kernel/kunit.rs to fix the Rust breakage. - The name of __kunit_init_parent_test was changed to kunit_init_parent_param_test and its call was changed to happen only if the test is parameterized. - The param_exit call was also moved inside the check for if the test is parameterized. - KUNIT_CASE_PARAM_WITH_INIT() macro logic was change to not automatically set generate_params() to KUnit's built-in generator function. Instead, the test user will be asked to provide it themselves. - The comments and the commit message were changed to reflect the parameterized testing terminology. See the patch series cover letter change log for the definitions. --- include/kunit/test.h | 25 +++++++++++++++++++++++++ lib/kunit/test.c | 27 ++++++++++++++++++++++++++- rust/kernel/kunit.rs | 4 ++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/include/kunit/test.h b/include/kunit/test.h index 9766403afd56..fc8fd55b2dfb 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -92,6 +92,8 @@ struct kunit_attributes { * @name: the name of the test case. * @generate_params: the generator function for parameterized tests. * @attr: the attributes associated with the test + * @param_init: The init function to run before a parameterized test. + * @param_exit: The exit function to run after a parameterized test. * * A test case is a function with the signature, * ``void (*)(struct kunit *)`` @@ -128,6 +130,8 @@ struct kunit_case { const char *name; const void* (*generate_params)(const void *prev, char *desc); struct kunit_attributes attr; + int (*param_init)(struct kunit *test); + void (*param_exit)(struct kunit *test); =20 /* private: internal use only. */ enum kunit_status status; @@ -218,6 +222,27 @@ static inline char *kunit_status_to_ok_not_ok(enum kun= it_status status) .generate_params =3D gen_params, \ .attr =3D attributes, .module_name =3D KBUILD_MODNAME} =20 +/** + * KUNIT_CASE_PARAM_WITH_INIT - Define a parameterized KUnit test case wit= h custom + * param_init() and param_exit() functions. + * @test_name: The function implementing the test case. + * @gen_params: The function to generate parameters for the test case. + * @init: A reference to the param_init() function to run before a paramet= erized test. + * @exit: A reference to the param_exit() function to run after a paramete= rized test. + * + * Provides the option to register param_init() and param_exit() functions. + * param_init/exit will be passed the parameterized test context and run o= nce + * before and once after the parameterized test. The init function can be = used + * to add resources to share between parameter runs, and any other setup l= ogic. + * The exit function can be used to clean up resources that were not manag= ed by + * the parameterized test, and any other teardown logic. + */ +#define KUNIT_CASE_PARAM_WITH_INIT(test_name, gen_params, init, exit) \ + { .run_case =3D test_name, .name =3D #test_name, \ + .generate_params =3D gen_params, \ + .param_init =3D init, .param_exit =3D exit, \ + .module_name =3D KBUILD_MODNAME} + /** * struct kunit_suite - describes a related collection of &struct kunit_ca= se * diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 587b5c51db58..0fe61dec5a96 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -641,6 +641,20 @@ static void kunit_accumulate_stats(struct kunit_result= _stats *total, total->total +=3D add.total; } =20 +static void kunit_init_parent_param_test(struct kunit_case *test_case, str= uct kunit *test) +{ + if (test_case->param_init) { + int err =3D test_case->param_init(test); + + if (err) { + kunit_err(test_case, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT + "# failed to initialize parent parameter test (%d)", err); + test->status =3D KUNIT_FAILURE; + test_case->status =3D KUNIT_FAILURE; + } + } +} + int kunit_run_tests(struct kunit_suite *suite) { char param_desc[KUNIT_PARAM_DESC_SIZE]; @@ -678,6 +692,11 @@ int kunit_run_tests(struct kunit_suite *suite) kunit_run_case_catch_errors(suite, test_case, &test); kunit_update_stats(¶m_stats, test.status); } else { + kunit_init_parent_param_test(test_case, &test); + if (test_case->status =3D=3D KUNIT_FAILURE) { + kunit_update_stats(¶m_stats, test.status); + goto test_case_end; + } /* Get initial param. */ param_desc[0] =3D '\0'; /* TODO: Make generate_params try-catch */ @@ -714,10 +733,16 @@ int kunit_run_tests(struct kunit_suite *suite) param_desc[0] =3D '\0'; curr_param =3D test_case->generate_params(curr_param, param_desc); } + /* + * TODO: Put into a try catch. Since we don't need suite->exit + * for it we can't reuse kunit_try_run_cleanup for this yet. + */ + if (test_case->param_exit) + test_case->param_exit(&test); /* TODO: Put this kunit_cleanup into a try-catch. */ kunit_cleanup(&test); } - +test_case_end: kunit_print_attr((void *)test_case, true, KUNIT_LEVEL_CASE); =20 kunit_print_test_stats(&test, param_stats); diff --git a/rust/kernel/kunit.rs b/rust/kernel/kunit.rs index 41efd87595d6..b1c97f8029c7 100644 --- a/rust/kernel/kunit.rs +++ b/rust/kernel/kunit.rs @@ -210,6 +210,8 @@ pub const fn kunit_case( status: kernel::bindings::kunit_status_KUNIT_SUCCESS, module_name: core::ptr::null_mut(), log: core::ptr::null_mut(), + param_init: None, + param_exit: None, } } =20 @@ -229,6 +231,8 @@ pub const fn kunit_case_null() -> kernel::bindings::kun= it_case { status: kernel::bindings::kunit_status_KUNIT_SUCCESS, module_name: core::ptr::null_mut(), log: core::ptr::null_mut(), + param_init: None, + param_exit: None, } } =20 --=20 2.51.0.261.g7ce5a0a67e-goog From nobody Sat Sep 27 19:19:59 2025 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 332613093A5 for ; Tue, 26 Aug 2025 09:13:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199632; cv=none; b=roiXH+3ToCzONXg04F8rx430C7iXCHN8hY3YZU0u4DeKZKcDc5vv5PFMHoIZ7sM+FqoLHBQt5BIvvyG2OBG8pFdxVzUE9rSH6g7qO/bEDf5jj+BnAzud1F1eThxkiTwPcIahH4aZPIGLxcrF5cKYkvEDVfMLRgyuPVZsQ0+5XR0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199632; c=relaxed/simple; bh=riDptoiHOYi3XRCYC5H+gPi3YBs3p0cVYPBHp6fHT4A=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=qvxerfoRol7FManaM2y0b9+n4Qy9CpbT5e+Bp1nWL3RWtzOzSLfIDqeq/eJMzjaeS8AAdieqyL68HwIWfQwRccYwN5c0Hfy68yfkw8n5xZr0xIT9pFQzcXIs3SzaujZ3r0PaWPT9V46TE2PaJmhzG9J+IT/9UjEjwiM7lpDlPvc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=PfyA6XUh; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="PfyA6XUh" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-771e2f5b5dcso2861825b3a.0 for ; Tue, 26 Aug 2025 02:13:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1756199629; x=1756804429; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=wOxgoJJJ8SZ3HeZjErz3bRaIvB/ECPnvmYM5E2IyxbQ=; b=PfyA6XUhDi50znW/4VwwIMagKB70QBPnJKilYqJcM6DGemkZpod6E+E0wp5GBqDo/i kAJOKmQxZfAMDNjGd+1uBUH0OkBye2yu4VAFQrDPJdK+Erphk4A7GTKDoYCNsIoniCVX sw/sr0Y08thw6bsCmSb+lrdFsUkm4CZmbfHb2TPHtn6S9lSrJFdgaibiCXMkQO4OTWHd +fSlMbRs79SE6KYxW4lOD3hC1o3EBFaKMavYwNwKDkinotLxwyf+cAyxvDuvCVVpqIRq OvC0dOfsuDdOUENarVIeX0S9yKYm5XwSv3PgTNF9j+3s0F30pfo7TS4BJ0rwd42l9dm+ P7qQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756199629; x=1756804429; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=wOxgoJJJ8SZ3HeZjErz3bRaIvB/ECPnvmYM5E2IyxbQ=; b=OzWGGOOmqB5BJn9Mkq3bIgSmSVJU0BE/2tXogLNJGBrFi/Ff5tbvDkYZOkZat8l+vl iGyhtEx3eVlwkF16YmGcegf4+WLVQyrZg74TA5ShXUzFTtKCQr1lfyPc9zCp0vHXMVOJ ZeJbGjA7v62TmhndWHFoeHHap4xA1Bmgi1tLycl9iXvxEJqS1wFzMfj/wcXkAieOfBKR ObgjN/K7GOIcE/lVlYZ/1kjcYDB1ThcXeg3kEbyg2AxPZ9aR9b4Ti09yx9DColjoQTzl Q2XUrIlYh8ZpBI+CuyIth5qiur+MQ0wQuMjBvwVB32j4pSkAezpMbWb8SBRClc9Q3miV 2k4A== X-Forwarded-Encrypted: i=1; AJvYcCVER23GMTY5E7+NkDuUhR+IPLApO6ZwgWntOrzjMEA8yLyTWzCpElRxbv6xREcW2o7+8FFb1/F0h6Rp8/4=@vger.kernel.org X-Gm-Message-State: AOJu0YwU9+7R394LKEuS12WwiyzI7nmXFNuqiP/BVnLPn6qCewkhy8V9 OwQxyJlWx749bAa/SYMxKTJJxGrD92eKN3674bdW8M26tVLBxQBGDE7JHHLOT16+H+TQGEoNSXn Afju5uLqKBwRbGA== X-Google-Smtp-Source: AGHT+IHgOfXfiRixc9DNGQsel6kZ84cURw6Em9ox/O6G5u8K+rIPYnapy1P78kwhi3bDoiirsFCy+wrz1erCSg== X-Received: from pfbkw7.prod.google.com ([2002:a05:6a00:94f7:b0:74b:41c0:e916]) (user=davidgow job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:14c4:b0:771:fbb0:b1ce with SMTP id d2e1a72fcca58-771fbb0b3dfmr1136261b3a.25.1756199629409; Tue, 26 Aug 2025 02:13:49 -0700 (PDT) Date: Tue, 26 Aug 2025 17:13:33 +0800 In-Reply-To: <20250826091341.1427123-1-davidgow@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250826091341.1427123-1-davidgow@google.com> X-Mailer: git-send-email 2.51.0.261.g7ce5a0a67e-goog Message-ID: <20250826091341.1427123-4-davidgow@google.com> Subject: [PATCH v4 3/7] kunit: Pass parameterized test context to generate_params() From: David Gow To: Marie Zhussupova , marievictoria875@gmail.com, rmoar@google.com, shuah@kernel.org, brendan.higgins@linux.dev Cc: mark.rutland@arm.com, elver@google.com, dvyukov@google.com, lucas.demarchi@intel.com, thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, kasan-dev@googlegroups.com, intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Stephen Rothwell , David Gow Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marie Zhussupova To enable more complex parameterized testing scenarios, the generate_params() function needs additional context beyond just the previously generated parameter. This patch modifies the generate_params() function signature to include an extra `struct kunit *test` argument, giving test users access to the parameterized test context when generating parameters. The `struct kunit *test` argument was added as the first parameter to the function signature as it aligns with the convention of other KUnit functions that accept `struct kunit *test` first. This also mirrors the "this" or "self" reference found in object-oriented programming languages. This patch also modifies xe_pci_live_device_gen_param() in xe_pci.c and nthreads_gen_params() in kcsan_test.c to reflect this signature change. Reviewed-by: David Gow Reviewed-by: Rae Moar Acked-by: Marco Elver Acked-by: Rodrigo Vivi Signed-off-by: Marie Zhussupova [Catch some additional gen_params signatures in drm/xe/tests --David] Signed-off-by: David Gow Acked-by: Mark Rutland --- Changes in v4: v3: https://lore.kernel.org/linux-kselftest/20250815103604.3857930-4-mariev= ic@google.com/ - Fixup some additional generate_params signature changes in xe_pci. - These are also available as a separate patch here: https://lore.kernel.org/linux-kselftest/20250821135447.1618942-1-davidgow= @google.com/ Changes in v3: v2: https://lore.kernel.org/all/20250811221739.2694336-4-marievic@google.co= m/ - Commit message formatting. Changes in v2: v1: https://lore.kernel.org/all/20250729193647.3410634-4-marievic@google.co= m/ https://lore.kernel.org/all/20250729193647.3410634-5-marievic@google.co= m/ https://lore.kernel.org/all/20250729193647.3410634-6-marievic@google.co= m/ - generate_params signature changes in xe_pci.c and kcsan_test.c were squashed into a single patch to avoid in-between breakages in the series. - The comments and the commit message were changed to reflect the parameterized testing terminology. See the patch series cover letter change log for the definitions. --- drivers/gpu/drm/xe/tests/xe_pci.c | 14 +++++++------- drivers/gpu/drm/xe/tests/xe_pci_test.h | 9 +++++---- include/kunit/test.h | 9 ++++++--- kernel/kcsan/kcsan_test.c | 2 +- lib/kunit/test.c | 5 +++-- 5 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_pci.c b/drivers/gpu/drm/xe/tests/x= e_pci.c index 9c715e59f030..f707e0a54295 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci.c +++ b/drivers/gpu/drm/xe/tests/xe_pci.c @@ -44,9 +44,9 @@ KUNIT_ARRAY_PARAM(pci_id, pciidlist, xe_pci_id_kunit_desc= ); * * Return: pointer to the next parameter or NULL if no more parameters */ -const void *xe_pci_graphics_ip_gen_param(const void *prev, char *desc) +const void *xe_pci_graphics_ip_gen_param(struct kunit *test, const void *p= rev, char *desc) { - return graphics_ip_gen_params(prev, desc); + return graphics_ip_gen_params(test, prev, desc); } EXPORT_SYMBOL_IF_KUNIT(xe_pci_graphics_ip_gen_param); =20 @@ -61,9 +61,9 @@ EXPORT_SYMBOL_IF_KUNIT(xe_pci_graphics_ip_gen_param); * * Return: pointer to the next parameter or NULL if no more parameters */ -const void *xe_pci_media_ip_gen_param(const void *prev, char *desc) +const void *xe_pci_media_ip_gen_param(struct kunit *test, const void *prev= , char *desc) { - return media_ip_gen_params(prev, desc); + return media_ip_gen_params(test, prev, desc); } EXPORT_SYMBOL_IF_KUNIT(xe_pci_media_ip_gen_param); =20 @@ -78,9 +78,9 @@ EXPORT_SYMBOL_IF_KUNIT(xe_pci_media_ip_gen_param); * * Return: pointer to the next parameter or NULL if no more parameters */ -const void *xe_pci_id_gen_param(const void *prev, char *desc) +const void *xe_pci_id_gen_param(struct kunit *test, const void *prev, char= *desc) { - const struct pci_device_id *pci =3D pci_id_gen_params(prev, desc); + const struct pci_device_id *pci =3D pci_id_gen_params(test, prev, desc); =20 return pci->driver_data ? pci : NULL; } @@ -159,7 +159,7 @@ EXPORT_SYMBOL_IF_KUNIT(xe_pci_fake_device_init); * Return: pointer to the next &struct xe_device ready to be used as a par= ameter * or NULL if there are no more Xe devices on the system. */ -const void *xe_pci_live_device_gen_param(const void *prev, char *desc) +const void *xe_pci_live_device_gen_param(struct kunit *test, const void *p= rev, char *desc) { const struct xe_device *xe =3D prev; struct device *dev =3D xe ? xe->drm.dev : NULL; diff --git a/drivers/gpu/drm/xe/tests/xe_pci_test.h b/drivers/gpu/drm/xe/te= sts/xe_pci_test.h index ce4d2b86b778..6d8bc56f7bde 100644 --- a/drivers/gpu/drm/xe/tests/xe_pci_test.h +++ b/drivers/gpu/drm/xe/tests/xe_pci_test.h @@ -7,6 +7,7 @@ #define _XE_PCI_TEST_H_ =20 #include +#include =20 #include "xe_platform_types.h" #include "xe_sriov_types.h" @@ -25,9 +26,9 @@ struct xe_pci_fake_data { =20 int xe_pci_fake_device_init(struct xe_device *xe); =20 -const void *xe_pci_graphics_ip_gen_param(const void *prev, char *desc); -const void *xe_pci_media_ip_gen_param(const void *prev, char *desc); -const void *xe_pci_id_gen_param(const void *prev, char *desc); -const void *xe_pci_live_device_gen_param(const void *prev, char *desc); +const void *xe_pci_graphics_ip_gen_param(struct kunit *test, const void *p= rev, char *desc); +const void *xe_pci_media_ip_gen_param(struct kunit *test, const void *prev= , char *desc); +const void *xe_pci_id_gen_param(struct kunit *test, const void *prev, char= *desc); +const void *xe_pci_live_device_gen_param(struct kunit *test, const void *p= rev, char *desc); =20 #endif diff --git a/include/kunit/test.h b/include/kunit/test.h index fc8fd55b2dfb..8eba1b03c3e3 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -128,7 +128,8 @@ struct kunit_attributes { struct kunit_case { void (*run_case)(struct kunit *test); const char *name; - const void* (*generate_params)(const void *prev, char *desc); + const void* (*generate_params)(struct kunit *test, + const void *prev, char *desc); struct kunit_attributes attr; int (*param_init)(struct kunit *test); void (*param_exit)(struct kunit *test); @@ -1703,7 +1704,8 @@ do { \ * Define function @name_gen_params which uses @array to generate paramete= rs. */ #define KUNIT_ARRAY_PARAM(name, array, get_desc) \ - static const void *name##_gen_params(const void *prev, char *desc) \ + static const void *name##_gen_params(struct kunit *test, \ + const void *prev, char *desc) \ { \ typeof((array)[0]) *__next =3D prev ? ((typeof(__next)) prev) + 1 : (arr= ay); \ if (__next - (array) < ARRAY_SIZE((array))) { \ @@ -1724,7 +1726,8 @@ do { \ * Define function @name_gen_params which uses @array to generate paramete= rs. */ #define KUNIT_ARRAY_PARAM_DESC(name, array, desc_member) \ - static const void *name##_gen_params(const void *prev, char *desc) \ + static const void *name##_gen_params(struct kunit *test, \ + const void *prev, char *desc) \ { \ typeof((array)[0]) *__next =3D prev ? ((typeof(__next)) prev) + 1 : (arr= ay); \ if (__next - (array) < ARRAY_SIZE((array))) { \ diff --git a/kernel/kcsan/kcsan_test.c b/kernel/kcsan/kcsan_test.c index 49ab81faaed9..a13a090bb2a7 100644 --- a/kernel/kcsan/kcsan_test.c +++ b/kernel/kcsan/kcsan_test.c @@ -1383,7 +1383,7 @@ static void test_atomic_builtins_missing_barrier(stru= ct kunit *test) * The thread counts are chosen to cover potentially interesting boundarie= s and * corner cases (2 to 5), and then stress the system with larger counts. */ -static const void *nthreads_gen_params(const void *prev, char *desc) +static const void *nthreads_gen_params(struct kunit *test, const void *pre= v, char *desc) { long nthreads =3D (long)prev; =20 diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 0fe61dec5a96..50705248abad 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -700,7 +700,7 @@ int kunit_run_tests(struct kunit_suite *suite) /* Get initial param. */ param_desc[0] =3D '\0'; /* TODO: Make generate_params try-catch */ - curr_param =3D test_case->generate_params(NULL, param_desc); + curr_param =3D test_case->generate_params(&test, NULL, param_desc); test_case->status =3D KUNIT_SKIPPED; kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT "KTAP version 1\n"); @@ -731,7 +731,8 @@ int kunit_run_tests(struct kunit_suite *suite) =20 /* Get next param. */ param_desc[0] =3D '\0'; - curr_param =3D test_case->generate_params(curr_param, param_desc); + curr_param =3D test_case->generate_params(&test, curr_param, + param_desc); } /* * TODO: Put into a try catch. Since we don't need suite->exit --=20 2.51.0.261.g7ce5a0a67e-goog From nobody Sat Sep 27 19:19:59 2025 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CCCA6309DCC for ; Tue, 26 Aug 2025 09:13:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199634; cv=none; b=AKY5TznlP687d5j0Sbv5LmTm+fwzDWMVyD6SFL/ikX2ZBxu5vLogVtQhsN5SFP6jwBGe/iGAeGFpnggj4FrAFP3Ocn3ZxCwAyWpuaptYR4Vytmbx+G4dRvUgCouIGhSNN2Ykm5F+LNbv9KlVxXaRyDWBATbPS9W+5hALdB1XBpA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199634; c=relaxed/simple; bh=vrAePBQl8uieLDDSjn/Panhaawxs13plOWDfDRbgVMU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=dvQiKXkZrCh4MgspLA2ghHahO20EeZ3DHvwXwZvxLIp54isCLB80Zh1SvYM5u3MY7CJ3OG1kBxpNpnB+A2/wB0rHpMzq6Hbnr0q0AwiVcp/8cr92SP9+qQVyEpH3FZNrd/NB8n2iFZsoxa0sFmoxgHBlewLtBPXio4gSV/1v+Y4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Eo9Iz+Jf; arc=none smtp.client-ip=209.85.210.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Eo9Iz+Jf" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-76e55665b05so4641276b3a.2 for ; Tue, 26 Aug 2025 02:13:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1756199631; x=1756804431; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=SS4RWWsYR8rt67WX12qateLzVdeeE0BdCVVhb7GW4rE=; b=Eo9Iz+Jf8EkOZrriDj5VsOXPd1jZ+l7AtJdXfaO6T6M4jK7W4/l5QW2CBCnCZsOpWC 8MJ7U3E8p6loUT+Y4mIW6mzYafhlw9yWozxV4lH1ibNhmCj4cM+grz36WCnVffCgTu6X HD+59TTl2S3nRoNd2qyABTdDCb8ayds0ctrc3aKCZZdf5vUd648GGnnkvc+LijoNDZSy +nJxgcm1IliAjqR70nyyqOo6usTqAwrJbw4fsbJVKUoBDSQrpDYg+VzXkfviUniNMYtL j6cerMjuaBqm2FhSE21HQrTULvz/uj3X1voGxCItrbPf+7sNXf/HfB8dfFRKPZ5Fjs5G dyoQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756199631; x=1756804431; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=SS4RWWsYR8rt67WX12qateLzVdeeE0BdCVVhb7GW4rE=; b=q3Bh16siXMCYvlU+KqCB+nd1zvhAKRbZngwOux8ehPjBnXIxYoZ255TEjEoH+cFRkm 6IyMNexmLz7DpVUf1MuXOg5LVsS+ve+NT7JCGpy7xEwQNLoqKLvL8DMDQrajYffHaGR/ 0gZZea2OHK9C0AOqJyHsBbn+7LF97exjUR6dAshaL2DBzYMr0xR6m/kWgcg6B6KW1Na6 3PjDWVi2vQUPWBeTho80+iP5gnLvoD43A/gYUitzw143jZ8y07XUUgXqJGtc4d1SeERI VnhZ/p5Dic8qvAQuFdmuzDp6FSM2vkPbjqxx641ARDWXEQEqHXkNfA54iD4Sg2parR3B sdlw== X-Forwarded-Encrypted: i=1; AJvYcCULKID/POdQ9JbuBHszfkGxX8Yj83E9gd6ZJzoDfFqz6azzjwgE81yMlKFoEZtkgQfJvMU801miiJ4tjAs=@vger.kernel.org X-Gm-Message-State: AOJu0YxpIbq/48JUctOKbb9YE7kfl4l3hpmtKBkYvJHoXNNhtCyaBZxw GKp5w1pN1NFhfYujxahTCUAYFL0IsXY6HVfumBUZE7l9C4m+XtYrEKhpM5vdWEuW3At4K7d3+Tx woHagBH3iB1lSxw== X-Google-Smtp-Source: AGHT+IEJ8SqLbXF/ST99SjsSnhPT3Oom4CqszB9KFVxbzLAYGGTQUnByacCzje67CXDYtFH0Xt8e2NrGNQS4lA== X-Received: from pfz14.prod.google.com ([2002:a05:6a00:bb8e:b0:748:e22c:600c]) (user=davidgow job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:3c91:b0:771:ebf1:5e4b with SMTP id d2e1a72fcca58-771ebf16677mr4678781b3a.26.1756199630989; Tue, 26 Aug 2025 02:13:50 -0700 (PDT) Date: Tue, 26 Aug 2025 17:13:34 +0800 In-Reply-To: <20250826091341.1427123-1-davidgow@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250826091341.1427123-1-davidgow@google.com> X-Mailer: git-send-email 2.51.0.261.g7ce5a0a67e-goog Message-ID: <20250826091341.1427123-5-davidgow@google.com> Subject: [PATCH v4 4/7] kunit: Enable direct registration of parameter arrays to a KUnit test From: David Gow To: Marie Zhussupova , marievictoria875@gmail.com, rmoar@google.com, shuah@kernel.org, brendan.higgins@linux.dev Cc: mark.rutland@arm.com, elver@google.com, dvyukov@google.com, lucas.demarchi@intel.com, thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, kasan-dev@googlegroups.com, intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Stephen Rothwell , David Gow Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marie Zhussupova KUnit parameterized tests currently support two primary methods f or getting parameters: 1. Defining custom logic within a generate_params() function. 2. Using the KUNIT_ARRAY_PARAM() and KUNIT_ARRAY_PARAM_DESC() macros with a pre-defined static array and passing the created *_gen_params() to KUNIT_CASE_PARAM(). These methods present limitations when dealing with dynamically generated parameter arrays, or in scenarios where populating parameters sequentially via generate_params() is inefficient or overly complex. This patch addresses these limitations by adding a new `params_array` field to `struct kunit`, of the type `kunit_params`. The `struct kunit_params` is designed to store the parameter array itself, along with essential metadata including the parameter count, parameter size, and a get_description() function for providing custom descriptions for individual parameters. The `params_array` field can be populated by calling the new kunit_register_params_array() macro from within a param_init() function. This will register the array as part of the parameterized test context. The user will then need to pass kunit_array_gen_params() to the KUNIT_CASE_PARAM_WITH_INIT() macro as the generator function, if not providing their own. kunit_array_gen_params() is a KUnit helper that will use the registered array to generate parameters. The arrays passed to KUNIT_ARRAY_PARAM(,DESC) will also be registered to the parameterized test context for consistency as well as for higher availability of the parameter count that will be used for outputting a KTAP test plan for a parameterized test. This modification provides greater flexibility to the KUnit framework, allowing testers to easily register and utilize both dynamic and static parameter arrays. Reviewed-by: David Gow Reviewed-by: Rae Moar Signed-off-by: Marie Zhussupova [Only output the test plan if using kunit_array_gen_params --David] Signed-off-by: David Gow Acked-by: Mark Rutland --- Changes in v4: v3: https://lore.kernel.org/linux-kselftest/20250815103604.3857930-5-mariev= ic@google.com/ - Only output a KTAP test plan if the generate_params function is kunit_array_gen_params. - This fixes an issue with generate_params functions which use an array, but skip some elements. - This change is also available as a separate patch here: https://lore.kernel.org/linux-kselftest/20250821135447.1618942-2-davidgow= @google.com/ Changes in v3: v2: https://lore.kernel.org/all/20250811221739.2694336-5-marievic@google.co= m/ - Commit message formatting. Changes in v2: v1: https://lore.kernel.org/all/20250729193647.3410634-7-marievic@google.co= m/ - If the parameter count is available for a parameterized test, the kunit_run_tests() function will now output the KTAP test plan for it. - The name of the struct kunit_params field in struct kunit was changed from params_data to params_array. This name change better reflects its purpose, which is to encapsulate both the parameter array and its associated metadata. - The name of `kunit_get_next_param_and_desc` was changed to `kunit_array_gen_params` to make it simpler and to better fit its purpose of being KUnit's built-in generator function that uses arrays to generate parameters. - The signature of get_description() in `struct params_array` was changed to accept the parameterized test context, as well. This way test users can potentially use information available in the parameterized test context, such as the parameterized test name for setting the parameter description= s. - The type of `num_params` in `struct params_array` was changed from int to size_t for better handling of the array size. - The name of __kunit_init_params() was changed to be kunit_init_params(). Logic that sets the get_description() function pointer to NULL was also added in there. - `kunit_array_gen_params` is now exported to make it available to use with modules. - Instead of allowing NULL to be passed in as the parameter generator function in the KUNIT_CASE_PARAM_WITH_INIT macro, users will now be asked to provide `kunit_array_gen_params` as the generator function. This will ensure that a parameterized test remains defined by the existence of a parameter generation function. - KUNIT_ARRAY_PARAM(,DESC) will now additionally register the passed in arr= ay in struct kunit_params. This will make things more consistent i.e. if a parameter array is available then the struct kunit_params field in parent struct kunit is populated. Additionally, this will increase the availability of the KTAP test plan. - The comments and the commit message were changed to reflect the parameterized testing terminology. See the patch series cover letter change log for the definitions. --- include/kunit/test.h | 65 ++++++++++++++++++++++++++++++++++++++++---- lib/kunit/test.c | 32 ++++++++++++++++++++++ 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/include/kunit/test.h b/include/kunit/test.h index 8eba1b03c3e3..5ec5182b5e57 100644 --- a/include/kunit/test.h +++ b/include/kunit/test.h @@ -234,9 +234,13 @@ static inline char *kunit_status_to_ok_not_ok(enum kun= it_status status) * Provides the option to register param_init() and param_exit() functions. * param_init/exit will be passed the parameterized test context and run o= nce * before and once after the parameterized test. The init function can be = used - * to add resources to share between parameter runs, and any other setup l= ogic. - * The exit function can be used to clean up resources that were not manag= ed by - * the parameterized test, and any other teardown logic. + * to add resources to share between parameter runs, pass parameter arrays, + * and any other setup logic. The exit function can be used to clean up re= sources + * that were not managed by the parameterized test, and any other teardown= logic. + * + * Note: If you are registering a parameter array in param_init() with + * kunit_register_param_array() then you need to pass kunit_array_gen_para= ms() + * to this as the generator function. */ #define KUNIT_CASE_PARAM_WITH_INIT(test_name, gen_params, init, exit) \ { .run_case =3D test_name, .name =3D #test_name, \ @@ -289,6 +293,20 @@ struct kunit_suite_set { struct kunit_suite * const *end; }; =20 +/* Stores the pointer to the parameter array and its metadata. */ +struct kunit_params { + /* + * Reference to the parameter array for a parameterized test. This + * is NULL if a parameter array wasn't directly passed to the + * parameterized test context struct kunit via kunit_register_params_arra= y(). + */ + const void *params; + /* Reference to a function that gets the description of a parameter. */ + void (*get_description)(struct kunit *test, const void *param, char *desc= ); + size_t num_params; + size_t elem_size; +}; + /** * struct kunit - represents a running instance of a test. * @@ -296,16 +314,18 @@ struct kunit_suite_set { * created in the init function (see &struct kunit_suite). * @parent: reference to the parent context of type struct kunit that can * be used for storing shared resources. + * @params_array: for storing the parameter array. * * Used to store information about the current context under which the test * is running. Most of this data is private and should only be accessed - * indirectly via public functions; the two exceptions are @priv and @pare= nt - * which can be used by the test writer to store arbitrary data and access= the - * parent context, respectively. + * indirectly via public functions; the exceptions are @priv, @parent and + * @params_array which can be used by the test writer to store arbitrary d= ata, + * access the parent context, and to store the parameter array, respective= ly. */ struct kunit { void *priv; struct kunit *parent; + struct kunit_params params_array; =20 /* private: internal use only. */ const char *name; /* Read only after initialization! */ @@ -376,6 +396,8 @@ void kunit_exec_list_tests(struct kunit_suite_set *suit= e_set, bool include_attr) struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_= suite_set, struct kunit_suite_set suite_set); =20 +const void *kunit_array_gen_params(struct kunit *test, const void *prev, c= har *desc); + #if IS_BUILTIN(CONFIG_KUNIT) int kunit_run_all_tests(void); #else @@ -1708,6 +1730,8 @@ do { \ const void *prev, char *desc) \ { \ typeof((array)[0]) *__next =3D prev ? ((typeof(__next)) prev) + 1 : (arr= ay); \ + if (!prev) \ + kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \ if (__next - (array) < ARRAY_SIZE((array))) { \ void (*__get_desc)(typeof(__next), char *) =3D get_desc; \ if (__get_desc) \ @@ -1730,6 +1754,8 @@ do { \ const void *prev, char *desc) \ { \ typeof((array)[0]) *__next =3D prev ? ((typeof(__next)) prev) + 1 : (arr= ay); \ + if (!prev) \ + kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \ if (__next - (array) < ARRAY_SIZE((array))) { \ strscpy(desc, __next->desc_member, KUNIT_PARAM_DESC_SIZE); \ return __next; \ @@ -1737,6 +1763,33 @@ do { \ return NULL; \ } =20 +/** + * kunit_register_params_array() - Register parameter array for a KUnit te= st. + * @test: The KUnit test structure to which parameters will be added. + * @array: An array of test parameters. + * @param_count: Number of parameters. + * @get_desc: Function that generates a string description for a given par= ameter + * element. + * + * This macro initializes the @test's parameter array data, storing inform= ation + * including the parameter array, its count, the element size, and the par= ameter + * description function within `test->params_array`. + * + * Note: If using this macro in param_init(), kunit_array_gen_params() + * will then need to be manually provided as the parameter generator funct= ion to + * KUNIT_CASE_PARAM_WITH_INIT(). kunit_array_gen_params() is a KUnit + * function that uses the registered array to generate parameters + */ +#define kunit_register_params_array(test, array, param_count, get_desc) = \ + do { \ + struct kunit *_test =3D (test); \ + const typeof((array)[0]) * _params_ptr =3D &(array)[0]; \ + _test->params_array.params =3D _params_ptr; \ + _test->params_array.num_params =3D (param_count); \ + _test->params_array.elem_size =3D sizeof(*_params_ptr); \ + _test->params_array.get_description =3D (get_desc); \ + } while (0) + // TODO(dlatypov@google.com): consider eventually migrating users to expli= citly // include resource.h themselves if they need it. #include diff --git a/lib/kunit/test.c b/lib/kunit/test.c index 50705248abad..bb66ea1a3eac 100644 --- a/lib/kunit/test.c +++ b/lib/kunit/test.c @@ -337,6 +337,14 @@ void __kunit_do_failed_assertion(struct kunit *test, } EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion); =20 +static void kunit_init_params(struct kunit *test) +{ + test->params_array.params =3D NULL; + test->params_array.get_description =3D NULL; + test->params_array.num_params =3D 0; + test->params_array.elem_size =3D 0; +} + void kunit_init_test(struct kunit *test, const char *name, struct string_s= tream *log) { spin_lock_init(&test->lock); @@ -347,6 +355,7 @@ void kunit_init_test(struct kunit *test, const char *na= me, struct string_stream string_stream_clear(log); test->status =3D KUNIT_SUCCESS; test->status_comment[0] =3D '\0'; + kunit_init_params(test); } EXPORT_SYMBOL_GPL(kunit_init_test); =20 @@ -641,6 +650,23 @@ static void kunit_accumulate_stats(struct kunit_result= _stats *total, total->total +=3D add.total; } =20 +const void *kunit_array_gen_params(struct kunit *test, const void *prev, c= har *desc) +{ + struct kunit_params *params_arr =3D &test->params_array; + const void *param; + + if (test->param_index < params_arr->num_params) { + param =3D (char *)params_arr->params + + test->param_index * params_arr->elem_size; + + if (params_arr->get_description) + params_arr->get_description(test, param, desc); + return param; + } + return NULL; +} +EXPORT_SYMBOL_GPL(kunit_array_gen_params); + static void kunit_init_parent_param_test(struct kunit_case *test_case, str= uct kunit *test) { if (test_case->param_init) { @@ -706,6 +732,12 @@ int kunit_run_tests(struct kunit_suite *suite) "KTAP version 1\n"); kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT "# Subtest: %s", test_case->name); + if (test.params_array.params && + test_case->generate_params =3D=3D kunit_array_gen_params) { + kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT + KUNIT_SUBTEST_INDENT "1..%zd\n", + test.params_array.num_params); + } =20 while (curr_param) { struct kunit param_test =3D { --=20 2.51.0.261.g7ce5a0a67e-goog From nobody Sat Sep 27 19:19:59 2025 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6E82130E0D6 for ; Tue, 26 Aug 2025 09:13:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199635; cv=none; b=tpP9UxxvGSuK6tuGvASfZXePsz2HcGZBZ+j0MABUrbnAYdFTuiLFVf9vJRF/fAO+vjTWiFzxvMgEK/eV+KwQdK2zKurmQrG016XTqhsl8h7v9j/L+Ur6c0WnWxZtD1jgiu/+yIh9zkomscqDk00TWiBMHqTq05kpEQXGxc0ObtA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199635; c=relaxed/simple; bh=3aFRb/9IcKHZ+M6T9pjKhjrVD03MzY2Xmw+S7EN4W2Q=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=miPNAaSLoB4DVbSKGTdgZQZIeWUrZaALpNSlU9ICMpfRd68fabB9N4b8rJddMk90FJ7ii4ZdMKAAPTNq2vGjQaHWGe6xzG8kJlbtRlWsbLCMgwvAh3hloX8YxPkicZbcuDZo7F8FD44gn9lAp0xAdfUxQF56Z/MkrO/NkXrEX+k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ztZKiFdZ; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ztZKiFdZ" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-24457f59889so56278315ad.0 for ; Tue, 26 Aug 2025 02:13:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1756199633; x=1756804433; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=E/DdI8QKaF0QvnOvsbrRP9RRgtoSroBxXesHs3tNY3s=; b=ztZKiFdZMJN4rUrWKMJzleotJY622iBy8j7e46ZVKKLa/Jgjd6otQYZwYMfWyvH0NM Gk7y9MRPBdUKnqDQuNNbuuIyJUskKJjS1yn//D8bCP+AyOvUr1j5Qsj/tFinKjAdDRgI eMz4poDUQ8J7JfksA9xZZ/t/NBv6lsjZFqa91gQ5z0Zn1xuK9zYArSAu3ddO6nbNdrlJ vBlzcTW5jCxkhStAL+xxy2NCJoTXRugMEq6Tt5y6lFYz2Kg1NN10Xf0yMdP2bIVZRCDx jp1U5nAMGYZloOVPxq0pxqek6bAD19QoC4I2ApzG/mZfofKXzZpixmkV9KhTr5n1AF0/ 1dUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756199633; x=1756804433; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=E/DdI8QKaF0QvnOvsbrRP9RRgtoSroBxXesHs3tNY3s=; b=KCxxPm6K9hw31jSHRTVr5gqwKtlGz3opbYtIVr02y/4DCFRFjr7HZBbWtec7Wl4S8j Cl7bVvgvcrzlneYCM1F81qofIsuw80PWk3pAwht3cubC06Gnq2/kkfI2j/YXiFaMrW5y +nQqGSwzZMLpCe4GUHzF4MHxVXT/PJojw09Z5Z2WVVb5xhiBSs+CMOGTXjmsXt5hjBkX +FT8Ed0QjABahr4jxCXINn1zwsv3Sy6KUHPRbdGsL1MMhrY7g8CJUOD7L7GEDazgMjpz caibOH2tTAeUrR40MiJRZxiRMXthmn4E3hVqD3V/hMRqViVgHYX26RgQhfFYUueP/kbT 0sfg== X-Forwarded-Encrypted: i=1; AJvYcCVuii3lL/ruHzvdRFeHW/wXDSb6iYyMuKSB//rFmbeoDopnw6Hp3y8bpIIMogkvLK1bc5Y8pGYpzRpVkyo=@vger.kernel.org X-Gm-Message-State: AOJu0YzxpqEyKX2uRQz1G+KTKRpkCiWGZzW9nTgJ1pUc9cYPDvfCdBao gXWtdmM4e4LscmGzHyODN4qfVeA/nbuOwN+0hrQPkufIlMBxcKQ9G+GZmhTPbwj6wZn8WE9gXDz iPQiNJbminGO7NA== X-Google-Smtp-Source: AGHT+IFm2ccebIdeBPqgsg0k7MRJFE97IlpYmQ10sZM4xPEDskf6ORLyTRQTD8U2eP7B+NNUOmHZ2XIMml/jXw== X-Received: from pldp2.prod.google.com ([2002:a17:902:eac2:b0:237:cedc:1467]) (user=davidgow job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:ec87:b0:246:6a8b:8473 with SMTP id d9443c01a7336-2466a8b8672mr147539915ad.45.1756199632691; Tue, 26 Aug 2025 02:13:52 -0700 (PDT) Date: Tue, 26 Aug 2025 17:13:35 +0800 In-Reply-To: <20250826091341.1427123-1-davidgow@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250826091341.1427123-1-davidgow@google.com> X-Mailer: git-send-email 2.51.0.261.g7ce5a0a67e-goog Message-ID: <20250826091341.1427123-6-davidgow@google.com> Subject: [PATCH v4 5/7] kunit: Add example parameterized test with shared resource management using the Resource API From: David Gow To: Marie Zhussupova , marievictoria875@gmail.com, rmoar@google.com, shuah@kernel.org, brendan.higgins@linux.dev Cc: mark.rutland@arm.com, elver@google.com, dvyukov@google.com, lucas.demarchi@intel.com, thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, kasan-dev@googlegroups.com, intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Stephen Rothwell , David Gow Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marie Zhussupova Add example_params_test_with_init() to illustrate how to manage shared resources across a parameterized KUnit test. This example showcases the use of the new param_init() function and its registration to a test using the KUNIT_CASE_PARAM_WITH_INIT() macro. Additionally, the test demonstrates how to directly pass a parameter array to the parameterized test context via kunit_register_params_array() and leveraging the Resource API for shared resource management. Reviewed-by: Rae Moar Reviewed-by: David Gow Signed-off-by: Marie Zhussupova Signed-off-by: David Gow Acked-by: Mark Rutland --- No changes in v4: v3: https://lore.kernel.org/linux-kselftest/20250815103604.3857930-6-mariev= ic@google.com/ Changes in v3: v2: https://lore.kernel.org/all/20250811221739.2694336-6-marievic@google.co= m/ - Code comment edits. Changes in v2: v1: https://lore.kernel.org/all/20250729193647.3410634-8-marievic@google.co= m/ - kunit_array_gen_params() is now explicitly passed to KUNIT_CASE_PARAM_WITH_INIT() to be consistent with a parameterized test being defined by the existence of the generate_params() function. - The comments were edited to be more concise. - The patch header was changed to reflect that this example test's intent is more aligned with showcasing using the Resource API for shared resource management. - The comments and the commit message were changed to reflect the parameterized testing terminology. See the patch series cover letter change log for the definitions. --- lib/kunit/kunit-example-test.c | 113 +++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c index 3056d6bc705d..3e858367be01 100644 --- a/lib/kunit/kunit-example-test.c +++ b/lib/kunit/kunit-example-test.c @@ -277,6 +277,117 @@ static void example_slow_test(struct kunit *test) KUNIT_EXPECT_EQ(test, 1 + 1, 2); } =20 +/* + * This custom function allocates memory and sets the information we want + * stored in the kunit_resource->data field. + */ +static int example_resource_init(struct kunit_resource *res, void *context) +{ + int *info =3D kmalloc(sizeof(*info), GFP_KERNEL); + + if (!info) + return -ENOMEM; + *info =3D *(int *)context; + res->data =3D info; + return 0; +} + +/* + * This function deallocates memory for the kunit_resource->data field. + */ +static void example_resource_free(struct kunit_resource *res) +{ + kfree(res->data); +} + +/* + * This match function is invoked by kunit_find_resource() to locate + * a test resource based on certain criteria. + */ +static bool example_resource_alloc_match(struct kunit *test, + struct kunit_resource *res, + void *match_data) +{ + return res->data && res->free =3D=3D example_resource_free; +} + +/* + * This is an example of a function that provides a description for each o= f the + * parameters in a parameterized test. + */ +static void example_param_array_get_desc(struct kunit *test, const void *p= , char *desc) +{ + const struct example_param *param =3D p; + + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "example check if %d is less than or equal to 3", param->value); +} + +/* + * This function gets passed in the parameterized test context i.e. the + * struct kunit belonging to the parameterized test. You can use this func= tion + * to add resources you want shared across the whole parameterized test or + * for additional setup. + */ +static int example_param_init(struct kunit *test) +{ + int ctx =3D 3; /* Data to be stored. */ + size_t arr_size =3D ARRAY_SIZE(example_params_array); + + /* + * This allocates a struct kunit_resource, sets its data field to + * ctx, and adds it to the struct kunit's resources list. Note that + * this is parameterized test managed. So, it doesn't need to have + * a custom exit function to deallocation as it will get cleaned up at + * the end of the parameterized test. + */ + void *data =3D kunit_alloc_resource(test, example_resource_init, example_= resource_free, + GFP_KERNEL, &ctx); + + if (!data) + return -ENOMEM; + /* + * Pass the parameter array information to the parameterized test context + * struct kunit. Note that you will need to provide kunit_array_gen_param= s() + * as the generator function to KUNIT_CASE_PARAM_WITH_INIT() when registe= ring + * a parameter array this route. + */ + kunit_register_params_array(test, example_params_array, arr_size, + example_param_array_get_desc); + return 0; +} + +/* + * This is an example of a test that uses shared resources available in the + * parameterized test context. + */ +static void example_params_test_with_init(struct kunit *test) +{ + int threshold; + struct kunit_resource *res; + const struct example_param *param =3D test->param_value; + + /* By design, param pointer will not be NULL. */ + KUNIT_ASSERT_NOT_NULL(test, param); + + /* + * Here we pass test->parent to search for shared resources in the + * parameterized test context. + */ + res =3D kunit_find_resource(test->parent, example_resource_alloc_match, N= ULL); + + KUNIT_ASSERT_NOT_NULL(test, res); + + /* Since kunit_resource->data is a void pointer we need to typecast it. */ + threshold =3D *((int *)res->data); + + /* Assert that the parameter is less than or equal to a certain threshold= . */ + KUNIT_ASSERT_LE(test, param->value, threshold); + + /* This decreases the reference count after calling kunit_find_resource()= . */ + kunit_put_resource(res); +} + /* * Here we make a list of all the test cases we want to add to the test su= ite * below. @@ -296,6 +407,8 @@ static struct kunit_case example_test_cases[] =3D { KUNIT_CASE(example_static_stub_using_fn_ptr_test), KUNIT_CASE(example_priv_test), KUNIT_CASE_PARAM(example_params_test, example_gen_params), + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen= _params, + example_param_init, NULL), KUNIT_CASE_SLOW(example_slow_test), {} }; --=20 2.51.0.261.g7ce5a0a67e-goog From nobody Sat Sep 27 19:19:59 2025 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DD13630F55C for ; Tue, 26 Aug 2025 09:13:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199636; cv=none; b=a3uoFDdPYP2YhbEUVHIHpl7zvAe2GUeQa1Zh70a0qQCDktJ46KwByWtc7WP+REsl/ouXM9II0c5FgOwM4R/CFIzDILZ+XmRaREQ09EesQKkwKCBL07mawdrvaxv81p1gx6uJ3db//0Dnca5JsEmbCnit1isLEw0bD9MO9galnqY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199636; c=relaxed/simple; bh=YYAqQOrOM9pO/vDtcPG9o4KAmJKgdt7NSEdpwQyFils=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=loiIKbYqHD8DFdxFddjA00W4blmJji0KV+Glco61q3h3UrHN+sS2yKX/P96GkSpgjPDNwZtUTDctWUeOnkhc1vw5mAiUF5Rp+IgfBiUy4lhzQgvNOlZQP/H1kM3rDsjk9nFCZxBfJJEoZXsRzmcV9PqOQ5x2h4LP1H/Pp5Uqy4s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=GxLzhGbw; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="GxLzhGbw" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-b474b68cff7so4346497a12.1 for ; Tue, 26 Aug 2025 02:13:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1756199634; x=1756804434; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=r6YJBLokWG2Gb5OXsNbbrh9Xzkxl6kNwLj7uGaP0ytI=; b=GxLzhGbwnoXUIoD2LCD5GErKeZVHWnQ6UYKyvIJw1f6fawtHHu49nhEPY4EwKjIIod 6E3UJkna842bG7Zc3vLOScDfqRdqn6DOukKfenFaOJsKTr5dLLh6kuX9wMZIoPP0asUZ 2OaAKfJzDinjJTRhQGe2k7Estyd5gMRihIt6uOItGxBCfSEndZsQCAWMQQCoCXf17A6K SP7E8ypvOtudysiI+Cb2NPhvAnZSa+Z7U79TCop19n7j687h2xz9LGk9PdAM4F3668K1 rssnpAtC99Hnx/QlBcAT14oVeffxp7Jj8+DQFQ1+ZiRmq3/IcBJwxJnvrdoylZcf/q/E PoHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756199634; x=1756804434; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=r6YJBLokWG2Gb5OXsNbbrh9Xzkxl6kNwLj7uGaP0ytI=; b=nbJumnqJHI9ybtzUZpnwJ8QWhvQwM9OE3pfz65Ui21/eeLwvP0v/RPQsRW9GedISWf DfM9bLKGeh6LvT8znD8D2FyPC9hhgwtptr9k6xh/2cd7VtQ6rEZeHMz/45uB1o/1VW4p O0+blfQ/UuLAryFXwg5Cwqrrj2odEpX8TlXYFN9L+SQisS0aQT181iV+J6+2+VhnBSJF DpBg8bAD0ktrx2yulPQMVrL/CJoKj+4wt47pc+gZ7RbjqRCXPfUe7XWowMID+ZKvEeZV HXe+qn2KbQAtA82ecIZkdumMUno2lKW7Rhi2JNVcQqpP/xM0OwI88NuPYRfPj4Aq1Xw8 VPyg== X-Forwarded-Encrypted: i=1; AJvYcCUMAiZJd1Ahe+B53YJIFC1Lb+SQKu6kS80I4bkvRGAO+WG1nyx+mDBkkCJLLUMNja83vi3eIonNe2NbkrE=@vger.kernel.org X-Gm-Message-State: AOJu0YyBmGabRJ1TFZwhsL7BDlUTGOuEeCPOAhFeBUPu6qSWo16bLIX/ yx+MMx0BhteFxDOzvVpdLCFyP+M93jlFNR03gircYpypiTlfia7cjUgvQv2rHAy74GplPYJl1wf qv8QlOaHTP6mfqg== X-Google-Smtp-Source: AGHT+IFaxfaFtDgDXFqhlggWIN6qGO50AHV0jzc2236uvg1CHDn3C9T5tAHUO2oFudu0A5MM9qc/raG7mN2Efw== X-Received: from pjbpm5.prod.google.com ([2002:a17:90b:3c45:b0:31f:6ddd:ef5]) (user=davidgow job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:c202:b0:243:6f08:86b4 with SMTP id adf61e73a8af0-2436f088fe5mr8170082637.39.1756199634209; Tue, 26 Aug 2025 02:13:54 -0700 (PDT) Date: Tue, 26 Aug 2025 17:13:36 +0800 In-Reply-To: <20250826091341.1427123-1-davidgow@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250826091341.1427123-1-davidgow@google.com> X-Mailer: git-send-email 2.51.0.261.g7ce5a0a67e-goog Message-ID: <20250826091341.1427123-7-davidgow@google.com> Subject: [PATCH v4 6/7] kunit: Add example parameterized test with direct dynamic parameter array setup From: David Gow To: Marie Zhussupova , marievictoria875@gmail.com, rmoar@google.com, shuah@kernel.org, brendan.higgins@linux.dev Cc: mark.rutland@arm.com, elver@google.com, dvyukov@google.com, lucas.demarchi@intel.com, thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, kasan-dev@googlegroups.com, intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Stephen Rothwell , David Gow Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marie Zhussupova Introduce example_params_test_with_init_dynamic_arr(). This new KUnit test demonstrates directly assigning a dynamic parameter array, using the kunit_register_params_array() macro, to a parameterized test context. It highlights the use of param_init() and param_exit() for initialization and exit of a parameterized test, and their registration to the test case with KUNIT_CASE_PARAM_WITH_INIT(). Reviewed-by: Rae Moar Reviewed-by: David Gow Signed-off-by: Marie Zhussupova Signed-off-by: David Gow Acked-by: Mark Rutland --- Changes in v4: v3: https://lore.kernel.org/linux-kselftest/20250815103604.3857930-7-mariev= ic@google.com/ - No changes. Changes in v3: v2: https://lore.kernel.org/all/20250811221739.2694336-7-marievic@google.co= m/ - No changes. Changes in v2: v1: https://lore.kernel.org/all/20250729193647.3410634-9-marievic@google.co= m/ - kunit_array_gen_params() is now explicitly passed to KUNIT_CASE_PARAM_WITH_INIT() to be consistent with the parameterized test being defined by the existence of the generate_params() function. - param_init() was changed to output a log at the start of a parameterized test. - The parameter array was changed to be allocated using kunit_kmalloc_array= (), a KUnit memory allocation API, as that would be the preferred/easier meth= od. To still demonstrate a use of param_exit(), it now outputs a log at the e= nd of the parameterized test. - The comments and the commit message were changed to reflect the parameterized testing terminology. See the patch series cover letter change log for the definitions. --- lib/kunit/kunit-example-test.c | 104 +++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/lib/kunit/kunit-example-test.c b/lib/kunit/kunit-example-test.c index 3e858367be01..9452b163956f 100644 --- a/lib/kunit/kunit-example-test.c +++ b/lib/kunit/kunit-example-test.c @@ -388,6 +388,107 @@ static void example_params_test_with_init(struct kuni= t *test) kunit_put_resource(res); } =20 +/* + * Helper function to create a parameter array of Fibonacci numbers. This = example + * highlights a parameter generation scenario that is: + * 1. Not feasible to fully pre-generate at compile time. + * 2. Challenging to implement with a standard generate_params() function, + * as it only provides the previous parameter, while Fibonacci requires + * access to two preceding values for calculation. + */ +static void *make_fibonacci_params(struct kunit *test, size_t seq_size) +{ + int *seq; + + if (seq_size <=3D 0) + return NULL; + /* + * Using kunit_kmalloc_array here ties the lifetime of the array to + * the parameterized test i.e. it will get automatically cleaned up + * by KUnit after the parameterized test finishes. + */ + seq =3D kunit_kmalloc_array(test, seq_size, sizeof(int), GFP_KERNEL); + + if (!seq) + return NULL; + if (seq_size >=3D 1) + seq[0] =3D 0; + if (seq_size >=3D 2) + seq[1] =3D 1; + for (int i =3D 2; i < seq_size; i++) + seq[i] =3D seq[i - 1] + seq[i - 2]; + return seq; +} + +/* + * This is an example of a function that provides a description for each o= f the + * parameters. + */ +static void example_param_dynamic_arr_get_desc(struct kunit *test, const v= oid *p, char *desc) +{ + const int *fib_num =3D p; + + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "fibonacci param: %d", *fib_num); +} + +/* + * Example of a parameterized test param_init() function that registers a = dynamic + * array of parameters. + */ +static int example_param_init_dynamic_arr(struct kunit *test) +{ + size_t seq_size; + int *fibonacci_params; + + kunit_info(test, "initializing parameterized test\n"); + + seq_size =3D 6; + fibonacci_params =3D make_fibonacci_params(test, seq_size); + + if (!fibonacci_params) + return -ENOMEM; + + /* + * Passes the dynamic parameter array information to the parameterized te= st + * context struct kunit. The array and its metadata will be stored in + * test->parent->params_array. The array itself will be located in + * params_data.params. + * + * Note that you will need to pass kunit_array_gen_params() as the + * generator function to KUNIT_CASE_PARAM_WITH_INIT() when registering + * a parameter array this route. + */ + kunit_register_params_array(test, fibonacci_params, seq_size, + example_param_dynamic_arr_get_desc); + return 0; +} + +/* + * Example of a parameterized test param_exit() function that outputs a log + * at the end of the parameterized test. It could also be used for any oth= er + * teardown logic. + */ +static void example_param_exit_dynamic_arr(struct kunit *test) +{ + kunit_info(test, "exiting parameterized test\n"); +} + +/* + * Example of test that uses the registered dynamic array to perform asser= tions + * and expectations. + */ +static void example_params_test_with_init_dynamic_arr(struct kunit *test) +{ + const int *param =3D test->param_value; + int param_val; + + /* By design, param pointer will not be NULL. */ + KUNIT_ASSERT_NOT_NULL(test, param); + + param_val =3D *param; + KUNIT_EXPECT_EQ(test, param_val - param_val, 0); +} + /* * Here we make a list of all the test cases we want to add to the test su= ite * below. @@ -409,6 +510,9 @@ static struct kunit_case example_test_cases[] =3D { KUNIT_CASE_PARAM(example_params_test, example_gen_params), KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen= _params, example_param_init, NULL), + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr, + kunit_array_gen_params, example_param_init_dynamic_arr, + example_param_exit_dynamic_arr), KUNIT_CASE_SLOW(example_slow_test), {} }; --=20 2.51.0.261.g7ce5a0a67e-goog From nobody Sat Sep 27 19:19:59 2025 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B4EF030E84D for ; Tue, 26 Aug 2025 09:13:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199639; cv=none; b=HKkgccR/Ut7Zv0cKlGcL4HhXbaL5L3KTrHVOH9WgidWVVy+iYjaC53DIH00yDHXTSjcD/oDtZAMVQ6YtGZ7yIUuj3e/3/Xg82QIY6Gn2HwEUyOvRj7qERCce0uWN9Y1GbPmuLlpcYC81WM3N+325p7W4qOf4yFOlXVK4H7N0Rro= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756199639; c=relaxed/simple; bh=fZTQKoZtxlMdY02VJWnzaaF/U4lTXk6cYMSJTCj31kM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ot3PIN/MyNXCZs12IKg2vyzGCTet6a89GT4H02QDKsTT4F/bIwfQRFl4BnOtWRPjX8Uoyr2W/wxzrg0hzhhHhHHfdBEiYaZ1WKwfn6aoxGIfpzdT1C8teH6og9CsSHTGawTKOJhgSIygMwfins1Jm6UfsFWfcrgkHcZVaDi844w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=OywzlLDA; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--davidgow.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="OywzlLDA" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-76e364afb44so4195112b3a.3 for ; Tue, 26 Aug 2025 02:13:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1756199636; x=1756804436; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=bNb+tbEq0O34V9vRUZVDatMKWz5EoksX488NOcATxpQ=; b=OywzlLDANFX7ChjyBhgk6gwM7ssWzFwr3Y/eBEHqgZEdZeiwy7GNpNY2ObEk5jgR1j nbUdHnZEQt/H29V6fcRDqWvsfwDUyPJagc8I/QrVdDh+gvNHoFVWP9OIIX3d+3RZ1+zg w+Pf7klEc1rPDmsQEfOY7E1ZY2xXVcQjFGVlpqv/bdYQnManZHgUnlKkEC36HRI+c0k1 zoPdltSO9rbBd1sR+Mtt8Ja3kVZZJYdSiqg3PYqXrmjiYeuGQP+JyrxgVg6MxQKCvDNi VJo4Ox335MdDQAjNv7RKdxD3ar/pkrN7bq0xy/kpuhNGPNFBsrRGAmDjglsJvSMAzRHW ItWg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756199636; x=1756804436; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=bNb+tbEq0O34V9vRUZVDatMKWz5EoksX488NOcATxpQ=; b=JQ+GmJyMWMzvZizhibgU8VcImxE7XHSV7vCPjsP3nqvzPZhud8XoMkCmZ71+Iigho8 46ojGkl1+uLN5F3QA3iJCDt34rR+h+VKNxyN3W5Quwt1IjcMv4PoPE37zwx4tKclZeJt McV9Wna848hER5vcbcB1FLs9aTt2mL8yMdx/nigSdR/tgWiHCZDbjNIiHlorJHuh2rAS fpe4Ydt53qGkITfs0mTjMdgaNvzL0qjsPjEQfoo308L1I614ggrxo0JmM+Bvvytl7+GR OehwtOrZn8VyK6KFpt34TJsSK6E/tVsbQ8HqEBYl95X/p/g5GVAZj2kxCWPPz2eqOQRn q+xQ== X-Forwarded-Encrypted: i=1; AJvYcCUSkck2j/Xp7tkX6V6XHGVFzbUWxHH/zMg6qvLP/WbcFKlP3qeOcgHHUx0iO/YPP2OZQXmpMSdW2EgYa3w=@vger.kernel.org X-Gm-Message-State: AOJu0YxmKNKbtlE8B/UGkA+oYNn8xcVvYn/pUunSdwsdaMiIbPX1gw7W G/ZZQ8q3sOUMAOHYrdhcXSiea442/Qiydi00eJSy9L/oRkPZVURow2pxDlb578tZMUPUdGADNhm BYljUEQVAwC+LeQ== X-Google-Smtp-Source: AGHT+IFAkx9n+aeNyw8isqYmiZfZjNU29qXldl9QF7x6LCP8tU6gomeW8VRUwkiD6vhkbmXxwS8+qtx3wIknug== X-Received: from pfbbx23.prod.google.com ([2002:a05:6a00:4297:b0:770:4ea0:3960]) (user=davidgow job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:3e01:b0:76e:885a:c33a with SMTP id d2e1a72fcca58-7702fc28b0cmr21053996b3a.32.1756199635827; Tue, 26 Aug 2025 02:13:55 -0700 (PDT) Date: Tue, 26 Aug 2025 17:13:37 +0800 In-Reply-To: <20250826091341.1427123-1-davidgow@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250826091341.1427123-1-davidgow@google.com> X-Mailer: git-send-email 2.51.0.261.g7ce5a0a67e-goog Message-ID: <20250826091341.1427123-8-davidgow@google.com> Subject: [PATCH v4 7/7] Documentation: kunit: Document new parameterized test features From: David Gow To: Marie Zhussupova , marievictoria875@gmail.com, rmoar@google.com, shuah@kernel.org, brendan.higgins@linux.dev Cc: mark.rutland@arm.com, elver@google.com, dvyukov@google.com, lucas.demarchi@intel.com, thomas.hellstrom@linux.intel.com, rodrigo.vivi@intel.com, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, kasan-dev@googlegroups.com, intel-xe@lists.freedesktop.org, dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org, Stephen Rothwell , David Gow Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Marie Zhussupova This patch updates the KUnit docs to show how to use the new parameterized test context to share resources between parameter runs. It documents and show examples of different ways the test user can pass parameter arrays to a parameterized test. Finally, it specifies the parameterized testing terminology. Reviewed-by: Rae Moar Reviewed-by: David Gow Signed-off-by: Marie Zhussupova Signed-off-by: David Gow Acked-by: Mark Rutland --- Changes in v4: v3: https://lore.kernel.org/linux-kselftest/20250815103604.3857930-8-mariev= ic@google.com/ - No changes. Changes in v3: v2: https://lore.kernel.org/all/20250811221739.2694336-8-marievic@google.co= m/ - Parameterized test terminology was made more concise. - Introduction now includes more background information on the generate_params() function. - Minor wording edits for conciseness. - Code line number references were removed as they could quickly go out of date. Changes in v2: v1: https://lore.kernel.org/all/20250729193647.3410634-10-marievic@google.c= om/ - The documentation was updated to establish the parameterized testing terminology and reflect all the patch series changes. - The references to other parts of the KUnit Documentation were not changed from being "Documentation/dev-tools/kunit/api/test.rst" to ":ref:`kunit-resource`" links as originally planned. This is because the existing way shows up as a link to a webpage and it would be hard for people reading the documentation as an .rst file to find the referred section without having the file path. - The code examples were made more concise. - Minor edits to titles and formatting. --- Documentation/dev-tools/kunit/usage.rst | 342 +++++++++++++++++++++++- 1 file changed, 337 insertions(+), 5 deletions(-) diff --git a/Documentation/dev-tools/kunit/usage.rst b/Documentation/dev-to= ols/kunit/usage.rst index 066ecda1dd98..ebd06f5ea455 100644 --- a/Documentation/dev-tools/kunit/usage.rst +++ b/Documentation/dev-tools/kunit/usage.rst @@ -542,11 +542,31 @@ There is more boilerplate code involved, but it can: Parameterized Testing ~~~~~~~~~~~~~~~~~~~~~ =20 -The table-driven testing pattern is common enough that KUnit has special -support for it. +To run a test case against multiple inputs, KUnit provides a parameterized +testing framework. This feature formalizes and extends the concept of +table-driven tests discussed previously. =20 -By reusing the same ``cases`` array from above, we can write the test as a -"parameterized test" with the following. +A KUnit test is determined to be parameterized if a parameter generator fu= nction +is provided when registering the test case. A test user can either write t= heir +own generator function or use one that is provided by KUnit. The generator +function is stored in ``kunit_case->generate_params`` and can be set usin= g the +macros described in the section below. + +To establish the terminology, a "parameterized test" is a test which is run +multiple times (once per "parameter" or "parameter run"). Each parameter r= un has +both its own independent ``struct kunit`` (the "parameter run context") and +access to a shared parent ``struct kunit`` (the "parameterized test contex= t"). + +Passing Parameters to a Test +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +There are three ways to provide the parameters to a test: + +Array Parameter Macros: + + KUnit provides special support for the common table-driven testing patt= ern. + By applying either ``KUNIT_ARRAY_PARAM`` or ``KUNIT_ARRAY_PARAM_DESC`` = to the + ``cases`` array from the previous section, we can create a parameterize= d test + as shown below: =20 .. code-block:: c =20 @@ -555,7 +575,7 @@ By reusing the same ``cases`` array from above, we can = write the test as a const char *str; const char *sha1; }; - const struct sha1_test_case cases[] =3D { + static const struct sha1_test_case cases[] =3D { { .str =3D "hello world", .sha1 =3D "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", @@ -590,6 +610,318 @@ By reusing the same ``cases`` array from above, we ca= n write the test as a {} }; =20 +Custom Parameter Generator Function: + + The generator function is responsible for generating parameters one-by-= one + and has the following signature: + ``const void* (*)(struct kunit *test, const void *prev, char *desc)``. + You can pass the generator function to the ``KUNIT_CASE_PARAM`` + or ``KUNIT_CASE_PARAM_WITH_INIT`` macros. + + The function receives the previously generated parameter as the ``prev`= ` argument + (which is ``NULL`` on the first call) and can also access the parameter= ized + test context passed as the ``test`` argument. KUnit calls this function + repeatedly until it returns ``NULL``, which signifies that a parameteri= zed + test ended. + + Below is an example of how it works: + +.. code-block:: c + + #define MAX_TEST_BUFFER_SIZE 8 + + // Example generator function. It produces a sequence of buffer sizes that + // are powers of two, starting at 1 (e.g., 1, 2, 4, 8). + static const void *buffer_size_gen_params(struct kunit *test, const void = *prev, char *desc) + { + long prev_buffer_size =3D (long)prev; + long next_buffer_size =3D 1; // Start with an initial size of 1. + + // Stop generating parameters if the limit is reached or exceeded. + if (prev_buffer_size >=3D MAX_TEST_BUFFER_SIZE) + return NULL; + + // For subsequent calls, calculate the next size by doubling the previou= s one. + if (prev) + next_buffer_size =3D prev_buffer_size << 1; + + return (void *)next_buffer_size; + } + + // Simple test to validate that kunit_kzalloc provides zeroed memory. + static void buffer_zero_test(struct kunit *test) + { + long buffer_size =3D (long)test->param_value; + // Use kunit_kzalloc to allocate a zero-initialized buffer. This makes t= he + // memory "parameter run managed," meaning it's automatically cleaned up= at + // the end of each parameter run. + int *buf =3D kunit_kzalloc(test, buffer_size * sizeof(int), GFP_KERNEL); + + // Ensure the allocation was successful. + KUNIT_ASSERT_NOT_NULL(test, buf); + + // Loop through the buffer and confirm every element is zero. + for (int i =3D 0; i < buffer_size; i++) + KUNIT_EXPECT_EQ(test, buf[i], 0); + } + + static struct kunit_case buffer_test_cases[] =3D { + KUNIT_CASE_PARAM(buffer_zero_test, buffer_size_gen_params), + {} + }; + +Runtime Parameter Array Registration in the Init Function: + + For scenarios where you might need to initialize a parameterized test, = you + can directly register a parameter array to the parameterized test conte= xt. + + To do this, you must pass the parameterized test context, the array its= elf, + the array size, and a ``get_description()`` function to the + ``kunit_register_params_array()`` macro. This macro populates + ``struct kunit_params`` within the parameterized test context, effectiv= ely + storing a parameter array object. The ``get_description()`` function wi= ll + be used for populating parameter descriptions and has the following sig= nature: + ``void (*)(struct kunit *test, const void *param, char *desc)``. Note t= hat it + also has access to the parameterized test context. + + .. important:: + When using this way to register a parameter array, you will need = to + manually pass ``kunit_array_gen_params()`` as the generator funct= ion to + ``KUNIT_CASE_PARAM_WITH_INIT``. ``kunit_array_gen_params()`` is a= KUnit + helper that will use the registered array to generate the paramet= ers. + + If needed, instead of passing the KUnit helper, you can also pass your + own custom generator function that utilizes the parameter array. To + access the parameter array from within the parameter generator + function use ``test->params_array.params``. + + The ``kunit_register_params_array()`` macro should be called within a + ``param_init()`` function that initializes the parameterized test and h= as + the following signature ``int (*)(struct kunit *test)``. For a detailed + explanation of this mechanism please refer to the "Adding Shared Resour= ces" + section that is after this one. This method supports registering both + dynamically built and static parameter arrays. + + The code snippet below shows the ``example_param_init_dynamic_arr`` tes= t that + utilizes ``make_fibonacci_params()`` to create a dynamic array, which i= s then + registered using ``kunit_register_params_array()``. To see the full code + please refer to lib/kunit/kunit-example-test.c. + +.. code-block:: c + + /* + * Example of a parameterized test param_init() function that registers a = dynamic + * array of parameters. + */ + static int example_param_init_dynamic_arr(struct kunit *test) + { + size_t seq_size; + int *fibonacci_params; + + kunit_info(test, "initializing parameterized test\n"); + + seq_size =3D 6; + fibonacci_params =3D make_fibonacci_params(test, seq_size); + if (!fibonacci_params) + return -ENOMEM; + /* + * Passes the dynamic parameter array information to the parameterized te= st + * context struct kunit. The array and its metadata will be stored in + * test->parent->params_array. The array itself will be located in + * params_data.params. + */ + kunit_register_params_array(test, fibonacci_params, seq_size, + example_param_dynamic_arr_get_desc); + return 0; + } + + static struct kunit_case example_test_cases[] =3D { + /* + * Note how we pass kunit_array_gen_params() to use the array we + * registered in example_param_init_dynamic_arr() to generate + * parameters. + */ + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr, + kunit_array_gen_params, + example_param_init_dynamic_arr, + example_param_exit_dynamic_arr), + {} + }; + +Adding Shared Resources +^^^^^^^^^^^^^^^^^^^^^^^ +All parameter runs in this framework hold a reference to the parameterized= test +context, which can be accessed using the parent ``struct kunit`` pointer. = The +parameterized test context is not used to execute any test logic itself; i= nstead, +it serves as a container for shared resources. + +It's possible to add resources to share between parameter runs within a +parameterized test by using ``KUNIT_CASE_PARAM_WITH_INIT``, to which you p= ass +custom ``param_init()`` and ``param_exit()`` functions. These functions ru= n once +before and once after the parameterized test, respectively. + +The ``param_init()`` function, with the signature ``int (*)(struct kunit *= test)``, +can be used for adding resources to the ``resources`` or ``priv`` fields of +the parameterized test context, registering the parameter array, and any o= ther +initialization logic. + +The ``param_exit()`` function, with the signature ``void (*)(struct kunit = *test)``, +can be used to release any resources that were not parameterized test mana= ged (i.e. +not automatically cleaned up after the parameterized test ends) and for an= y other +exit logic. + +Both ``param_init()`` and ``param_exit()`` are passed the parameterized te= st +context behind the scenes. However, the test case function receives the pa= rameter +run context. Therefore, to manage and access shared resources from within = a test +case function, you must use ``test->parent``. + +For instance, finding a shared resource allocated by the Resource API requ= ires +passing ``test->parent`` to ``kunit_find_resource()``. This principle exte= nds to +all other APIs that might be used in the test case function, including +``kunit_kzalloc()``, ``kunit_kmalloc_array()``, and others (see +Documentation/dev-tools/kunit/api/test.rst and the +Documentation/dev-tools/kunit/api/resource.rst). + +.. note:: + The ``suite->init()`` function, which executes before each parameter ru= n, + receives the parameter run context. Therefore, any resources set up in + ``suite->init()`` are cleaned up after each parameter run. + +The code below shows how you can add the shared resources. Note that this = code +utilizes the Resource API, which you can read more about here: +Documentation/dev-tools/kunit/api/resource.rst. To see the full version of= this +code please refer to lib/kunit/kunit-example-test.c. + +.. code-block:: c + + static int example_resource_init(struct kunit_resource *res, void *contex= t) + { + ... /* Code that allocates memory and stores context in res->data. */ + } + + /* This function deallocates memory for the kunit_resource->data field. */ + static void example_resource_free(struct kunit_resource *res) + { + kfree(res->data); + } + + /* This match function locates a test resource based on defined criteria.= */ + static bool example_resource_alloc_match(struct kunit *test, struct kunit= _resource *res, + void *match_data) + { + return res->data && res->free =3D=3D example_resource_free; + } + + /* Function to initialize the parameterized test. */ + static int example_param_init(struct kunit *test) + { + int ctx =3D 3; /* Data to be stored. */ + void *data =3D kunit_alloc_resource(test, example_resource_init, + example_resource_free, + GFP_KERNEL, &ctx); + if (!data) + return -ENOMEM; + kunit_register_params_array(test, example_params_array, + ARRAY_SIZE(example_params_array)); + return 0; + } + + /* Example test that uses shared resources in test->resources. */ + static void example_params_test_with_init(struct kunit *test) + { + int threshold; + const struct example_param *param =3D test->param_value; + /* Here we pass test->parent to access the parameterized test context. = */ + struct kunit_resource *res =3D kunit_find_resource(test->parent, + example_resource_alloc_match, + NULL); + + threshold =3D *((int *)res->data); + KUNIT_ASSERT_LE(test, param->value, threshold); + kunit_put_resource(res); + } + + static struct kunit_case example_test_cases[] =3D { + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_ge= n_params, + example_param_init, NULL), + {} + }; + +As an alternative to using the KUnit Resource API for sharing resources, y= ou can +place them in ``test->parent->priv``. This serves as a more lightweight me= thod +for resource storage, best for scenarios where complex resource management= is +not required. + +As stated previously ``param_init()`` and ``param_exit()`` get the paramet= erized +test context. So, you can directly use ``test->priv`` within ``param_init/= exit`` +to manage shared resources. However, from within the test case function, y= ou must +navigate up to the parent ``struct kunit`` i.e. the parameterized test con= text. +Therefore, you need to use ``test->parent->priv`` to access those same +resources. + +The resources placed in ``test->parent->priv`` will need to be allocated in +memory to persist across the parameter runs. If memory is allocated using = the +KUnit memory allocation APIs (described more in the "Allocating Memory" se= ction +below), you won't need to worry about deallocation. The APIs will make the= memory +parameterized test 'managed', ensuring that it will automatically get clea= ned up +after the parameterized test concludes. + +The code below demonstrates example usage of the ``priv`` field for shared +resources: + +.. code-block:: c + + static const struct example_param { + int value; + } example_params_array[] =3D { + { .value =3D 3, }, + { .value =3D 2, }, + { .value =3D 1, }, + { .value =3D 0, }, + }; + + /* Initialize the parameterized test context. */ + static int example_param_init_priv(struct kunit *test) + { + int ctx =3D 3; /* Data to be stored. */ + int arr_size =3D ARRAY_SIZE(example_params_array); + + /* + * Allocate memory using kunit_kzalloc(). Since the `param_init` + * function receives the parameterized test context, this memory + * allocation will be scoped to the lifetime of the parameterized test. + */ + test->priv =3D kunit_kzalloc(test, sizeof(int), GFP_KERNEL); + + /* Assign the context value to test->priv.*/ + *((int *)test->priv) =3D ctx; + + /* Register the parameter array. */ + kunit_register_params_array(test, example_params_array, arr_size, NULL); + return 0; + } + + static void example_params_test_with_init_priv(struct kunit *test) + { + int threshold; + const struct example_param *param =3D test->param_value; + + /* By design, test->parent will not be NULL. */ + KUNIT_ASSERT_NOT_NULL(test, test->parent); + + /* Here we use test->parent->priv to access the shared resource. */ + threshold =3D *(int *)test->parent->priv; + + KUNIT_ASSERT_LE(test, param->value, threshold); + } + + static struct kunit_case example_tests[] =3D { + KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_priv, + kunit_array_gen_params, + example_param_init_priv, NULL), + {} + }; + Allocating Memory ----------------- =20 --=20 2.51.0.261.g7ce5a0a67e-goog