[CRIU] [PATCH] test: add rpc tests

Ruslan Kuprieiev kupruser at gmail.com
Sat Sep 14 13:43:44 EDT 2013


Hi!

This patch provides tests(in C and Python) of rpc, that can be used as 
examples.
Also, it contains shell script to automatize testing.

This patch requires patch "rpc: change some "required" fields to 
"optional" and rename rpc.proto to criu-rpc.proto" by Ruslan Kuprieiev.

Signed-off-by: Ruslan Kuprieiev <kupruser at gmail.com>

-------------- next part --------------
diff --git a/test/rpc/Makefile b/test/rpc/Makefile
new file mode 100644
index 0000000..726fd21
--- /dev/null
+++ b/test/rpc/Makefile
@@ -0,0 +1,20 @@
+all: test-c criu-rpc_pb2.py
+
+test-c: criu-rpc.pb-c.o test.o
+	gcc $^ -o test-c -lprotobuf-c
+
+#FIXME protoc*
+criu-rpc_pb2.py: ../../protobuf/criu-rpc.proto
+	protoc --proto_path=$(CURDIR)/../../protobuf/ --python_out=. $(CURDIR)/../../protobuf/criu-rpc.proto
+
+criu-rpc.pb-c.c: ../../protobuf/criu-rpc.proto
+	protoc-c --proto_path=$(CURDIR)/../../protobuf/ --c_out=. $(CURDIR)/../../protobuf/criu-rpc.proto
+
+clean:
+	rm -f *.o
+	rm -f criu*
+	rm -f test-c
+	rm -f _*
+	rm -rf imgs_*
+	rm -f *.log
+	rm -f *.socket
diff --git a/test/rpc/run.sh b/test/rpc/run.sh
new file mode 100755
index 0000000..17f0f09
--- /dev/null
+++ b/test/rpc/run.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+source ../env.sh || exit 1
+
+function my_print {
+	echo -e "\n**************************************************"
+	echo -e "\t\t"$1
+	echo -e "**************************************************\n"
+
+}
+
+function my_exit {
+	if [ $1 -ne 0 ]; then
+		echo FAIL
+	fi
+
+	my_print "Shutdown service server"
+	kill -SIGTERM ${SRV_PID}
+
+	exit $1
+}
+
+IMGS_DIR_C="imgs_c"
+IMGS_DIR_PY="imgs_py"
+SERV_LOG="service.log"
+REST_C_LOG="restore-c.log"
+REST_PY_LOG="restore-py.log"
+
+my_print "Build services"
+make clean && make || { echo "Failed to build"; exit 1; }
+if [ $? -ne 0 ]; then
+	echo FAIL
+	exit 1
+fi
+rm -rf ${IMGS_DIR_C} ${IMGS_DIR_PY} ${REST_LOG_C} ${REST_LOG_PY}
+mkdir ${IMGS_DIR_C} ${IMGS_DIR_PY}
+
+my_print "Start service server"
+setsid ${CRIU} service -v4 -o ${SERV_LOG} --address ./criu_service.socket &
+SRV_PID=${!}
+if [ $? -ne 0 ]; then
+	echo FAIL
+	exit 1
+fi
+echo PID ${SRV_PID}
+sleep 1 #server needs some time to initialize
+
+my_print "Run test-c"
+./test-c
+if [ $? -ne 0 ]; then
+	my_exit 1
+fi
+
+my_print "Run test-py"
+./test.py
+if [ $? -ne 0 ]; then
+	my_exit 1
+fi
+
+my_print "Restore test-c"
+${CRIU} restore -v4 -o ${REST_C_LOG} -D ./imgs_c --shell-job
+if [ $? -ne 0 ]; then
+	my_exit 1
+fi
+
+my_print "Restore test-py"
+${CRIU} restore -v4 -o ${REST_PY_LOG} -D ./imgs_py --shell-job
+if [ $? -ne 0 ]; then
+	my_exit 1
+fi
+
+my_exit 0
diff --git a/test/rpc/test.c b/test/rpc/test.c
new file mode 100644
index 0000000..b67c082
--- /dev/null
+++ b/test/rpc/test.c
@@ -0,0 +1,160 @@
+#include "criu-rpc.pb-c.h"
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/fcntl.h>
+#include <stdio.h>
+
+#define MAX_MSG_SIZE 1024
+
+/*
+ * recv_resp() reads criu msg from the socket,
+ * unpacks it and unwraps a dump response.
+ */
+
+static int recv_resp(int fd, CriuDumpResp **resp)
+{
+	unsigned char buf[MAX_MSG_SIZE];
+	int len;
+
+	CriuMsg *msg = 0;
+
+	len = read(fd, buf, MAX_MSG_SIZE);
+	if (len == -1) {
+		perror("Can't read resp");
+		return -1;
+	}
+
+	msg = criu_msg__unpack(NULL, len, buf);
+	if (!msg) {
+		perror("Failed unpacking resp");
+		return -1;
+	}
+
+	if (msg->type == CRIU_MSG__TYPE__DUMPRESP)
+		*resp = msg->dump_resp;
+	else {
+		perror("Unexpected msg type");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * send_req gets dump request as an argument,
+ * wraps it into criu msg and writes it to the socket
+ */
+
+static int send_req(int fd, CriuDumpReq *req)
+{
+	unsigned char buf[MAX_MSG_SIZE];
+	int len;
+
+	CriuMsg msg = CRIU_MSG__INIT;
+	msg.dump_req = req;
+	msg.type = CRIU_MSG__TYPE__DUMPREQ;
+
+	len = criu_msg__get_packed_size(&msg);
+
+	if (criu_msg__pack(&msg, buf) != len) {
+		perror("Failed packing request");
+		return -1;
+	}
+
+	if (write(fd, buf, len)  == -1) {
+		perror("Can't send request");
+		return -1;
+	}
+
+	return 0;
+}
+
+int main()
+{
+	CriuDumpReq req		= CRIU_DUMP_REQ__INIT;
+	CriuDumpResp *resp	= NULL;
+	int fd, dir_fd;
+	int ret = 0;
+	struct sockaddr_un addr;
+	socklen_t addr_len;
+
+	/*
+	 * Open a directory, in which criu will
+	 * put images
+	 */
+	dir_fd = open("./imgs_c", O_DIRECTORY);
+	if (dir_fd == -1) {
+		perror("Can't open dir");
+		return -1;
+	}
+
+	/*
+	 * Set dump options.
+	 * Checkout more in protobuf/criu-rpc.proto.
+	 */
+	req.has_leave_running	= true;
+	req.leave_running	= true;
+	req.images_dir_fd	= dir_fd;
+	req.has_shell_job	= true;
+	req.shell_job		= true;
+
+	/*
+	 * Connect to service socket
+	 */
+	fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
+	if (fd == -1) {
+		perror("Can't create socket");
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_LOCAL;
+	strcpy(addr.sun_path, "./criu_service.socket");
+
+	addr_len = strlen(addr.sun_path) + sizeof(addr.sun_family);
+
+	ret = connect(fd, (struct sockaddr *) &addr, addr_len);
+	if (ret == -1) {
+		perror("Cant connect to socket");
+		goto exit;
+	}
+
+	/*
+	 * Send dump request
+	 */
+	ret = send_req(fd, &req);
+	if (ret == -1) {
+		perror("Can't send request");
+		goto exit;
+	}
+
+	/*
+	 * Recv dump response
+	 */
+	ret = recv_resp(fd, &resp);
+	if (ret == -1) {
+		perror("Can't recv response");
+		goto exit;
+	}
+
+	/*
+	 * Check response.
+	 */
+	if (resp->success)
+		puts("Success");
+	else {
+		puts("Fail");
+		ret = -1;
+		goto exit;
+	}
+
+	if (resp->has_restored && resp->restored)
+		puts("Restored");
+
+exit:
+	close(fd);
+	close(dir_fd);
+	criu_dump_resp__free_unpacked(resp, NULL);
+	return ret;
+}
diff --git a/test/rpc/test.py b/test/rpc/test.py
new file mode 100755
index 0000000..74f0830
--- /dev/null
+++ b/test/rpc/test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+
+import socket, os
+import criu_rpc_pb2
+
+# Connect to service socket
+s = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
+s.connect('./criu_service.socket')
+
+# Create criu msg, set it's type to dump request
+# and set dump options
+msg_req		= criu_rpc_pb2.criu_msg()
+msg_req.type	= criu_rpc_pb2.criu_msg.DUMPREQ
+msg_req.dump_req.leave_running	= True
+msg_req.dump_req.shell_job	= True
+msg_req.dump_req.images_dir_fd	= os.open('./imgs_py', os.O_DIRECTORY)
+
+# Send criu msg with request
+s.send(msg_req.SerializeToString())
+
+# Recv criu msg with response
+msg_resp	= criu_rpc_pb2.criu_msg()
+MAX_MSG_SIZE = 1024
+msg_resp.ParseFromString(s.recv(MAX_MSG_SIZE))
+
+if msg_resp.type != criu_rpc_pb2.criu_msg.DUMPRESP:
+	print 'Unexpected msg type'
+else:
+	if msg_resp.dump_resp.success:
+		print 'Success'
+	else:
+		print 'Fail'
+
+	if msg_resp.dump_resp.restored:
+		print 'Restored'



More information about the CRIU mailing list