[CRIU] [PATCHv2 2/2] test/others/leave-stopped: implement test for new --leave-stopped option
Pavel Emelyanov
xemul at virtuozzo.com
Fri May 20 06:50:28 PDT 2016
On 05/20/2016 04:31 PM, Batalov Eugene wrote:
>
> 2016-05-20 16:12 GMT+03:00 Pavel Emelyanov <xemul at virtuozzo.com <mailto:xemul at virtuozzo.com>>:
>
> On 05/20/2016 02:31 PM, Batalov Eugene wrote:
> >
> >
> > 2016-05-20 14:23 GMT+03:00 Pavel Emelyanov <xemul at virtuozzo.com <mailto:xemul at virtuozzo.com> <mailto:xemul at virtuozzo.com <mailto:xemul at virtuozzo.com>>>:
> >
> > On 05/02/2016 06:46 PM, Eugene Batalov wrote:
> > > From: Kravchenko Dmitrii <equivalence1 at gmail.com <mailto:equivalence1 at gmail.com> <mailto:equivalence1 at gmail.com <mailto:equivalence1 at gmail.com>>>
> > >
> > > This patch implements a simple autotest for new --leave-stopped CRIU
> > > restorer option. Test creates ps tree then checkpoints it.
> > > Then test restores ps tree with --leave-stopped option.
> > > Then test checks that every process in restored ps tree is in
> > > stopped state.
> > >
> > > Signed-off-by: Kravchenko Dmitrii <equivalence1 at gmail.com <mailto:equivalence1 at gmail.com> <mailto:equivalence1 at gmail.com <mailto:equivalence1 at gmail.com>>>
> > > Signed-off-by: Eugene Batalov <eabatalov89 at gmail.com <mailto:eabatalov89 at gmail.com> <mailto:eabatalov89 at gmail.com <mailto:eabatalov89 at gmail.com>>>
> > > ---
> > > test/others/leave-stopped/.gitignore | 3 ++
> > > test/others/leave-stopped/Makefile | 7 +++++
> > > test/others/leave-stopped/pstree.c | 39 +++++++++++++++++++++++++
> > > test/others/leave-stopped/run.sh | 31 ++++++++++++++++++++
> > > test/others/leave-stopped/tree_checker.py | 47 +++++++++++++++++++++++++++++++
> >
> > Oh :( Is there any chance to have this as a part of zdtm.py suite?
> >
> >
> > We need to restore the whole ps tree in stopped state so ps tree can't validate itself after restore.
>
> Of course. This should be a mode when zdtm.py passes --leave-stopped to criu restore (and
> criu dump actually too :) ) and before checking the results SIGCONTs the tree.
>
> We should check state of all the restored processes in ps tree before we SIGCONT them.
> Please read my comment below for continuation of my point.
>
>
>
> > I think there should be some file in CRIU test suite where we can add new shell command to run our non-zdtm style test.
> > But we haven't found such a file.
> > Do you have such a shell script? Should we implement such a file?
>
> Nope :( But this can be solved by calling "crit x ps" -- it will show all the pids
> from the image file.
>
> In our test we traverse restored ps tree from root to children and check each process state to be stopped.
> So I don't see a big need to use additional component such as crit in our test (but crit ps based check is more strict).
>
> The question is how would we integrate our test/others/leave-stopped script into zdtm test suite?
I thought that you don't :) Instead, you can take the zdtm/transition/fork test, C/R it
with --leave-stopped, check that it is stopped, SIGCONT the tree and check the result.
The same can be done with any zdtm/ micro-test, but presumably it only makes sense to
regularly test only the fork one.
> The cleanest way is to just call our test script from zdtm and let our test script do all the work.
> I mean it looks like there is no need to add more code into zdtm.py.
> It is complicated thing already so I prefer not to add more functionality inside it (we have another
> isolated test and can just run it from zdtm.py).
>
>
>
> >
> >
> > > 5 files changed, 127 insertions(+)
> > > create mode 100644 test/others/leave-stopped/.gitignore
> > > create mode 100644 test/others/leave-stopped/Makefile
> > > create mode 100644 test/others/leave-stopped/pstree.c
> > > create mode 100755 test/others/leave-stopped/run.sh
> > > create mode 100755 test/others/leave-stopped/tree_checker.py
> > >
> > > diff --git a/test/others/leave-stopped/.gitignore b/test/others/leave-stopped/.gitignore
> > > new file mode 100644
> > > index 0000000..f0f7d9e
> > > --- /dev/null
> > > +++ b/test/others/leave-stopped/.gitignore
> > > @@ -0,0 +1,3 @@
> > > +dump/*
> > > +nohup.out
> > > +pstree
> > > diff --git a/test/others/leave-stopped/Makefile b/test/others/leave-stopped/Makefile
> > > new file mode 100644
> > > index 0000000..83e91cc
> > > --- /dev/null
> > > +++ b/test/others/leave-stopped/Makefile
> > > @@ -0,0 +1,7 @@
> > > +pstree: pstree.c
> > > + gcc -pthread -std=c99 $< -o $@
> > > +
> > > +clean:
> > > + rm -f pstree
> > > +
> > > +.PHONY: clean
> > > diff --git a/test/others/leave-stopped/pstree.c b/test/others/leave-stopped/pstree.c
> > > new file mode 100644
> > > index 0000000..a6e437c
> > > --- /dev/null
> > > +++ b/test/others/leave-stopped/pstree.c
> > > @@ -0,0 +1,39 @@
> > > +#include <stdlib.h>
> > > +#include <unistd.h>
> > > +#include <limits.h>
> > > +#include <pthread.h>
> > > +
> > > +const size_t THREADS_N = 3;
> > > +const size_t TREE_HEIGHT = 3;
> > > +
> > > +static void *hang(void *arg)
> > > +{
> > > + (void)arg;
> > > + while (1)
> > > + sleep(UINT_MAX);
> > > +}
> > > +
> > > +static void create_threads(void)
> > > +{
> > > + pthread_t thread;
> > > +
> > > + for (size_t i = 1; i < THREADS_N; i++)
> > > + pthread_create(&thread, NULL, hang, NULL);
> > > +}
> > > +
> > > +int main(void)
> > > +{
> > > + /**
> > > + * just building full binary tree of processes
> > > + */
> > > + for (size_t i = 1; i < TREE_HEIGHT; i++) {
> > > + if (fork()) {
> > > + if (fork())
> > > + break;
> > > + }
> > > + }
> > > +
> > > + create_threads();
> > > +
> > > + hang(NULL);
> > > +}
> > > diff --git a/test/others/leave-stopped/run.sh b/test/others/leave-stopped/run.sh
> > > new file mode 100755
> > > index 0000000..d2f2ec6
> > > --- /dev/null
> > > +++ b/test/others/leave-stopped/run.sh
> > > @@ -0,0 +1,31 @@
> > > +#!/bin/bash
> > > +
> > > +source ../env.sh || exit 1
> > > +
> > > +make || { echo "Failed to build"; exit 1; }
> > > +
> > > +DDIR="dump"
> > > +
> > > +rm -f nohup.out
> > > +rm -rf ${DDIR}
> > > +
> > > +mkdir ${DDIR}
> > > +
> > > +setsid nohup ./pstree &
> > > +root_pid=$!
> > > +
> > > +${CRIU} dump -D ${DDIR} -t ${root_pid} || \
> > > + { echo "Failed to dump"; kill -9 -${root_pid}; exit 1; }
> > > +${CRIU} restore -D ${DDIR} --leave-stopped -d || \
> > > + { echo "Failed to restore"; exit 1; }
> > > +
> > > +./tree_checker.py ${root_pid}
> > > +
> > > +if [ $? -eq 0 ]; then
> > > + echo "PASS"
> > > + kill -9 -${root_pid}
> > > +else
> > > + echo "FAIL"
> > > + kill -9 -${root_pid}
> > > + exit 1
> > > +fi
> > > diff --git a/test/others/leave-stopped/tree_checker.py b/test/others/leave-stopped/tree_checker.py
> > > new file mode 100755
> > > index 0000000..87d45e2
> > > --- /dev/null
> > > +++ b/test/others/leave-stopped/tree_checker.py
> > > @@ -0,0 +1,47 @@
> > > +#!/usr/bin/python2
> > > +
> > > +import os
> > > +import sys
> > > +
> > > +
> > > +def get_thread_status(thread_dir):
> > > + for line in open(os.path.join(thread_dir, "status")).readlines():
> > > + if line.startswith("State:"):
> > > + return line.split(":", 1)[1].strip().split(' ')[0]
> > > + return None
> > > +
> > > +
> > > +def is_process_stopped(pid):
> > > + tasks_dir = "/proc/{}/task".format(pid)
> > > +
> > > + for thread_dir in os.listdir(tasks_dir):
> > > + thread_status = get_thread_status(os.path.join(tasks_dir, thread_dir))
> > > + if not thread_status == "T":
> > > + return False
> > > +
> > > + thread_status = get_thread_status("/proc/{}".format(pid))
> > > + if not thread_status == "T":
> > > + return False
> > > +
> > > + return True
> > > +
> > > +
> > > +def check_tree(root_pid):
> > > + if not is_process_stopped(root_pid):
> > > + print "Process with pid {} is not stopped.".format(root_pid)
> > > + return False
> > > +
> > > + f_children_path = "/proc/{0}/task/{0}/children".format(root_pid)
> > > +
> > > + with open(f_children_path, "r") as f_children:
> > > + for line in f_children:
> > > + for child_pid in line.strip().split(" "):
> > > + if not check_tree(int(child_pid)):
> > > + return False
> > > +
> > > + return True
> > > +
> > > +
> > > +if __name__ == "__main__":
> > > + if not check_tree(sys.argv[1]):
> > > + sys.exit(1)
> > >
> >
> >
> >
> >
> > --
> > Best regards,
> > Eugene Batalov.
>
>
>
>
> --
> Best regards,
> Eugene Batalov.
More information about the CRIU
mailing list