diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /qa/src/proc_test.c | |
download | pcp-debian/3.9.10.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'qa/src/proc_test.c')
-rw-r--r-- | qa/src/proc_test.c | 624 |
1 files changed, 624 insertions, 0 deletions
diff --git a/qa/src/proc_test.c b/qa/src/proc_test.c new file mode 100644 index 0000000..a8a5ec1 --- /dev/null +++ b/qa/src/proc_test.c @@ -0,0 +1,624 @@ +/* + * Copyright (c) 1997-2001 Silicon Graphics, Inc. All Rights Reserved. + */ + +/* + * Test Plan + * --------- + * + * 0. Agent has associated PMNS, testable say thru PMNS functions. + * + * Test the agent exported functions using the PMAPI: + * (We could call the agent functions directly but we might as well test + * that the whole package is working - i.e. communication via pmcd). + * + * 1. proc_desc - pmGetDesc + * 2. proc_text - pmLookupText, pmLookupInDomText + * 3. proc_instance - pmGetInDom, pmNameInDom, pmLookupInDom + * 4. proc_profile - pmAddProfile, pmDelProfile + * 5. proc_fetch - pmFetch + * 6. proc_store - pmStore + * + * Not used: proc_control + * + * + * Method + * ------ + * + * 1. desc + * a. Test that all specified metrics can have their desc retrieved without error + * b. Test that all spec. metrics have the same indom. + * Note: ideally we would want to make sure that all the desc values returned are + * correct but that means basically just duplicating the agent's code. + * + * 3. instance + * a. Output the instance map, name-->inst, inst-->name + * This output can be tested by a script to look for certain + * processes. + * b. Verify that names and ids are consistent with each other. + * + * 4.5. profile/fetch + * a. Profile is set correctly - look at context dump + * b. Fetch on profile and ensure that the results only have the specified + * instances. + * Note: ideally we would to ensure that the values returned are correct. + * This, however, would be a tricky thing for a lot of metrics. + * The metrics are continually changing for the processes. + * + * 6. store + * a. Ensure it fails appropriately. + * + * TODO + * ---- + * 0, 2, + * + */ + +#include <ctype.h> +#include <sys/wait.h> +#include <pcp/pmapi.h> +#include <pcp/impl.h> + +#ifdef HAVE_PROCFS +#ifdef IS_NETBSD +#include <miscfs/procfs/procfs.h> +#else +#include <sys/procfs.h> +#endif + +#define MAXMETRICS 1024 + +int verbose = 0; +char *host = "localhost"; +char *pmnsfile = PM_NS_DEFAULT; +int nmetrics; +char *metrics[MAXMETRICS]; +pmID pmids[MAXMETRICS]; +pmInDom indom; +int iterations = 1; +int all_n; +int *all_inst; +char **all_names; +pid_t child_pid; +int is_hotproc = 0; +int refresh = 1; + +/* format of an entry in /proc */ +char proc_fmt[8]; /* export for procfs fname conversions */ + + +/* + * getargs + */ + +void +getargs(int argc, char **argv) +{ +#ifdef PCP_DEBUG + static char *debug = "[-D N]"; +#else + static char *debug = ""; +#endif + static char *usage = " [-h hostname] [-n pmnsfile] " + "[-i iterations] [-t refresh] [-v] " + "metric [metric ...]"; + int errflag = 0; + char *endnum; + int c; + int i; + int sts; + + __pmSetProgname(argv[0]); + + while ((c = getopt(argc, argv, "D:h:n:i:t:v")) != EOF) { + switch (c) { + +#ifdef PCP_DEBUG + case 'D': /* debug flag */ + sts = __pmParseDebug(optarg); + if (sts < 0) { + fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", + pmProgname, optarg); + errflag++; + } + else + pmDebug |= sts; + break; +#endif + + case 'h': /* hostname for PMCD to contact */ + host = optarg; + break; + + case 'i': /* iterations */ + iterations = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0') { + fprintf(stderr, "%s: -i requires numeric argument\n", pmProgname); + errflag++; + } + break; + + case 'n': /* alternative name space file */ + pmnsfile = optarg; + break; + + case 't': + refresh = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0') { + fprintf(stderr, "%s: -t requires numeric argument\n", pmProgname); + errflag++; + } + break; + + case 'v': + verbose = 1; + break; + + case '?': + default: + errflag++; + break; + } + } + + if (errflag) { +USAGE: + fprintf(stderr, "Usage: %s %s%s\n", pmProgname, debug, usage); + exit(1); + } + + /* non-flag args are argv[optind] ... argv[argc-1] */ + if (optind >= argc) + goto USAGE; + + /* note metrics and dump them out */ + for (i = 0; i < argc - optind; i++) { + metrics[i] = argv[optind+i]; + if (strncmp(metrics[i], "hotproc.", 8) == 0) { + if (i > 0 && !is_hotproc) { + printf("%s: Error: all metrics should be from same agent\n", + pmProgname); + exit(1); + } + is_hotproc = 1; + } + else if (strncmp(metrics[i], "proc.", 5) == 0) { + if (i > 0 && is_hotproc) { + printf("%s: Error: all metrics should be from same agent\n", + pmProgname); + exit(1); + } + is_hotproc = 0; + } + else { + printf("%s: Error: all metrics should be from " + "proc or hotproc agent: %s\n", pmProgname, metrics[i]); + exit(1); + } + printf("metrics[%d] = <%s>\n", i, metrics[i]); + } + nmetrics = i; + + if (nmetrics <= 0) + goto USAGE; +} + + +void +print_banner_start(char *msg) +{ + int len = strlen(msg); + int i; + + printf("\n"); + for (i = 0; i < len+14; i++) printf("="); + printf("\n"); + printf("=== Test: %s ===\n", msg); + for (i = 0; i < len+14; i++) printf("="); + printf("\n"); + +} + +void +print_banner_end(char *msg) +{ + int len = strlen(msg); + int i; + + printf("\n"); + for (i = 0; i < len+21; i++) printf("="); + printf("\n"); + printf("=== End Of Test: %s ===\n", msg); + for (i = 0; i < len+21; i++) printf("="); + printf("\n"); + +} + +static void +set_proc_fmt(void) +{ + DIR *procdir; + const char *procfs = "/proc"; + struct dirent *directp; + int ndigit; + int proc_entry_len; /* number of chars in procfs entry */ + + if ((procdir = opendir(procfs)) == NULL) { + perror(procfs); + return; + } + proc_entry_len = -1; + for (rewinddir(procdir); (directp = readdir(procdir));) { + if (!isdigit((int)directp->d_name[0])) + continue; + ndigit = (int)strlen(directp->d_name); + if (proc_entry_len == -1) { + proc_entry_len = ndigit; + sprintf(proc_fmt, "%%0%dd", proc_entry_len); + } + else if (ndigit != proc_entry_len) { + /* + * different lengths, so not fixed width ... this is the + * Linux way + */ + sprintf(proc_fmt, "%%d"); + break; + } + } + closedir(procdir); +} + +/* + * 0. + * Does NOT really verify PMNS + * get pmids for rest of pm functions + */ +void +test_PMNS(void) +{ + int sts; + int i; + + print_banner_start("PMNS"); + if ((sts = pmLookupName(nmetrics, metrics, pmids)) < 0) { + printf("pmLookupName: %s\n", pmErrStr(sts)); + for (i = 0; i < nmetrics; i++) { + if (pmids[i] == PM_ID_NULL) + printf(" %s - not known\n", metrics[i]); + } + exit(1); + } + print_banner_end("PMNS"); + +} + +/* + * 1. check all the descriptors + */ +void +test_desc(void) +{ + int sts; + int i; + pmDesc desc; + + print_banner_start("desc"); + + /* test if possible to get one of them and get its indom */ + if ((sts = pmLookupDesc(pmids[0], &desc)) < 0) { + fprintf(stderr, "pmLookupDesc: %s\n", pmErrStr(sts)); + fprintf(stderr, "Associated metric = %s (%s)\n", metrics[0], pmIDStr(pmids[0])); + exit(1); + } + indom = desc.indom; + for (i=0; i < nmetrics; i++) { + if ((sts = pmLookupDesc(pmids[i], &desc)) < 0) { + fprintf(stderr, "pmLookupDesc: %s\n", pmErrStr(sts)); + fprintf(stderr, "Associated metric = %s (%s)\n", metrics[i], pmIDStr(pmids[i])); + exit(1); + } + if (desc.indom != indom) { + fprintf(stderr, "metric <%s> has indom = %d, different to metric <%s> indom = %d\n", + metrics[i], desc.indom, metrics[0], indom); + fprintf(stderr, "This test requires all metrics have the same indom\n"); + exit(1); + } + } + + print_banner_end("desc"); + +} + + +/* + * 3. + * Test out proc_instance + * Using pmGetInDom(), pmNameInDom(), pmLookupInDom() + * Now get metrics for the entire instance domain + * + * Does some sanity checks on names and ids + */ + +void +test_instance(void) +{ + int sts; + int i; + + print_banner_start("instance"); + if (indom == PM_INDOM_NULL) + return; + + fflush(stdout); + if ((child_pid=fork()) == 0) { + /* child sleeps and then exits */ + sleep(2*refresh+1); + exit(0); + } + printf("cpid=%" FMT_PID "\n", child_pid); + + if (is_hotproc) { + /* sleep so that hotprocs can update active list */ + sleep(2*refresh); + } + printf("\n--- GetInDom ---\n"); + sts = pmGetInDom(indom, &all_inst, &all_names); + if (sts < 0) { + printf("%s: pmGetInDom: %s\n", pmProgname, pmErrStr(sts)); + exit(1); + } + else + all_n = sts; + + /* print the instance id's (i.e. pids) match the first field in the name */ + for (i=0; i < all_n; i++) { + int inst; + if (verbose) + printf(" instance map [%d \"%s\"]\n", all_inst[i], all_names[i]); + + /* e.g. inst=0, name="00000 sched" */ + if (sscanf(all_names[i], proc_fmt, &inst) != 1) { + printf("%s: Error: cannot get PID from instname\n", pmProgname); + printf("%s: <id,name> = <%ld,\"%s\">\n", pmProgname, + (long)all_inst[i], all_names[i]); + exit(1); + } + if (inst != all_inst[i]) { + printf("%s: Error: instname is wrong\n", pmProgname); + printf("%s: <id,name> = <%ld,\"%s\"> != %d (fmt=%s)\n", pmProgname, + (long)all_inst[i], all_names[i], inst, proc_fmt); + exit(1); + } + } + + /* parent waits for child to exit */ + /* so that the the following lookups will NOT be able to find it */ + wait(&sts); + + + printf("\n--- LookupInDom ---\n"); + for (i = 0; i < all_n; i++) { + int inst, x; + sts = pmLookupInDom(indom, all_names[i]); + if (sts < 0) { + if (sts == PM_ERR_INST) { + if (all_inst[i] == child_pid) + printf(" Death of child detected, pid=%" FMT_PID "\n", child_pid); + /* ignore deaths */ + continue; + } + else { + printf("%s: pmLookupInDom: %s\n", pmProgname, pmErrStr(sts)); + exit(1); + } + } + inst = sts; + if (verbose) + printf(" instance lookup \"%s\" --> %d\n", all_names[i], inst); + sscanf(all_names[i], proc_fmt, &x); + if (x != inst) { + printf("%s: Error: inst is wrong, expect: %d got: %d\n", + pmProgname, inst, x); + printf("%s: Expected=%d, Actual=%d\n", pmProgname, x, inst); + exit(1); + } + }/*for*/ + + printf("\n--- NameInDom ---\n"); + for (i = 0; i < all_n; i++) { + char *name; + char x[100]; + + sts = pmNameInDom(indom, all_inst[i], &name); + if (sts < 0) { + if (sts == PM_ERR_INST) { + if (all_inst[i] == child_pid) + printf(" Death of child detected\n"); + /* ignore deaths */ + continue; + } + else { + printf("%s: pmNameInDom: %s\n", pmProgname, pmErrStr(sts)); + exit(1); + } + } + if (verbose) + printf(" instance name %d --> \"%s\"\n", all_inst[i], name); + sprintf(x, proc_fmt, all_inst[i]); + if (strncmp(name, x, strlen(x)) != 0 || + (name[strlen(x)] != '\0' && name[strlen(x)] != ' ')) { + /* try w/out leading zeroes */ + char *q; + sprintf(x, "%d", all_inst[i]); + for (q = name; *q && *q == '0'; q++) + ; + if (strncmp(q, x, strlen(x)) != 0 || + (q[strlen(x)] != '\0' && q[strlen(x)] != ' ')) { + printf("%s: Error: name is wrong\n", pmProgname); + printf("%s: Expected=\"%s\", Actual=\"%s\"\n", pmProgname, x, name); + exit(1); + } + } + free(name); + }/*for*/ + + print_banner_end("instance"); +} + + +/* + * Tests 4. and 5. + * Set up an explicit profile of ourself and our parent + * If any of the metrics are not in the proc indom, we'll get no values back. + * Checks if profile is being handled correctly. + * Checks if fetch is using profile correctly. + */ +void +test_prof_fetch(void) +{ + int sts; + int i; + int pids[2]; + pmResult *result1, *result2; + + print_banner_start("profile/fetch"); + + pids[0] = (int)getpid(); + pids[1] = (int)getppid(); + pmDelProfile(indom, 0, NULL); + pmAddProfile(indom, 2, pids); + + printf("\n--- Check profile in context dump... ---\n"); + if ((sts = pmWhichContext()) < 0) { + printf("%s: pmWhichContext: %s\n", pmProgname, pmErrStr(sts)); + exit(1); + } + __pmDumpContext(stdout, sts, PM_INDOM_NULL); + printf("--- End Check profile in context dump... ---\n"); + + printf("\n--- Fetch Over Restricted Instance Domain ... ---\n"); + for (i=0; i < iterations; i++) { + int j,k; + + sts = pmFetch(nmetrics, pmids, &result1); + if (sts < 0) { + printf("%s: iteration %d : %s\n", pmProgname, i, pmErrStr(sts)); + exit(1); + } + __pmDumpResult(stdout, result1); + + + for (j = 0; j < result1->numpmid; j++) { + pmValueSet *set = result1->vset[j]; + + if (set->numval != 2) { + printf("%s: Error: num of inst == %d\n", pmProgname, set->numval); + } + + for (k = 0; k < set->numval; k++) { + pmValue *val = &set->vlist[k]; + if (val->inst != pids[0] && val->inst != pids[1]) { + printf("%s: Error: inst ids do not match pids\n", pmProgname); + exit(1); + } + } + } + + pmFreeResult(result1); + } + printf("--- End Fetch Over Restricted Instance Domain ... ---\n"); + + + + printf("\n--- Fetch Over Entire Instance Domain ... ---\n"); + if (indom != PM_INDOM_NULL) { + pmDelProfile(indom, 0, NULL); + pmAddProfile(indom, all_n, all_inst); + } + sts = pmFetch(nmetrics, pmids, &result2); + if (sts < 0) { + printf("%s: fetch all %d instances : %s\n", pmProgname, all_n, pmErrStr(sts)); + exit(1); + } + __pmDumpResult(stdout, result2); + pmFreeResult(result2); + printf("--- End Fetch Over Entire Instance Domain ... ---\n"); + + print_banner_end("profile/fetch"); + +} + +void +test_store(void) +{ + int sts; + pmResult *result; + + print_banner_start("store"); + + sts = pmFetch(nmetrics, pmids, &result); + if (sts < 0) { + printf("%s: fetch failed : %s\n", pmProgname, pmErrStr(sts)); + exit(1); + } + if ((sts = pmStore(result)) != -EACCES && sts != PM_ERR_PERMISSION) { + printf("%s: Error: pmStore did not fail correctly\n", pmProgname); + printf("Expected: %s\n", pmErrStr(-EACCES)); + printf("or: %s\n", pmErrStr(PM_ERR_PERMISSION)); + printf("Got: %s\n", pmErrStr(sts)); + exit(1); + } + pmFreeResult(result); + + print_banner_end("store"); +} + +/* + * main + */ +int +main(int argc, char **argv) +{ + int sts; + + set_proc_fmt(); + printf("pid=%" FMT_PID " ppid=%" FMT_PID "\n", getpid(), getppid()); + getargs(argc, argv); + + if (pmnsfile != PM_NS_DEFAULT) { + if ((sts = pmLoadNameSpace(pmnsfile)) < 0) { + printf("%s: Cannot load pmnsfile from \"%s\": %s\n", + pmProgname, pmnsfile, pmErrStr(sts)); + exit(1); + } + } + + if ((sts = pmNewContext(PM_CONTEXT_HOST, host)) < 0) { + printf("%s: Cannot connect to PMCD on host \"%s\": %s\n", + pmProgname, host, pmErrStr(sts)); + exit(1); + } + + test_PMNS(); + test_desc(); + test_instance(); + test_prof_fetch(); + if (!is_hotproc) + test_store(); + + if ((sts = pmWhichContext()) < 0) { + printf("%s: pmWhichContext: %s\n", pmProgname, pmErrStr(sts)); + exit(1); + } + pmDestroyContext(sts); + + exit(0); +} +#else +int +main(int argc, char **argv) +{ + printf("No /proc pseudo filesystem on this platform\n"); + exit(1); +} +#endif /* HAVE_PROCFS */ |