ASoC: topology: KUnit: Add KUnit tests passing various arguments to snd_soc_tplg_component_load

In order to ensure correct behaviour of topology API, add unit tests
exercising topology functionality.

Start with adding cases for passing various arguments to
snd_soc_tplg_component_load as it is part of exposed topology API.

First test case adds test passing NULL component as argument.
Following one adds test case for passing NULL ops as argument.
Finally add test case passing NULL fw as argument.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Tested-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20210120152846.1703655-4-amadeuszx.slawinski@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Amadeusz Sławiński 2021-01-20 16:28:44 +01:00 committed by Mark Brown
parent 879a67e357
commit d52bbf747c
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
3 changed files with 325 additions and 0 deletions

View File

@ -37,6 +37,23 @@ config SND_SOC_COMPRESS
config SND_SOC_TOPOLOGY
bool
config SND_SOC_TOPOLOGY_KUNIT_TESTS
tristate "KUnit tests for SoC topology"
depends on KUNIT
depends on SND_SOC_TOPOLOGY
default KUNIT_ALL_TESTS
help
If you want to perform tests on ALSA SoC topology support say Y here.
This builds a module which can be later manually loaded to run KUNIT
test cases against soc-topology.c API. This should be primarily used
by developers to test their changes to ASoC.
Do note that it creates fake playback devices which do not interact
well with userspace. When running tests one may want to disable
userspace applications such as pulseaudio, to prevent unnecessary
problems.
config SND_SOC_ACPI
tristate

View File

@ -7,6 +7,11 @@ ifneq ($(CONFIG_SND_SOC_TOPOLOGY),)
snd-soc-core-objs += soc-topology.o
endif
ifneq ($(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS),)
# snd-soc-test-objs := soc-topology-test.o
obj-$(CONFIG_SND_SOC_TOPOLOGY_KUNIT_TESTS) := soc-topology-test.o
endif
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
endif

View File

