test: give each test its own XDG_RUNTIME_DIR and TMPDIR

On startup, create /tmp/pwtest-$TIME-$RANDOM/ and give each test an
XDG_RUNTIME_DIR and TMPDIR inside that (simply numerically numbered). This
avoids the tests interfering with the system like accidentally connecting to
the real pipewire instance or trying to create files where they shouldn't.
This commit is contained in:
Peter Hutterer 2021-06-04 11:09:23 +10:00
parent ed3f882fa9
commit e01faf42a1

View file

@ -30,6 +30,7 @@
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <ftw.h>
#include <getopt.h>
#include <limits.h>
#include <stdarg.h>
@ -39,8 +40,10 @@
#include <syscall.h>
#include <sys/epoll.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/timerfd.h>
#include <sys/wait.h>
#include <time.h>
#include <valgrind/valgrind.h>
@ -119,6 +122,7 @@ struct pwtest_context {
bool no_fork;
const char *test_filter;
char *xdg_dir;
};
struct pwtest_context *pwtest_get_context(struct pwtest_test *t)
@ -379,6 +383,48 @@ static void add_tests(struct pwtest_context *ctx)
}
}
static int remove_file(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
{
char *tmpdir = getenv("TMPDIR");
int r;
/* Safety check: bail out if somehow we left TMPDIR */
if (!tmpdir)
tmpdir = "/tmp";
spa_assert(spa_strneq(fpath, tmpdir, strlen(tmpdir)));
r = remove(fpath);
if (r)
fprintf(stderr, "Failed to remove %s: %m", fpath);
return r;
}
static void remove_xdg_runtime_dir(const char *xdg_dir)
{
char *tmpdir = getenv("TMPDIR");
char path[PATH_MAX];
int r;
if (xdg_dir == NULL)
return;
/* Safety checks, we really don't want to recursively remove a
* random directory due to a bug */
if (!tmpdir)
tmpdir = "/tmp";
spa_assert(spa_strneq(xdg_dir, tmpdir, strlen(tmpdir)));
r = spa_scnprintf(path, sizeof(path), "%s/pwtest.dir", xdg_dir);
spa_assert((size_t)r == strlen(xdg_dir) + 11);
if (access(path, F_OK) != 0) {
fprintf(stderr, "XDG_RUNTIME_DIR changed, cannot clean up\n");
return;
}
nftw(xdg_dir, remove_file, 16, FTW_DEPTH | FTW_PHYS);
}
static void cleanup(struct pwtest_context *ctx)
{
struct pwtest_suite *c, *tmp;
@ -386,6 +432,9 @@ static void cleanup(struct pwtest_context *ctx)
spa_list_for_each_safe(c, tmp, &ctx->suites, link) {
free_suite(c);
}
remove_xdg_runtime_dir(ctx->xdg_dir);
free(ctx->xdg_dir);
}
static void sighandler(int signal)
@ -490,8 +539,28 @@ static pid_t start_pwdaemon(struct pwtest_test *t, int stderr_fd, int log_fd)
return pid;
}
static void make_xdg_runtime_test_dir(char dir[PATH_MAX], const char *prefix)
{
static size_t counter;
int r;
r = spa_scnprintf(dir, PATH_MAX, "%s/%zd", prefix, counter++);
spa_assert(r >= (int)(strlen(prefix) + 2));
r = mkdir(dir, 0777);
if (r == -1) {
fprintf(stderr, "Failed to make XDG_RUNTIME_DIR %s (%m)\n", dir);
spa_assert(r != -1);
}
}
static void set_test_env(struct pwtest_context *ctx, struct pwtest_test *t)
{
char xdg_runtime_dir[PATH_MAX];
make_xdg_runtime_test_dir(xdg_runtime_dir, ctx->xdg_dir);
replace_env(t, "XDG_RUNTIME_DIR", xdg_runtime_dir);
replace_env(t, "TMPDIR", xdg_runtime_dir);
replace_env(t, "SPA_PLUGIN_DIR", BUILD_ROOT "/spa/plugins");
replace_env(t, "PIPEWIRE_CONFIG_DIR", BUILD_ROOT "/src/daemon");
replace_env(t, "PIPEWIRE_MODULE_DIR", BUILD_ROOT "/src/modules");
@ -701,6 +770,7 @@ static void run_test(struct pwtest_context *ctx, struct pwtest_suite *c, struct
}
set_test_env(ctx, t);
chdir(getenv("TMPDIR"));
t->result = PWTEST_SYSTEM_ERROR;
@ -832,6 +902,33 @@ static void log_test_result(struct pwtest_test *t)
}
}
static char* make_xdg_runtime_dir(void)
{
time_t t = time(NULL);
struct tm *tm = localtime(&t);
char *dir;
char *tmpdir = getenv("TMPDIR");
char path[PATH_MAX];
FILE *fp;
if (!tmpdir)
tmpdir = "/tmp";
int r = asprintf(&dir, "%s/pwtest-%02d:%02d-XXXXXX", tmpdir, tm->tm_hour, tm->tm_min);
spa_assert((size_t)r == strlen(tmpdir) + 20); /* rough estimate */
spa_assert(mkdtemp(dir) != NULL);
/* Marker file to avoid removing a random directory during cleanup */
r = spa_scnprintf(path, sizeof(path), "%s/pwtest.dir", dir);
spa_assert((size_t)r == strlen(dir) + 11);
fp = fopen(path, "w");
spa_assert(fp);
fprintf(fp, "pwtest\n");
fclose(fp);
return dir;
}
static int run_tests(struct pwtest_context *ctx)
{
int r = EXIT_SUCCESS;
@ -980,6 +1077,8 @@ int main(int argc, char **argv)
find_suites(ctx, suite_filter);
add_tests(ctx);
ctx->xdg_dir = make_xdg_runtime_dir();
switch (mode) {
case MODE_LIST:
list_tests(ctx);