Skip to content

Commit

Permalink
tests: build and run QPP tests
Browse files Browse the repository at this point in the history
These test plugins demonstrate the QPP API changes by exporting
and importing functions and creating and registering callbacks.
These tests are integrated into the `make check-tcg` tests.

This changes the check-tcg target to no longer have a one-to-one
correspondence to plugins in the tests/tcg/plugins directory as the
single qpp test involves both qpp_srv and qpp_client.

Signed-off-by: Elysia Witham <[email protected]>
Signed-off-by: Andrew Fasano <[email protected]>
  • Loading branch information
Elysia Witham authored and Andrew Fasano committed Sep 12, 2024
1 parent 9639ee0 commit 95fa8c5
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 5 deletions.
2 changes: 1 addition & 1 deletion tests/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ $(TCG_TESTS_TARGETS:%=distclean-tcg-tests-%): distclean-tcg-tests-%:
build-tcg: $(BUILD_TCG_TARGET_RULES)

.PHONY: check-tcg
.ninja-goals.check-tcg = all test-plugins
.ninja-goals.check-tcg = all test-plugins test-plugins-qpp
check-tcg: $(RUN_TCG_TARGET_RULES)

.PHONY: clean-tcg
Expand Down
35 changes: 32 additions & 3 deletions tests/tcg/Makefile.target
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,15 @@ ifeq ($(CONFIG_PLUGIN),y)
PLUGIN_SRC=$(SRC_PATH)/tests/tcg/plugins
PLUGIN_LIB=../plugins
VPATH+=$(PLUGIN_LIB)
PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))

ALL_PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))

# Exclude libqpp_srv.so and libqpp_client.so from SINGLE_PLUGINS
SINGLE_PLUGINS=$(filter-out libqpp_srv.so libqpp_client.so, $(ALL_PLUGINS))

# Set PLUGINS to ALL_PLUGINS so that all plugins are built
PLUGINS=$(ALL_PLUGINS)