@ -0,0 +1,303 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* soc-topology-test.c -- ALSA SoC Topology Kernel Unit Tests
*
* Copyright(c) 2021 Intel Corporation. All rights reserved.
*/
#include <linux/firmware.h>
#include <linux/random.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-topology.h>
#include <kunit/test.h>
/* ===== HELPER FUNCTIONS =================================================== */
/*
* snd_soc_component needs device to operate on (primarily for prints), create
* fake one, as we don't register with PCI or anything else
* device_driver name is used in some of the prints (fmt_single_name) so
* we also mock up minimal one
*/
static struct device *test_dev;
static struct device_driver test_drv = {
.name = "sound-soc-topology-test-driver",
};
static int snd_soc_tplg_test_init(struct kunit *test)
{
test_dev = root_device_register("sound-soc-topology-test");
test_dev = get_device(test_dev);
if (!test_dev)
return -ENODEV;
test_dev->driver = &test_drv;
return 0;
}
static void snd_soc_tplg_test_exit(struct kunit *test)
{
put_device(test_dev);
root_device_unregister(test_dev);
}
/*
* helper struct we use when registering component, as we load topology during
* component probe, we need to pass struct kunit somehow to probe function, so
* we can report test result
*/
struct kunit_soc_component {
struct kunit *kunit;
int expect; /* what result we expect when loading topology */
struct snd_soc_component comp;
struct snd_soc_card card;
struct firmware fw;
};
static int d_probe(struct snd_soc_component *component)
{
struct kunit_soc_component *kunit_comp =
container_of(component, struct kunit_soc_component, comp);
int ret;
ret = snd_soc_tplg_component_load(component, NULL, &kunit_comp->fw);
KUNIT_EXPECT_EQ_MSG(kunit_comp->kunit, kunit_comp->expect, ret,
"Failed topology load");
return 0;
}
static void d_remove(struct snd_soc_component *component)
{
struct kunit_soc_component *kunit_comp =
container_of(component, struct kunit_soc_component, comp);
int ret;
ret = snd_soc_tplg_component_remove(component);
KUNIT_EXPECT_EQ(kunit_comp->kunit, 0, ret);
}
/*
* ASoC minimal boiler plate
*/
SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
SND_SOC_DAILINK_DEF(platform, DAILINK_COMP_ARRAY(COMP_PLATFORM("sound-soc-topology-test")));
static struct snd_soc_dai_link kunit_dai_links[] = {
{
.name = "KUNIT Audio Port",
.id = 0,
.stream_name = "Audio Playback/Capture",
.nonatomic = 1,
.dynamic = 1,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
.dpcm_capture = 1,
SND_SOC_DAILINK_REG(dummy, dummy, platform),
},
};
static const struct snd_soc_component_driver test_component = {
.name = "sound-soc-topology-test",
.probe = d_probe,
.remove = d_remove,
.non_legacy_dai_naming = 1,
};
/* ===== TEST CASES ========================================================= */
// TEST CASE
// Test passing NULL component as parameter to snd_soc_tplg_component_load
/*
* need to override generic probe function with one using NULL when calling
* topology load during component initialization, we don't need .remove
* handler as load should fail
*/
static int d_probe_null_comp(struct snd_soc_component *component)
{
struct kunit_soc_component *kunit_comp =
container_of(component, struct kunit_soc_component, comp);
int ret;
/* instead of passing component pointer as first argument, pass NULL here */
ret = snd_soc_tplg_component_load(NULL, NULL, &kunit_comp->fw);
KUNIT_EXPECT_EQ_MSG(kunit_comp->kunit, kunit_comp->expect, ret,
"Failed topology load");
return 0;
}
static const struct snd_soc_component_driver test_component_null_comp = {
.name = "sound-soc-topology-test",
.probe = d_probe_null_comp,
.non_legacy_dai_naming = 1,
};
static void snd_soc_tplg_test_load_with_null_comp(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
int ret;
/* prepare */
kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
kunit_comp->kunit = test;
kunit_comp->expect = -EINVAL; /* expect failure */
kunit_comp->card.dev = test_dev,
kunit_comp->card.name = "kunit-card",
kunit_comp->card.owner = THIS_MODULE,
kunit_comp->card.dai_link = kunit_dai_links,
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
kunit_comp->card.fully_routed = true,
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_comp, test_dev);
KUNIT_EXPECT_EQ(test, 0, ret);
ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
ret = snd_soc_unregister_card(&kunit_comp->card);
KUNIT_EXPECT_EQ(test, 0, ret);
snd_soc_unregister_component(test_dev);
}
// TEST CASE
// Test passing NULL ops as parameter to snd_soc_tplg_component_load
/*
* NULL ops is default case, we pass empty topology (fw), so we don't have
* anything to parse and just do nothing, which results in return 0; from
* calling soc_tplg_dapm_complete in soc_tplg_process_headers
*/
static void snd_soc_tplg_test_load_with_null_ops(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
int ret;
/* prepare */
kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
kunit_comp->kunit = test;
kunit_comp->expect = 0; /* expect success */
kunit_comp->card.dev = test_dev,
kunit_comp->card.name = "kunit-card",
kunit_comp->card.owner = THIS_MODULE,
kunit_comp->card.dai_link = kunit_dai_links,
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
kunit_comp->card.fully_routed = true,
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component, test_dev);
KUNIT_EXPECT_EQ(test, 0, ret);
ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
ret = snd_soc_unregister_card(&kunit_comp->card);
KUNIT_EXPECT_EQ(test, 0, ret);
snd_soc_unregister_component(test_dev);
}
// TEST CASE
// Test passing NULL fw as parameter to snd_soc_tplg_component_load
/*
* need to override generic probe function with one using NULL pointer to fw
* when calling topology load during component initialization, we don't need
* .remove handler as load should fail
*/
static int d_probe_null_fw(struct snd_soc_component *component)
{
struct kunit_soc_component *kunit_comp =
container_of(component, struct kunit_soc_component, comp);
int ret;
/* instead of passing fw pointer as third argument, pass NULL here */
ret = snd_soc_tplg_component_load(component, NULL, NULL);
KUNIT_EXPECT_EQ_MSG(kunit_comp->kunit, kunit_comp->expect, ret,
"Failed topology load");
return 0;
}
static const struct snd_soc_component_driver test_component_null_fw = {
.name = "sound-soc-topology-test",
.probe = d_probe_null_fw,
.non_legacy_dai_naming = 1,
};
static void snd_soc_tplg_test_load_with_null_fw(struct kunit *test)
{
struct kunit_soc_component *kunit_comp;
int ret;
/* prepare */
kunit_comp = kunit_kzalloc(test, sizeof(*kunit_comp), GFP_KERNEL);
KUNIT_EXPECT_NOT_ERR_OR_NULL(test, kunit_comp);
kunit_comp->kunit = test;
kunit_comp->expect = -EINVAL; /* expect failure */
kunit_comp->card.dev = test_dev,
kunit_comp->card.name = "kunit-card",
kunit_comp->card.owner = THIS_MODULE,
kunit_comp->card.dai_link = kunit_dai_links,
kunit_comp->card.num_links = ARRAY_SIZE(kunit_dai_links),
kunit_comp->card.fully_routed = true,
/* run test */
ret = snd_soc_register_card(&kunit_comp->card);
if (ret != 0 && ret != -EPROBE_DEFER)
KUNIT_FAIL(test, "Failed to register card");
ret = snd_soc_component_initialize(&kunit_comp->comp, &test_component_null_fw, test_dev);
KUNIT_EXPECT_EQ(test, 0, ret);
ret = snd_soc_add_component(&kunit_comp->comp, NULL, 0);
KUNIT_EXPECT_EQ(test, 0, ret);
/* cleanup */
ret = snd_soc_unregister_card(&kunit_comp->card);
KUNIT_EXPECT_EQ(test, 0, ret);
snd_soc_unregister_component(test_dev);
}
/* ===== KUNIT MODULE DEFINITIONS =========================================== */
static struct kunit_case snd_soc_tplg_test_cases[] = {
KUNIT_CASE(snd_soc_tplg_test_load_with_null_comp),
KUNIT_CASE(snd_soc_tplg_test_load_with_null_ops),
KUNIT_CASE(snd_soc_tplg_test_load_with_null_fw),
{}
};
static struct kunit_suite snd_soc_tplg_test_suite = {
.name = "snd_soc_tplg_test",
.init = snd_soc_tplg_test_init,
.exit = snd_soc_tplg_test_exit,
.test_cases = snd_soc_tplg_test_cases,
};
kunit_test_suites(&snd_soc_tplg_test_suite);
MODULE_LICENSE("GPL");