[Devel] Re: Container Test Campaign

Sam Vilain sam.vilain at catalyst.net.nz
Thu Jun 22 16:39:24 PDT 2006


Serge E. Hallyn wrote:
> Quoting Marc E. Fiuczynski (mef at CS.Princeton.EDU):
>> Hi Clement,
>>
>> You mention that testing isolation properties is more of an extra than an
>> immediate criteria.  Based on our experience, this actually is a fairly
>> important criteria.  Without decent isolation (both from a namespace and
>
> As we develop our own patches for upstream inclusion, we will also be
> writing testcases to verify isolation, but obviously sitting down and
> writing such testcases for every c/r implementation is not something we
> can commit to  :)
>
> OTOH, perhaps we can collaborate on a test wrapper.  This would require
> details to be filled in by each implementation's owner, but would save
> us from each having to come up with the boundary conditions.  For
> instance, my testcase for the utsname patches which are in -mm is
> attached.  While the testcase is specific to that implementation, by
> abstracting the "start a new container" command into a variable which
> can be filled in for vserver, openvz, etc, we might be able to come up
> with a generic utsname resource testing shell which can be easily filled
> in to work for each implementation.
>
> Just a thought.
>
> -serge

You might like to consider making the output of these tests use the
Perl Test::TAP output; eg:

 1..5 # declare how many tests you expect to run - 0..0 means unknown
 ok 1 # pass test one
 not ok 2 # this one failed - perhaps say why in comments
 ok 3 # SKIP somereason - this test was skipped
 ok 4
 ok 5

This makes it easier to run the tests inside Harnesses.

Sam.