# We need to ensure expand the run-plugin-TEST-with-PLUGIN
# pre-requistes manually here as we can't use stems to handle it. We
Expand All @@ -155,9 +163,14 @@ PLUGINS=$(patsubst %.c, lib%.so, $(notdir $(wildcard $(PLUGIN_SRC)/*.c)))
# add some special helpers the run-plugin- rules can use below.
# In more, extra tests can be added using ADDITIONAL_PLUGINS_TESTS variable.

# We also add a -with-qpp runner for all tests which tests inter-plugin
# interactions. This is a special case where there isn't a one-to-one
# mapping between tests and plugins.

ifneq ($(MULTIARCH_TESTS),)
$(foreach p,$(PLUGINS), \
$(foreach t,$(MULTIARCH_TESTS) $(ADDITIONAL_PLUGINS_TESTS),\
$(foreach t,$(MULTIARCH_TESTS) $(ADDITIONAL_PLUGINS_TESTS),\
$(eval RUN_TESTS+=run-plugin-$(t)-with-qpp) \
$(foreach p,$(SINGLE_PLUGINS), \
$(eval run-plugin-$(t)-with-$(p): $t $p) \
$(eval RUN_TESTS+=run-plugin-$(t)-with-$(p))))
endif # MULTIARCH_TESTS
Expand All @@ -168,6 +181,22 @@ extract-plugin = $(wordlist 2, 2, $(subst -with-, ,$1))

RUN_TESTS+=$(EXTRA_RUNS)

# The QPP test runs with two plugins, a client and server. It checks
# that they can interact with the QPP protocol.
run-plugin-%-with-qpp: CHECK_PLUGIN_OUTPUT_COMMAND = grep -q 'PASS'
run-plugin-%-with-qpp: hello libqpp_srv.so libqpp_client.so
$(call run-test, $@, \
$(QEMU) -monitor none -display none \
-chardev file$(COMMA)path=$@.out$(COMMA)id=output \
-plugin $(PLUGIN_LIB)/libqpp_srv.so \
-plugin $(PLUGIN_LIB)/libqpp_client.so \
-d plugin -D $*.pout \
$(QEMU_OPTS) $<)
$(if $(CHECK_PLUGIN_OUTPUT_COMMAND), \
$(call quiet-command, $(CHECK_PLUGIN_OUTPUT_COMMAND) $*.pout, \
TEST, check plugin output with $<))


# Some plugins need additional arguments above the default to fully
# exercise things. We can define them on a per-test basis here.
run-plugin-%-with-libmem.so: PLUGIN_ARGS=$(COMMA)inline=true
Expand Down
2 changes: 1 addition & 1 deletion tests/tcg/plugins/meson.build
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
t = []
if get_option('plugins')
foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'syscall']
foreach i : ['bb', 'empty', 'inline', 'insn', 'mem', 'syscall', 'qpp_client', 'qpp_srv']
if host_os == 'windows'
t += shared_module(i, files(i + '.c') + '../../../contrib/plugins/win32_linker.c',
include_directories: '../../../include/qemu',
Expand Down
48 changes: 48 additions & 0 deletions tests/tcg/plugins/qpp_client.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <stdio.h>
#include <qemu-plugin.h>
#include <plugin-qpp.h>
#include <glib.h>

QEMU_PLUGIN_EXPORT const char *qemu_plugin_name = "qpp_client";
QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
QEMU_PLUGIN_EXPORT const char *qemu_plugin_uses[] = {"qpp_srv", NULL};

#include "qpp_srv.h"
static bool pass = true;

void my_cb_exit_callback(gpointer evdata, gpointer udata);

QEMU_PLUGIN_EXPORT void my_cb_exit_callback(gpointer evdata, gpointer udata)
{
// Function is called by qpp_srv, update the evdata to be our 'pass' var
*(bool *)evdata = pass;

g_autoptr(GString) report = g_string_new("QPP client: my_on_exit callback triggered. ");
g_string_append_printf(report, "Setting result=%d\n",pass);
qemu_plugin_outs(report->str);
}

QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
const qemu_info_t *info, int argc, char **argv) {

// Use the QPP interface to run functions in qpp_srv

// Target plugin is 'qpp_srv', we're calling the 'do_add' function and
// we append '_qpp' to the function name to identify it as a QPP function.
// This function is defined in qpp_srv.h
// Ensure that the return value is as expected
if (qpp_srv_do_add_qpp(3) == 4) {
pass &= true;
}

// Now call the 'do_sub' method from qpp_srv and checking the result.
if (qpp_srv_do_sub_qpp(10) == 9) {
pass &= true;
}

// Register a callback to run on a QPP callback provided by qpp_srv
qemu_plugin_reg_callback("qpp_srv", "my_on_exit", &my_cb_exit_callback);

return 0;
}

44 changes: 44 additions & 0 deletions tests/tcg/plugins/qpp_srv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <stdio.h>
#include <qemu-plugin.h>
#include <plugin-qpp.h>
#include <gmodule.h>
#include <assert.h>

QEMU_PLUGIN_EXPORT int qemu_plugin_version = QEMU_PLUGIN_VERSION;
QEMU_PLUGIN_EXPORT const char *qemu_plugin_name = "qpp_srv";
#include "qpp_srv.h"

static void plugin_exit(qemu_plugin_id_t id, void *p)
{
qemu_plugin_outs("qpp_srv: exit triggered, running all registered"
" QPP callbacks\n");

// Trigger all callbacks registered with our custom on_exit callback
// We expect qpp_client to set qpp_client_passed if everything worked

bool qpp_client_passed = false;
qemu_plugin_run_callback(id, "my_on_exit", &qpp_client_passed, NULL);

if (qpp_client_passed) {
qemu_plugin_outs("PASS\n");
} else {
qemu_plugin_outs("FAIL\n");
}
}

QEMU_PLUGIN_EXPORT int qpp_srv_do_add(int x)
{
return x + 1;
}

QEMU_PLUGIN_EXPORT int qpp_srv_do_sub(int x)
{
return x - 1;
}

QEMU_PLUGIN_EXPORT int qemu_plugin_install(qemu_plugin_id_t id,
const qemu_info_t *info, int argc, char **argv) {
qemu_plugin_create_callback(id, "my_on_exit");
qemu_plugin_register_atexit_cb(id, plugin_exit, NULL);
return 0;
}
12 changes: 12 additions & 0 deletions tests/tcg/plugins/qpp_srv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef QPP_SRV_H
#define QPP_SRV_H


/*
* Prototypes for the do_add and do_sub functions. Both return an int and
* take an int as an argument.
*/
QPP_FUN_PROTOTYPE(qpp_srv, int, qpp_srv_do_add, int);
QPP_FUN_PROTOTYPE(qpp_srv, int, qpp_srv_do_sub, int);

#endif /* QPP_SRV_H */

0 comments on commit 95fa8c5

Please sign in to comment.