|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH XTF 3/4] xtf: Add monitor test class
This class starts alongside the domain a monitor application which opens
an event channel corresponding to that domain and handles the received
requests.
Use the "monitor_args" key to pass test specific arguments to the
monitor application.
The arguments will be added in the test's Makefile using the
TEST-EXTRA-INFO variable.
Signed-off-by: Petre Pircalabu <ppircalabu@xxxxxxxxxxxxxxx>
---
Makefile | 6 +-
build/common.mk | 22 ++-
build/files.mk | 3 +
build/gen.mk | 12 ++
docs/all-tests.dox | 5 +
include/monitor/monitor.h | 117 +++++++++++++
monitor/Makefile | 20 +++
monitor/monitor.c | 409 ++++++++++++++++++++++++++++++++++++++++++++++
xtf/__init__.py | 2 +-
xtf/monitor_test.py | 132 +++++++++++++++
xtf/utils.py | 17 ++
11 files changed, 741 insertions(+), 4 deletions(-)
create mode 100644 include/monitor/monitor.h
create mode 100644 monitor/Makefile
create mode 100644 monitor/monitor.c
create mode 100644 xtf/monitor_test.py
create mode 100644 xtf/utils.py
diff --git a/Makefile b/Makefile
index 15a865f..db28075 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,9 @@ INSTALL_PROGRAM := $(INSTALL) -p
OBJCOPY := $(CROSS_COMPILE)objcopy
PYTHON := python
-export CC CPP INSTALL INSTALL_DATA INSTALL_DIR INSTALL_PROGRAM OBJCOPY PYTHON
+HOSTCC := gcc
+
+export CC CPP INSTALL INSTALL_DATA INSTALL_DIR INSTALL_PROGRAM OBJCOPY PYTHON
HOSTCC
.PHONY: all
all:
@@ -51,7 +53,7 @@ install:
done
define all_sources
- find include/ arch/ common/ tests/ -name "*.[hcsS]"
+ find include/ arch/ common/ tests/ monitor/ -name "*.[hcsS]"
endef
.PHONY: cscope
diff --git a/build/common.mk b/build/common.mk
index b786ddf..1ec0fa4 100644
--- a/build/common.mk
+++ b/build/common.mk
@@ -1,4 +1,4 @@
-ALL_CATEGORIES := special functional xsa utility in-development
+ALL_CATEGORIES := special functional xsa utility in-development monitor
ALL_ENVIRONMENTS := pv64 pv32pae hvm64 hvm32pae hvm32pse hvm32
@@ -35,11 +35,20 @@ COMMON_AFLAGS-x86_64 := -m64
COMMON_CFLAGS-x86_32 := -m32
COMMON_CFLAGS-x86_64 := -m64
+#HOSTCFLAGS := -Wall -Werror
+HOSTCFLAGS :=
+HOSTLDFLAGS :=
+HOSTLDLIBS :=
+HOSTCFLAGS += -D__XEN_TOOLS__ -g -O3 -I$(ROOT)/include/monitor
+HOSTCFLAGS += -DXC_WANT_COMPAT_DEVICEMODEL_API
-DXC_WANT_COMPAT_MAP_FOREIGN_API
+HOSTLDLIBS += -lxenctrl -lxenstore -lxenevtchn
+
defcfg-pv := $(ROOT)/config/default-pv.cfg.in
defcfg-hvm := $(ROOT)/config/default-hvm.cfg.in
obj-perarch :=
obj-perenv :=
+obj-monitor :=
include $(ROOT)/build/files.mk
@@ -90,8 +99,19 @@ DEPS-$(1) = $$(head-$(1)) \
endef
+# Setup monitor rules
+define MONITOR_setup
+DEPS-MONITOR = \
+ $$(obj-monitor:%.o=%-monitor.o)
+
+%-monitor.o: %.c
+ $$(HOSTCC) $$(HOSTCFLAGS) -c $$< -o $$@
+endef
+
$(foreach env,$(ALL_ENVIRONMENTS),$(eval $(call PERENV_setup,$(env))))
+$(eval $(call MONITOR_setup))
+
define move-if-changed
if ! cmp -s $(1) $(2); then mv -f $(1) $(2); else rm -f $(1); fi
endef
diff --git a/build/files.mk b/build/files.mk
index dfa27e4..972c797 100644
--- a/build/files.mk
+++ b/build/files.mk
@@ -54,3 +54,6 @@ $(foreach env,$(32BIT_ENVIRONMENTS),$(eval obj-$(env) +=
$(obj-32)))
# 64bit specific objects
obj-64 += $(ROOT)/arch/x86/entry_64.o
$(foreach env,$(64BIT_ENVIRONMENTS),$(eval obj-$(env) += $(obj-64)))
+
+# Monitor common objects
+obj-monitor += $(ROOT)/monitor/monitor.o
diff --git a/build/gen.mk b/build/gen.mk
index c19ca6a..1e6773a 100644
--- a/build/gen.mk
+++ b/build/gen.mk
@@ -32,6 +32,9 @@ CLASS ?= "xtf.domu_test.DomuTestInfo"
.PHONY: build
build: $(foreach env,$(TEST-ENVS),test-$(env)-$(NAME)) $(TEST-CFGS)
build: info.json
+ifeq (x$(CATEGORY),xmonitor)
+build: test-monitor-$(NAME)
+endif
MKINFO-OPTS := -n "$(NAME)"
MKINFO-OPTS += -c "$(CLASS)"
@@ -100,6 +103,15 @@ install-each-env: install-$(1) install-$(1).cfg
endef
$(foreach env,$(TEST-ENVS),$(eval $(call PERENV_build,$(env))))
+define MONITOR_build
+test-monitor-$(NAME): $(DEPS-MONITOR)
+ @echo $(obj-monitor)
+ @echo $(DEPS-MONITOR)
+ $(HOSTCC) $(HOSTLDFLAGS) $(DEPS-MONITOR) $(HOSTLDLIBS) -o $$@
+endef
+
+$(eval $(call MONITOR_build))
+
.PHONY: clean
clean:
find $(ROOT) \( -name "*.o" -o -name "*.d" \) -delete
diff --git a/docs/all-tests.dox b/docs/all-tests.dox
index 732d44c..3ee552e 100644
--- a/docs/all-tests.dox
+++ b/docs/all-tests.dox
@@ -145,4 +145,9 @@ enable BTS.
@subpage test-nested-svm - Nested SVM tests.
@subpage test-nested-vmx - Nested VT-x tests.
+
+
+@section index-monitor Monitor
+
+@subpage test-emul_unimplemented - @Test EMUL_UNIMPLEMENTED event generation
*/
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
new file mode 100644
index 0000000..d01c259
--- /dev/null
+++ b/include/monitor/monitor.h
@@ -0,0 +1,117 @@
+/*
+ * XTF Monitor interface
+ */
+
+#ifndef XTF_MONITOR_H
+#define XTF_MONITOR_H
+
+#include <inttypes.h>
+#include <xenctrl.h>
+#include <xenevtchn.h>
+#include <xenstore.h>
+#include <xen/vm_event.h>
+
+typedef enum
+{
+ XTF_MON_LEVEL_FATAL,
+ XTF_MON_LEVEL_ERROR,
+ XTF_MON_LEVEL_WARNING,
+ XTF_MON_LEVEL_INFO,
+ XTF_MON_LEVEL_DEBUG,
+ XTF_MON_LEVEL_TRACE,
+} xtf_mon_log_level_t;
+
+/* Should be in sync with "test_status" from common/report.c */
+typedef enum {
+ XTF_MON_RUNNING, /**< Test not yet completed. */
+ XTF_MON_SUCCESS, /**< Test was successful. */
+ XTF_MON_SKIP, /**< Test cannot be completed. */
+ XTF_MON_ERROR, /**< Issue with the test itself. */
+ XTF_MON_FAILURE, /**< Issue with the tested matter. */
+} xtf_mon_status_t;
+
+void xtf_log(xtf_mon_log_level_t lvl, const char *fmt, ...)
__attribute__((__format__(__printf__, 2, 3)));
+
+#define XTF_MON_FATAL(format...) xtf_log(XTF_MON_LEVEL_FATAL, format)
+#define XTF_MON_ERROR(format...) xtf_log(XTF_MON_LEVEL_ERROR, format)
+#define XTF_MON_WARNING(format...) xtf_log(XTF_MON_LEVEL_WARNING, format)
+#define XTF_MON_INFO(format...) xtf_log(XTF_MON_LEVEL_INFO, format)
+#define XTF_MON_DEBUG(format...) xtf_log(XTF_MON_LEVEL_DEBUG, format)
+#define XTF_MON_TRACE(format...) xtf_log(XTF_MON_LEVEL_TRACE, format)
+
+typedef struct xtf_evtchn_ops
+{
+ int (*mem_access_handler)(domid_t domain_id, vm_event_request_t *req,
vm_event_response_t *rsp);
+ int (*singlestep_handler)(domid_t domain_id, vm_event_request_t *req,
vm_event_response_t *rsp);
+ int (*emul_unimpl_handler)(domid_t domain_id, vm_event_request_t *req,
vm_event_response_t *rsp);
+} xtf_evtchn_ops_t;
+
+/** XTF Event channel interface */
+typedef struct xtf_evtchn
+{
+ xenevtchn_handle *xce_handle; /**< Event channel handle */
+ xenevtchn_port_or_error_t remote_port; /**< Event channel remote port */
+ evtchn_port_t local_port; /**< Event channel local port */
+ vm_event_back_ring_t back_ring; /**< vm_event back ring */
+ void *ring_page; /**< Shared ring page */
+ xtf_evtchn_ops_t ops; /**< Test specific event callbacks
*/
+} xtf_evtchn_t;
+
+int add_evtchn(xtf_evtchn_t *evt, domid_t domain_id);
+xtf_evtchn_t *get_evtchn(domid_t domain_id);
+#define evtchn(domain_id) ( get_evtchn(domain_id) )
+
+/** XTF Monitor Driver */
+typedef struct xtf_monitor
+{
+ xc_interface *xch; /**< Control interface */
+ struct xs_handle *xsh; /**< XEN store handle */
+ xtf_evtchn_t *evt; /**< Event channel list */
+ xtf_mon_log_level_t log_lvl; /**< Log Level */
+ xtf_mon_status_t status; /**< Test Status */
+ int (*setup)(int, char*[]); /**< Test specific setup */
+ int (*init)(void); /**< Test specific initialization
*/
+ int (*run)(void); /**< Test specific routine */
+ int (*cleanup)(void); /**< Test specific cleanup */
+ int (*get_result)(void); /**< Returns the test's result */
+} xtf_monitor_t;
+
+xtf_monitor_t *get_monitor();
+#define monitor ( get_monitor() )
+#define xtf_xch ( monitor->xch )
+#define xtf_xsh ( monitor->xsh )
+
+#define call_helper(func, ... ) ( (func) ? func(__VA_ARGS__) : 0 )
+#define xtf_monitor_setup(argc, argv) ( call_helper(monitor->setup, argc,
argv) )
+#define xtf_monitor_init() ( call_helper(monitor->init) )
+#define xtf_monitor_run() ( call_helper(monitor->run) )
+#define xtf_monitor_cleanup() ( call_helper(monitor->cleanup) )
+#define xtf_monitor_get_result() ( call_helper(monitor->get_result) )
+
+int xtf_evtchn_init(domid_t domain_id);
+int xtf_evtchn_cleanup(domid_t domain_id);
+int xtf_evtchn_loop(domid_t domain_id);
+
+extern const char monitor_test_help[];
+
+void usage();
+
+extern xtf_monitor_t *xtf_monitor_instance;
+
+#define XTF_MONITOR(param) \
+static void __attribute__((constructor)) register_monitor_##param() \
+{ \
+ xtf_monitor_instance = (xtf_monitor_t *)¶m; \
+}
+
+#endif /* XTF_MONITOR_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/monitor/Makefile b/monitor/Makefile
new file mode 100644
index 0000000..64d4f8a
--- /dev/null
+++ b/monitor/Makefile
@@ -0,0 +1,20 @@
+.PHONY: all
+
+all: monitor
+
+HOSTCC ?= gcc
+
+OBJS = monitor.o
+
+#HOSTCFLAGS += -Wall -Werror
+HOSTCFLAGS += -D__XEN_TOOLS__ -g -O0
+HOSTCFLAGS += -DXC_WANT_COMPAT_DEVICEMODEL_API -DXC_WANT_COMPAT_MAP_FOREIGN_API
+
+%.o : %.c
+ $(HOSTCC) -c $(HOSTCFLAGS) $(HOSTCPPFLAGS) $< -o $@
+
+monitor: $(OBJS)
+ $(HOSTCC) -o $@ $^ -lxenctrl -lxenstore -lxenevtchn
+
+clean:
+ $(RM) $(OBJS) monitor
diff --git a/monitor/monitor.c b/monitor/monitor.c
new file mode 100644
index 0000000..943ff35
--- /dev/null
+++ b/monitor/monitor.c
@@ -0,0 +1,409 @@
+/**
+ * @file monitor/monitor.c
+ *
+ * Common functions for test specific monitor applications.
+ */
+
+#include <errno.h>
+#include <monitor.h>
+#include <poll.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+
+void xtf_log(xtf_mon_log_level_t lvl, const char *fmt, ...)
+{
+ static const char* log_level_names[] = {
+ "FATAL",
+ "ERROR",
+ "WARNING",
+ "INFO",
+ "DEBUG",
+ "TRACE",
+ };
+
+ if ( lvl <= monitor->log_lvl )
+ {
+ va_list argptr;
+
+ fprintf(stderr, "[%s]\t", log_level_names[lvl]);
+ va_start(argptr, fmt);
+ vfprintf(stderr, fmt, argptr);
+ va_end(argptr);
+ }
+}
+
+static void xtf_print_status(xtf_mon_status_t status)
+{
+ const char *xtf_mon_status_name[] =
+ {
+ "RUNNING",
+ "SUCCESS",
+ "SKIP",
+ "ERROR",
+ "FAILURE"
+ };
+
+ if ( status > XTF_MON_RUNNING && status <= XTF_MON_FAILURE )
+ {
+ printf("Test result: %s\n", xtf_mon_status_name[status]);
+ }
+}
+
+void usage()
+{
+ fprintf(stderr, "%s", monitor_test_help);
+}
+
+xtf_monitor_t *xtf_monitor_instance;
+xtf_monitor_t *get_monitor()
+{
+ return xtf_monitor_instance;
+}
+
+xtf_evtchn_t *get_evtchn(domid_t domain_id)
+{
+ (void)(domain_id);
+ return monitor->evt;
+}
+
+int add_evtchn(xtf_evtchn_t *evt, domid_t domain_id)
+{
+ (void)(domain_id);
+ monitor->evt = evt;
+}
+
+int xtf_evtchn_init(domid_t domain_id)
+{
+ int rc;
+ xtf_evtchn_t *evt = evtchn(domain_id);
+
+ if ( !evt )
+ {
+ XTF_MON_ERROR("Invalid event channel\n");
+ return -EINVAL;
+ }
+
+ evt->ring_page = xc_monitor_enable(monitor->xch, domain_id,
+ &evt->remote_port);
+ if ( !evt->ring_page )
+ {
+ XTF_MON_ERROR("Error enabling monitor\n");
+ return -1;
+ }
+
+ evt->xce_handle = xenevtchn_open(NULL, 0);
+ if ( !evt->xce_handle )
+ {
+ XTF_MON_ERROR("Failed to open XEN event channel\n");
+ return -1;
+ }
+
+ rc = xenevtchn_bind_interdomain(evt->xce_handle, domain_id,
+ evt->remote_port);
+ if ( rc < 0 )
+ {
+ XTF_MON_ERROR("Failed to bind XEN event channel\n");
+ return rc;
+ }
+ evt->local_port = rc;
+
+ /* Initialise ring */
+ SHARED_RING_INIT((vm_event_sring_t *)evt->ring_page);
+ BACK_RING_INIT(&evt->back_ring, (vm_event_sring_t *)evt->ring_page,
+ XC_PAGE_SIZE);
+
+ return 0;
+}
+
+int xtf_evtchn_cleanup(domid_t domain_id)
+{
+ int rc;
+ xtf_evtchn_t *evt = evtchn(domain_id);
+
+ if ( !evt )
+ return -EINVAL;
+
+ if ( evt->ring_page )
+ munmap(evt->ring_page, XC_PAGE_SIZE);
+
+ rc = xc_monitor_disable(monitor->xch, domain_id);
+ if ( rc != 0 )
+ {
+ XTF_MON_INFO("Error disabling monitor\n");
+ return rc;
+ }
+
+ rc = xenevtchn_unbind(evt->xce_handle, evt->local_port);
+ if ( rc != 0 )
+ {
+ XTF_MON_INFO("Failed to unbind XEN event channel\n");
+ return rc;
+ }
+
+ rc = xenevtchn_close(evt->xce_handle);
+ if ( rc != 0 )
+ {
+ XTF_MON_INFO("Failed to close XEN event channel\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int xtf_wait_for_event(domid_t domain_id, xc_interface *xch,
xenevtchn_handle *xce, unsigned long ms)
+{
+ struct pollfd fds[2] = {
+ { .fd = xenevtchn_fd(xce), .events = POLLIN | POLLERR },
+ { .fd = xs_fileno(monitor->xsh), .events = POLLIN | POLLERR },
+ };
+ int port;
+ int rc;
+
+ rc = poll(fds, 2, ms);
+
+ if ( rc < 0 )
+ return -errno;
+
+ if ( rc == 0 )
+ return 0;
+
+ if ( fds[0].revents )
+ {
+ port = xenevtchn_pending(xce);
+ if ( port == -1 )
+ return -errno;
+
+ rc = xenevtchn_unmask(xce, port);
+ if ( rc != 0 )
+ return -errno;
+
+ return port;
+ }
+
+ if ( fds[1].revents )
+ {
+ if ( !xs_is_domain_introduced(monitor->xsh, domain_id) )
+ {
+ return 1;
+ }
+
+ return 0;
+ }
+
+ return -2; /* Error */
+}
+
+static void xtf_evtchn_get_request(xtf_evtchn_t *evt, vm_event_request_t *req)
+{
+ vm_event_back_ring_t *back_ring;
+ RING_IDX req_cons;
+
+ back_ring = &evt->back_ring;
+ req_cons = back_ring->req_cons;
+
+ /* Copy request */
+ memcpy(req, RING_GET_REQUEST(back_ring, req_cons), sizeof(*req));
+ req_cons++;
+
+ /* Update ring */
+ back_ring->req_cons = req_cons;
+ back_ring->sring->req_event = req_cons + 1;
+}
+
+static void xtf_evtchn_put_response(xtf_evtchn_t *evt, vm_event_response_t
*rsp)
+{
+ vm_event_back_ring_t *back_ring;
+ RING_IDX rsp_prod;
+
+ back_ring = &evt->back_ring;
+ rsp_prod = back_ring->rsp_prod_pvt;
+
+ /* Copy response */
+ memcpy(RING_GET_RESPONSE(back_ring, rsp_prod), rsp, sizeof(*rsp));
+ rsp_prod++;
+
+ /* Update ring */
+ back_ring->rsp_prod_pvt = rsp_prod;
+ RING_PUSH_RESPONSES(back_ring);
+}
+
+int xtf_evtchn_loop(domid_t domain_id)
+{
+ vm_event_request_t req;
+ vm_event_response_t rsp;
+ int rc;
+ xtf_evtchn_t *evt = evtchn(domain_id);
+
+ if ( !evt )
+ return -EINVAL;
+
+ printf("Monitor initialization complete.\n");
+
+ for (;;)
+ {
+ rc = xtf_wait_for_event(domain_id, xtf_xch, evt->xce_handle, 100);
+ if ( rc < -1 )
+ {
+ XTF_MON_ERROR("Error getting event");
+ return rc;
+ }
+ else if ( rc == 1 )
+ {
+ XTF_MON_INFO("Domain %d exited\n", domain_id);
+ return 0;
+ }
+
+ while ( RING_HAS_UNCONSUMED_REQUESTS(&evt->back_ring) )
+ {
+ xtf_evtchn_get_request(evt, &req);
+
+ if ( req.version != VM_EVENT_INTERFACE_VERSION )
+ {
+ XTF_MON_ERROR("Error: vm_event interface version mismatch!\n");
+ return -1;
+ }
+
+ memset( &rsp, 0, sizeof (rsp) );
+ rsp.version = VM_EVENT_INTERFACE_VERSION;
+ rsp.vcpu_id = req.vcpu_id;
+ rsp.flags = (req.flags & VM_EVENT_FLAG_VCPU_PAUSED);
+ rsp.reason = req.reason;
+
+ rc = 0;
+
+ switch (req.reason)
+ {
+ case VM_EVENT_REASON_MEM_ACCESS:
+ XTF_MON_DEBUG("mem_access rip = %016lx gfn = %lx offset = %lx
gla =%lx\n",
+ req.data.regs.x86.rip,
+ req.u.mem_access.gfn,
+ req.u.mem_access.offset,
+ req.u.mem_access.gla);
+
+ if ( evt->ops.mem_access_handler )
+ rc = evt->ops.mem_access_handler(domain_id, &req, &rsp);
+ break;
+ case VM_EVENT_REASON_SINGLESTEP:
+ XTF_MON_DEBUG("Singlestep: rip=%016lx, vcpu %d, altp2m %u\n",
+ req.data.regs.x86.rip,
+ req.vcpu_id,
+ req.altp2m_idx);
+ if ( evt->ops.singlestep_handler )
+ rc = evt->ops.singlestep_handler(domain_id, &req, &rsp);
+ break;
+ case VM_EVENT_REASON_EMUL_UNIMPLEMENTED:
+ XTF_MON_DEBUG("Emulation unimplemented: rip=%016lx, vcpu
%d:\n",
+ req.data.regs.x86.rip,
+ req.vcpu_id);
+ if ( evt->ops.emul_unimpl_handler )
+ rc = evt->ops.emul_unimpl_handler(domain_id, &req, &rsp);
+ break;
+ default:
+ XTF_MON_ERROR("Unknown request id = %d\n", req.reason);
+ }
+
+ if ( rc )
+ return rc;
+
+ /* Put the response on the ring */
+ xtf_evtchn_put_response(evt, &rsp);
+ }
+ /* Tell Xen page is ready */
+ rc = xenevtchn_notify(evt->xce_handle, evt->local_port);
+
+ if ( rc != 0 )
+ {
+ XTF_MON_ERROR("Error resuming page");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+int main(int argc, char* argv[])
+{
+ int rc;
+
+ monitor->status = XTF_MON_RUNNING;
+ monitor->log_lvl = XTF_MON_LEVEL_ERROR;
+
+ /* test specific setup sequence */
+ rc = xtf_monitor_setup(argc, argv);
+ if ( rc )
+ {
+ monitor->status = XTF_MON_ERROR;
+ goto e_exit;
+ }
+
+ monitor->xch = xc_interface_open(NULL, NULL, 0);
+ if ( !monitor->xch )
+ {
+ XTF_MON_FATAL("Error initialising xenaccess\n");
+ rc = -EINVAL;
+ monitor->status = XTF_MON_ERROR;
+ goto e_exit;
+ }
+
+ monitor->xsh = xs_open(XS_OPEN_READONLY);
+ if ( !monitor->xsh )
+ {
+ XTF_MON_FATAL("Error opening XEN store\n");
+ rc = -EINVAL;
+ monitor->status = XTF_MON_ERROR;
+ goto cleanup;
+ }
+
+ if ( !xs_watch( monitor->xsh, "@releaseDomain", "RELEASE_TOKEN") )
+ {
+ XTF_MON_FATAL("Error monitoring releaseDomain\n");
+ rc = -EINVAL;
+ monitor->status = XTF_MON_ERROR;
+ goto cleanup;
+ }
+
+ /* test specific initialization sequence */
+ rc = xtf_monitor_init();
+ if ( rc )
+ {
+ monitor->status = XTF_MON_ERROR;
+ goto cleanup;
+ }
+
+ /* Run test */
+ rc = xtf_monitor_run();
+ if ( rc )
+ {
+ XTF_MON_ERROR("Error running test\n");
+ monitor->status = XTF_MON_ERROR;
+ }
+
+ monitor->status = xtf_monitor_get_result();
+
+cleanup:
+ /* test specific cleanup sequence */
+ xtf_monitor_cleanup();
+ if ( monitor->xsh )
+ {
+ xs_unwatch(monitor->xsh, "@releaseDomain", "RELEASE_TOKEN");
+ xs_close(monitor->xsh);
+ monitor->xsh = NULL;
+ }
+
+ xc_interface_close(monitor->xch);
+
+e_exit:
+ xtf_print_status(monitor->status);
+ return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xtf/__init__.py b/xtf/__init__.py
index 07c269a..e405013 100644
--- a/xtf/__init__.py
+++ b/xtf/__init__.py
@@ -3,7 +3,7 @@
# All test categories
default_categories = set(("functional", "xsa"))
-non_default_categories = set(("special", "utility", "in-development", "host"))
+non_default_categories = set(("special", "utility", "in-development", "host",
"monitor"))
all_categories = default_categories | non_default_categories
# All test environments
diff --git a/xtf/monitor_test.py b/xtf/monitor_test.py
new file mode 100644
index 0000000..b9b010e
--- /dev/null
+++ b/xtf/monitor_test.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+""" Monitor test classes.
+
+ The monitor test spawns an test monitor (event channel handler application)
+ instance and runs a DomU image which interacts with it.
+"""
+
+import os
+from subprocess import Popen
+
+from xtf.exceptions import RunnerError
+from xtf.domu_test import DomuTestInstance, DomuTestInfo
+from xtf.executable_test import ExecutableTestInstance
+from xtf.logger import Logger
+from xtf.test import TestResult, TestInstance
+from xtf.utils import XTFAsyncCall
+
+class MonitorTestInstance(TestInstance):
+ """Monitor test instance"""
+
+ def __init__(self, env, name, variation, monitor_args):
+ super(MonitorTestInstance, self).__init__(name)
+
+ self.env, self.variation = env, variation
+
+ if self.env is None:
+ raise RunnerError("No environment for '%s'" % (self.name, ))
+
+ self.monitor_args = monitor_args.replace("@@VM_PATH@@", self.vm_path())
+
+ self.domu_test = None
+ self.monitor_test = None
+
+ def vm_name(self):
+ """ Return the VM name as `xl` expects it. """
+ return repr(self)
+
+ def cfg_path(self):
+ """ Return the path to the `xl` config file for this test. """
+ return os.path.join("tests", self.name, repr(self) + ".cfg")
+
+ def __repr__(self):
+ if self.variation:
+ return "test-%s-%s~%s" % (self.env, self.name, self.variation)
+ return "test-%s-%s" % (self.env, self.name)
+
+ def vm_path(self):
+ """ Return the VM path. """
+ return os.path.join("tests", self.name, repr(self))
+
+ def monitor_path(self):
+ """ Return the path to the test's monitor app if applicable. """
+ return os.path.join("tests", self.name, "test-monitor-" + self.name)
+
+ def start_monitor(self, dom_id):
+ """ Starts the monitor application. """
+ cmd = [" ".join([self.monitor_path(), self.monitor_args, str(dom_id)])]
+ Logger().log("Executing '%s'" % (" ".join(cmd), ))
+ return Popen(cmd, shell=True)
+
+ def set_up(self, opts, result):
+ self.domu_test = DomuTestInstance(self.env, self.name, self.variation)
+ self.domu_test.set_up(opts, result)
+ if result != TestResult.SUCCESS:
+ return
+
+ monitor_cmd = ' '.join([self.monitor_path(), self.monitor_args,
+ str(self.domu_test.domu.dom_id)])
+
+ self.monitor_test = ExecutableTestInstance(self.name, '/bin/sh',
+ ['-c', monitor_cmd], "")
+ self.monitor_test.set_up(opts, result)
+ match = self.monitor_test.wait_pattern(['Monitor initialization
complete.'])
+ if match != 0:
+ result.set(TestResult.CRASH)
+
+ def run(self, result):
+ t1 = XTFAsyncCall(target=self.domu_test.run, args=(result,))
+ t2 = XTFAsyncCall(target=self.monitor_test.wait_pattern,
+ args=(self.result_pattern(), ))
+
+ for th in (t1, t2):
+ th.start()
+
+ t1.join()
+ res = TestResult(t2.join())
+ if res > result:
+ result.set(str(res))
+
+
+ def clean_up(self, result):
+ if self.domu_test:
+ self.domu_test.clean_up(result)
+
+ if self.monitor_test:
+ self.monitor_test.clean_up(result)
+
+class MonitorTestInfo(DomuTestInfo):
+ """Monitor test info"""
+
+ def __init__(self, test_json):
+ super(MonitorTestInfo, self).__init__(test_json)
+ self.instance_class = MonitorTestInstance
+ self.monitor_args = self.extra['monitor_args']
+
+ def all_instances(self, env_filter = None, vary_filter = None):
+ """Return a list of TestInstances, for each supported environment.
+ Optionally filtered by env_filter. May return an empty list if
+ the filter doesn't match any supported environment.
+ """
+
+ if env_filter:
+ envs = set(env_filter).intersection(self.envs)
+ else:
+ envs = self.envs
+
+ if vary_filter:
+ variations = set(vary_filter).intersection(self.variations)
+ else:
+ variations = self.variations
+
+ res = []
+ if variations:
+ for env in envs:
+ for vary in variations:
+ res.append(self.instance_class(env, self.name, vary,
+ self.monitor_args))
+ else:
+ res = [ self.instance_class(env, self.name, None,
self.monitor_args)
+ for env in envs ]
+ return res
diff --git a/xtf/utils.py b/xtf/utils.py
new file mode 100644
index 0000000..96c570b
--- /dev/null
+++ b/xtf/utils.py
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+""" XTF utils """
+
+import threading
+
+class XTFAsyncCall(threading.Thread):
+ def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
+ super(XTFAsyncCall, self).__init__(group, target, name, args, kwargs)
+ self._return = None
+ def run(self):
+ if self._Thread__target is not None:
+ self._return = self._Thread__target(*self._Thread__args,
+ **self._Thread__kwargs)
+ def join(self):
+ threading.Thread.join(self)
+ return self._return
--
2.7.4
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |