[CRIU] [PATCH] test: add rpc tests
Andrew Vagin
avagin at parallels.com
Sun Sep 15 10:28:57 EDT 2013
On Sat, Sep 14, 2013 at 09:43:44PM +0400, Ruslan Kuprieiev wrote:
> 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>
>
Offtop: Do you try to send message from non-leader thread? What do we
expect in this case?
> 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
Can we save all test files in one directory?
> 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
./test-c
my_exit $?
> +
> +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
Where do you check that the origin process was completed? If it is not,
restore will fail, because the pid is busy.
> +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
The python test always returns 0
> +
> +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)
Can we return CriuDumpResp *resp?
static CriuDumpResp *resp recv_resp(int sk)
> +{
> + 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
Where is this module?
> +
> +# 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'
sys.exit(1)
> +else:
> + if msg_resp.dump_resp.success:
> + print 'Success'
> + else:
> + print 'Fail'
> +
> + if msg_resp.dump_resp.restored:
> + print 'Restored'
>
> _______________________________________________
> CRIU mailing list
> CRIU at openvz.org
> https://lists.openvz.org/mailman/listinfo/criu
More information about the CRIU
mailing list