>
> ----------------------------------------------------------------------
>
> /*
>  * Copyright (C) 2005 IBM
>  * Author: Serge Hallyn <serue at us.ibm.com>
>  * Compile using "gcc -o utstest utstest.c"
>  * Run using "for i in `seq 1 5`; do  ./utstest $i; done"
>  *
>  * test1:
>     P1: A=gethostname
>     P2: B=gethostname
>     Ensure(A==B)
>
>  * test2:
>     P1: sethostname(newname); A=gethostname
>     P2: (wait); B=gethostname
>     Ensure (A==B)
>
>  * test3:
>     P1: A=gethostname; unshare(utsname); sethostname(newname);
C=gethostname
>     P2: B=gethostname; (wait); (wait); D=gethostname
>     Ensure (A==B && A==D && C!=D)
>
>  * test4:
>     P1: A=gethostname; unshare(utsname); (wait); C=gethostname
>     P2: B=gethostname; (wait); sethostname(newname); D=gethostname
>     Ensure (A==B && A==C && C!=D)
>
>  * test5:
>     P1: A=gethostname; unshare(utsname) without suff. perms; (wait);
C=gethostname
>     P2: B=gethostname; (wait); sethostname(newname); D=gethostname
>     Ensure (A==B==C==D) and state is ok.
>  *
>  */
>
> #include <sys/wait.h>
> #include <assert.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <string.h>
> #include <errno.h>
>
> int drop_root()
> {
>     int ret;
>     ret = setresuid(1000, 1000, 1000);
>     if (ret) {
>         perror("setresuid");
>         exit(4);
>     }
>     return 1;
> }
>
> #include <linux/unistd.h>
>
> static inline _syscall1 (int,  unshare, int, flags)
>
> #ifndef CLONE_NEWUTS
> #define CLONE_NEWUTS            0x04000000      /* New utsname group? */
> #endif
>
> int p1fd[2], p2fd[2];
> pid_t cpid;
> int testnum;
>
> #define HLEN 100
> #define NAME1 "serge1"
> #define NAME2 "serge2"
>
> void picknewhostname(char *orig, char *new)
> {
>     memset(new, 0, HLEN);
>     if (strcmp(orig, NAME1) == 0)
>         strcpy(new, NAME2);
>     else
>         strcpy(new, NAME1);
> }
>
> void P1(void)
> {
>     char hostname[HLEN], newhostname[HLEN], rhostname[HLEN];
>     int err;
>     int len;
>
>     close(p1fd[1]);
>     close(p2fd[0]);
>
>     switch(testnum) {
>     case 1:
>         gethostname(hostname, HLEN);
>         len = read(p1fd[0], rhostname, HLEN);
>         if (len == strlen(hostname) &&
>             strncmp(hostname, rhostname, len) == 0) {
>             printf("test 1: success\n");
>             exit(0);
>         }
>         printf("test 1: fail\n");
>         printf("Proc 1: hostname %s\n", hostname);
>         printf("test 2: hostname %s\n", rhostname);
>         exit(1);
>     case 2:
>         gethostname(hostname, HLEN);
>         picknewhostname(hostname, newhostname);
>         err = sethostname(newhostname, strlen(newhostname));
>         write(p2fd[1], "1", 1);
>         if (err == -1) { perror("sethostname"); exit(1); }
>         len = read(p1fd[0], rhostname, HLEN);
>         if (len == strlen(newhostname) &&
>                 strncmp(newhostname, rhostname, len) == 0) {
>             printf("test 2: success\n");
>             exit(0);
>         }
>         printf("test 2: fail\n");
>         printf("Proc 1: hostname %s\n", newhostname);
>         printf("test 2: hostname %s\n", rhostname);
>         exit(1);
>     case 3:
>         gethostname(hostname, HLEN);
>         picknewhostname(hostname, newhostname);
>         err = unshare(CLONE_NEWUTS);
>         printf("unshare returned %d (should be 0)\n", err);
>         err = sethostname(newhostname, strlen(newhostname));
>         write(p2fd[1], "1", 1);
>         if (err == -1) { perror("sethostname"); exit(1); }
>
>         len = read(p1fd[0], rhostname, HLEN);
>         if (len == strlen(newhostname) &&
>                 strncmp(newhostname, rhostname, len) == 0) {
>             printf("test 3: fail\n");
>             printf("Proc 1: hostname %s\n", newhostname);
>             printf("test 2: hostname %s\n", rhostname);
>             printf("These should have been different\n");
>             exit(1);
>         }
>         if (len == strlen(hostname) &&
>                 strncmp(hostname, rhostname, len) == 0) {
>             printf("test 3: success\n");
>             exit(0);
>         }
>         printf("test 3: fail\n");
>         printf("Proc 1: original hostname %s\n", hostname);
>         printf("Proc 2: hostname %s\n", rhostname);
>         printf("These should have been the same\n");
>         exit(1);
>
>     case 4:
>         gethostname(hostname, HLEN);
>         err = unshare(CLONE_NEWUTS);
>         printf("unshare returned %d (should be 0)\n", err);
>         write(p2fd[1], "1", 1); /* tell p2 to go ahead and sethostname */
>         len = read(p1fd[0], rhostname, HLEN);
>         gethostname(newhostname, HLEN);
>         if (strcmp(hostname, newhostname) != 0) {
>             printf("test 4: fail\n");
>             printf("Proc 1: hostname %s\n", hostname);
>             printf("Proc 1: new hostname %s\n", newhostname);
>             printf("These should have been the same\n");
>             exit(1);
>         }
>         if (strncmp(hostname, rhostname, len)==0) {
>             printf("test 4: fail\n");
>             printf("Proc 1: hostname %s\n", hostname);
>             printf("Proc 2: new hostname %s\n", rhostname);
>             printf("These should have been different\n");
>             exit(1);
>         }
>         printf("test 4: success\n");
>         exit(0);
>     case 5:
>         /* drop CAP_SYS_ADMIN, then do same as case 4 but check
>          * that hostname != newhostname && rhostname == newhostname */
>         if (!drop_root()) {
>             printf("failed to drop root.\n");
>             exit(3);
>         }
>         gethostname(hostname, HLEN);
>         err = unshare(CLONE_NEWUTS);
>         printf("unshare returned %d (should be -1)\n", err);
>         write(p2fd[1], "1", 1); /* tell p2 to go ahead and sethostname */
>         len = read(p1fd[0], rhostname, HLEN);
>         gethostname(newhostname, HLEN);
>         if (strncmp(newhostname, rhostname, len)!=0) {
>             printf("test 5: fail\n");
>             printf("Proc 1: newhostname %s\n", newhostname);
>             printf("Proc 2: new hostname %s\n", rhostname);
>             printf("These should have been the same\n");
>             exit(1);
>         }
>         if (strcmp(hostname, newhostname) == 0) {
>             printf("test 5: fail\n");
>             printf("Proc 1: hostname %s\n", hostname);
>             printf("Proc 1: new hostname %s\n", newhostname);
>             printf("These should have been different\n");
>             exit(1);
>         }
>         printf("test 5: success\n");
>         exit(0);
>     default:
>         break;
>     }
>     return;
> }
>
> void P2(void)
> {
>     char hostname[HLEN], newhostname[HLEN];
>     int len;
>     int err;
>
>     close(p1fd[0]);
>     close(p2fd[1]);
>
>     switch(testnum) {
>     case 1:
>         gethostname(hostname, HLEN);
>         write(p1fd[1], hostname, strlen(hostname));
>         break;
>     case 2:
>     case 3:
>         len = 0;
>         while (!len) {
>             len = read(p2fd[0], hostname, 1);
>         }
>         gethostname(hostname, HLEN);
>         write(p1fd[1], hostname, strlen(hostname));
>         break;
>     case 4:
>     case 5:
>         len = 0;
>         while (!len) {
>             len = read(p2fd[0], hostname, 1);
>         }
>         gethostname(hostname, HLEN);
>         picknewhostname(hostname, newhostname);
>         sethostname(newhostname, strlen(newhostname));
>         write(p1fd[1], newhostname, strlen(newhostname));
>         break;
>     default:
>         printf("undefined test: %d\n", testnum);
>         break;
>     }
>     return;
> }
>
> int main(int argc, char *argv[])
> {
>     if (argc != 2) {
>         printf("Usage: %s <testnum>\n", argv[0]);
>         printf(" where testnum is between 1 and 5 inclusive\n");
>         exit(2);
>     }
>     if (pipe(p1fd) == -1) { perror("pipe"); exit(EXIT_FAILURE); }
>     if (pipe(p2fd) == -1) { perror("pipe"); exit(EXIT_FAILURE); }
>
>     testnum = atoi(argv[1]);
>     if (testnum < 1 || testnum > 5) {
>         printf("testnum should be between 1 and 5 inclusive.\n");
>         exit(2);
>     }
>
>     cpid = fork();
>
>     if (cpid == -1) { perror("fork"); exit(EXIT_FAILURE); }
>
>     if (cpid == 0)
>         P1();
>     else
>         P2();
>
>     return 0;
> }


-- 
Sam Vilain, Catalyst IT (NZ) Ltd.
phone: +64 4 499 2267        cell:  +64 21 55 40 50
DDI:   +64 4 803 2342        PGP ID: 0x66B25843




More information about the Devel mailing list