view tests/test-db.c @ 5:566bc028cdcb

tests: initial tests coming - Add tests for database access. - While here transform common code into libsci.a
author David Demelier <markand@malikania.fr>
date Wed, 16 Jun 2021 13:25:42 +0200
parents
children 3ef8128e244f
line wrap: on
line source

/*
 * test-db.c -- test database access
 *
 * Copyright (c) 2021 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdio.h>
#include <string.h>
#include <err.h>

#define GREATEST_USE_ABBREVS 0
#include <greatest.h>

#include "db.h"
#include "types.h"
#include "util.h"

#define DB "test.db"

static void
setup(void *data)
{
	(void)data;

	remove(DB);

	if (db_open(DB) < 0)
		err(1, "unable to create database");
}

static void
teardown(void *data)
{
	(void)data;

	db_finish();
	remove(DB);
}

GREATEST_TEST
test_projects_add(void)
{
	struct project proj = {0};

	proj.name = "test";
	proj.desc = "Test project";
	proj.url = "example.org";
	proj.script = "#!/bin/sh exit 0";

	GREATEST_ASSERT_EQ(db_project_add(&proj), 0);
	GREATEST_ASSERT(proj.id > 0);

	GREATEST_PASS();
}

GREATEST_TEST
test_projects_list(void)
{
	struct project projs[] = {
		{
			.name = "example 1",
			.desc = "Example project 1",
			.url = "example.org",
			.script = "#!/bin/sh exit 0"
		},
		{
			.name = "example 2",
			.desc = "Example project 2",
			.url = "example.org",
			.script = "#!/bin/sh exit 0"
		}
	};
	struct db_ctx ctx;

	for (size_t i = 0; i < UTIL_SIZE(projs); ++i) {
		GREATEST_ASSERT_EQ(db_project_add(&projs[i]), 0);
		GREATEST_ASSERT(projs[i].id > 0);
	}

	memset(projs, 0, sizeof (projs));

	GREATEST_ASSERT_EQ(db_project_list(&ctx, projs, UTIL_SIZE(projs)), 2LL);
	GREATEST_ASSERT(projs[0].id > 0);
	GREATEST_ASSERT_STR_EQ(projs[0].name, "example 1");
	GREATEST_ASSERT_STR_EQ(projs[0].desc, "Example project 1");
	GREATEST_ASSERT_STR_EQ(projs[0].url, "example.org");
	GREATEST_ASSERT_STR_EQ(projs[0].script, "#!/bin/sh exit 0");
	GREATEST_ASSERT(projs[1].id > 0);
	GREATEST_ASSERT_STR_EQ(projs[1].name, "example 2");
	GREATEST_ASSERT_STR_EQ(projs[1].desc, "Example project 2");
	GREATEST_ASSERT_STR_EQ(projs[1].url, "example.org");
	GREATEST_ASSERT_STR_EQ(projs[1].script, "#!/bin/sh exit 0");

	db_ctx_finish(&ctx);

	GREATEST_PASS();
}

GREATEST_TEST
test_projects_find(void)
{
	struct project projs[] = {
		{
			.name = "example 1",
			.desc = "Example project 1",
			.url = "example.org",
			.script = "#!/bin/sh exit 0"
		},
		{
			.name = "example 2",
			.desc = "Example project 2",
			.url = "example.org",
			.script = "#!/bin/sh exit 0"
		}
	};
	struct project find = { .name = "example 2" };
	struct db_ctx ctx;

	for (size_t i = 0; i < UTIL_SIZE(projs); ++i) {
		GREATEST_ASSERT_EQ(db_project_add(&projs[i]), 0);
		GREATEST_ASSERT(projs[i].id > 0);
	}

	GREATEST_ASSERT_EQ(db_project_find(&ctx, &find), 0);
	GREATEST_ASSERT_EQ(find.id, 2);
	GREATEST_ASSERT_STR_EQ(find.name, "example 2");
	GREATEST_ASSERT_STR_EQ(find.desc, "Example project 2");
	GREATEST_ASSERT_STR_EQ(find.url, "example.org");
	GREATEST_ASSERT_STR_EQ(find.script, "#!/bin/sh exit 0");

	db_ctx_finish(&ctx);

	GREATEST_PASS();
}

GREATEST_TEST
test_projects_find_id(void)
{
	struct project projs[] = {
		{
			.name = "example 1",
			.desc = "Example project 1",
			.url = "example.org",
			.script = "#!/bin/sh exit 0"
		},
		{
			.name = "example 2",
			.desc = "Example project 2",
			.url = "example.org",
			.script = "#!/bin/sh exit 0"
		}
	};
	struct project find = { .id = 2 };
	struct db_ctx ctx;

	for (size_t i = 0; i < UTIL_SIZE(projs); ++i) {
		GREATEST_ASSERT_EQ(db_project_add(&projs[i]), 0);
		GREATEST_ASSERT(projs[i].id > 0);
	}

	/* First generated id should start at 1. */
	GREATEST_ASSERT_EQ(db_project_find_id(&ctx, &find), 0);
	GREATEST_ASSERT_EQ(find.id, 2);
	GREATEST_ASSERT_STR_EQ(find.name, "example 2");
	GREATEST_ASSERT_STR_EQ(find.desc, "Example project 2");
	GREATEST_ASSERT_STR_EQ(find.url, "example.org");
	GREATEST_ASSERT_STR_EQ(find.script, "#!/bin/sh exit 0");

	db_ctx_finish(&ctx);

	GREATEST_PASS();
}

GREATEST_SUITE(suite_projects)
{
	GREATEST_SET_SETUP_CB(setup, NULL);
	GREATEST_SET_TEARDOWN_CB(teardown, NULL);
	GREATEST_RUN_TEST(test_projects_add);
	GREATEST_RUN_TEST(test_projects_list);
	GREATEST_RUN_TEST(test_projects_find);
	GREATEST_RUN_TEST(test_projects_find_id);
}

GREATEST_TEST
test_workers_add(void)
{
	struct worker wk = {0};

	wk.name = "test";
	wk.desc = "Test worker";

	GREATEST_ASSERT_EQ(db_worker_add(&wk), 0);
	GREATEST_ASSERT(wk.id > 0);

	GREATEST_PASS();
}

GREATEST_TEST
test_workers_list(void)
{
	struct worker wks[] = {
		{
			.name = "example 1",
			.desc = "Example worker 1",
		},
		{
			.name = "example 2",
			.desc = "Example worker 2",
		}
	};
	struct db_ctx ctx;

	for (size_t i = 0; i < UTIL_SIZE(wks); ++i) {
		GREATEST_ASSERT_EQ(db_worker_add(&wks[i]), 0);
		GREATEST_ASSERT(wks[i].id > 0);
	}

	memset(wks, 0, sizeof (wks));

	GREATEST_ASSERT_EQ(db_worker_list(&ctx, wks, UTIL_SIZE(wks)), 2LL);
	GREATEST_ASSERT(wks[0].id > 0);
	GREATEST_ASSERT_STR_EQ(wks[0].name, "example 1");
	GREATEST_ASSERT_STR_EQ(wks[0].desc, "Example worker 1");
	GREATEST_ASSERT(wks[1].id > 0);
	GREATEST_ASSERT_STR_EQ(wks[1].name, "example 2");
	GREATEST_ASSERT_STR_EQ(wks[1].desc, "Example worker 2");

	db_ctx_finish(&ctx);

	GREATEST_PASS();
}

GREATEST_TEST
test_workers_find(void)
{
	struct worker wks[] = {
		{
			.name = "example 1",
			.desc = "Example worker 1",
		},
		{
			.name = "example 2",
			.desc = "Example worker 2",
		}
	};
	struct worker find = { .name = "example 1" };
	struct db_ctx ctx;

	for (size_t i = 0; i < UTIL_SIZE(wks); ++i) {
		GREATEST_ASSERT_EQ(db_worker_add(&wks[i]), 0);
		GREATEST_ASSERT(wks[i].id > 0);
	}

	GREATEST_ASSERT_EQ(db_worker_find(&ctx, &find), 0);
	GREATEST_ASSERT_EQ(find.id, 1);
	GREATEST_ASSERT_STR_EQ(find.name, "example 1");
	GREATEST_ASSERT_STR_EQ(find.desc, "Example worker 1");

	db_ctx_finish(&ctx);

	GREATEST_PASS();
}

GREATEST_TEST
test_workers_find_id(void)
{
	struct worker wks[] = {
		{
			.name = "example 1",
			.desc = "Example worker 1",
		},
		{
			.name = "example 2",
			.desc = "Example worker 2",
		}
	};
	struct worker find = { .id = 1 };
	struct db_ctx ctx;

	for (size_t i = 0; i < UTIL_SIZE(wks); ++i) {
		GREATEST_ASSERT_EQ(db_worker_add(&wks[i]), 0);
		GREATEST_ASSERT(wks[i].id > 0);
	}

	/* First generated id should start at 1. */
	GREATEST_ASSERT_EQ(db_worker_find_id(&ctx, &find), 0);
	GREATEST_ASSERT_EQ(find.id, 1);
	GREATEST_ASSERT_STR_EQ(find.name, "example 1");
	GREATEST_ASSERT_STR_EQ(find.desc, "Example worker 1");

	db_ctx_finish(&ctx);

	GREATEST_PASS();
}

GREATEST_SUITE(suite_workers)
{
	GREATEST_SET_SETUP_CB(setup, NULL);
	GREATEST_SET_TEARDOWN_CB(teardown, NULL);
	GREATEST_RUN_TEST(test_workers_add);
	GREATEST_RUN_TEST(test_workers_list);
	GREATEST_RUN_TEST(test_workers_find);
	GREATEST_RUN_TEST(test_workers_find_id);
}

GREATEST_TEST
test_jobs_add(void)
{
	struct project proj = {0};
	struct job job = {0};

	proj.name = "test";
	proj.desc = "Test project";
	proj.url = "example.org";
	proj.script = "#!/bin/sh exit 0";

	GREATEST_ASSERT_EQ(db_project_add(&proj), 0);
	GREATEST_ASSERT(proj.id > 0);

	job.project_id = proj.id;
	job.tag = "123456";

	GREATEST_ASSERT_EQ(db_job_add(&job), 0);
	GREATEST_ASSERT(job.id > 0);

	GREATEST_PASS();
}

GREATEST_TEST
test_jobs_todo(void)
{
	struct project proj = {0};
	struct job job = {0};
	struct worker wk = {0};
	struct job todo[16] = {0};
	struct db_ctx ctx;

	proj.name = "test";
	proj.desc = "Test project";
	proj.url = "example.org";
	proj.script = "#!/bin/sh exit 0";

	GREATEST_ASSERT_EQ(db_project_add(&proj), 0);
	GREATEST_ASSERT(proj.id > 0);

	job.project_id = proj.id;
	job.tag = "123456";

	GREATEST_ASSERT_EQ(db_job_add(&job), 0);
	GREATEST_ASSERT(job.id > 0);

	wk.name = "test";
	wk.desc = "Test worker";

	GREATEST_ASSERT_EQ(db_worker_add(&wk), 0);
	GREATEST_ASSERT(wk.id > 0);

	GREATEST_ASSERT_EQ(db_job_todo(&ctx, todo, UTIL_SIZE(todo), wk.id), 1);
	GREATEST_ASSERT(todo[0].id > 0);
	GREATEST_ASSERT_STR_EQ(todo[0].tag, "123456");
	GREATEST_ASSERT_EQ(todo[0].project_id, proj.id);

	db_ctx_finish(&ctx);

	GREATEST_PASS();
}

GREATEST_SUITE(suite_jobs)
{
	GREATEST_SET_SETUP_CB(setup, NULL);
	GREATEST_SET_TEARDOWN_CB(teardown, NULL);
	GREATEST_RUN_TEST(test_jobs_add);
	GREATEST_RUN_TEST(test_jobs_todo);
}


GREATEST_TEST
test_jobresults_add(void)
{
	struct project projs[] = {
		{
			.name = "example 1",
			.desc = "Example project 1",
			.url = "example.org",
			.script = "#!/bin/sh exit 0"
		},
		{
			.name = "example 2",
			.desc = "Example project 2",
			.url = "example.org",
			.script = "#!/bin/sh exit 0"
		}
	};
	struct job jobs[] = {
		{
			.project_id = 0, /* will be project 1 */
			.tag = "123456"
		},
		{
			.project_id = 0, /* will be project 2 */
			.tag = "abcdef"
		},
	};
	struct worker wks[] = {
		{
			.name = "alpine-aarch64",
			.desc = "alpine-aarch64"
		},
		{
			.name = "alpine-armhf",
			.desc = "alpine-armhf"
		},
	};
	struct job todo[16] = {0};
	struct jobresult res = {0};
	struct db_ctx ctx;

	for (size_t i = 0; i < UTIL_SIZE(projs); ++i) {
		GREATEST_ASSERT_EQ(db_project_add(&projs[i]), 0);
		GREATEST_ASSERT(projs[i].id > 0);
	}

	/* Update jobs with newly created projects. */
	jobs[0].project_id = projs[0].id;
	jobs[1].project_id = projs[1].id;

	for (size_t i = 0; i < UTIL_SIZE(jobs); ++i) {
		GREATEST_ASSERT_EQ(db_job_add(&jobs[i]), 0);
		GREATEST_ASSERT(jobs[i].id > 0);
	}

	for (size_t i = 0; i < UTIL_SIZE(wks); ++i) {
		GREATEST_ASSERT_EQ(db_worker_add(&wks[i]), 0);
		GREATEST_ASSERT(wks[i].id > 0);
	}

	/*
	 * Now add a jobresult for worker alpine-aarch64 and the job "abcdef",
	 * this means that this worker will only have the job "123456" to do
	 * while the other worker will have all to do.
	 */
	res.job_id = jobs[1].id;
	res.worker_id = wks[0].id;
	res.exitcode = 0;
	res.log = "Success";

	GREATEST_ASSERT_EQ(db_jobresult_add(&res), 0);
	GREATEST_ASSERT(res.id > 0);

	/* 1 job left for alpine-aarch64 -> [123456]. */
	GREATEST_ASSERT_EQ(db_job_todo(&ctx, todo, UTIL_SIZE(todo), wks[0].id), 1);
	GREATEST_ASSERT(todo[0].id > 0);
	GREATEST_ASSERT_STR_EQ(todo[0].tag, "123456");
	GREATEST_ASSERT_EQ(todo[0].project_id, projs[0].id);

	db_ctx_finish(&ctx);

	/* 2 jobs left for alpine-armhf -> [123456, abcdef]. */
	GREATEST_ASSERT_EQ(db_job_todo(&ctx, todo, UTIL_SIZE(todo), wks[1].id), 2);
	GREATEST_ASSERT(todo[0].id > 0);
	GREATEST_ASSERT_STR_EQ(todo[0].tag, "123456");
	GREATEST_ASSERT_EQ(todo[0].project_id, projs[0].id);
	GREATEST_ASSERT(todo[1].id > 0);
	GREATEST_ASSERT_STR_EQ(todo[1].tag, "abcdef");
	GREATEST_ASSERT_EQ(todo[1].project_id, projs[1].id);

	db_ctx_finish(&ctx);

	GREATEST_PASS();
}

GREATEST_SUITE(suite_jobresults)
{
	GREATEST_SET_SETUP_CB(setup, NULL);
	GREATEST_SET_TEARDOWN_CB(teardown, NULL);
	GREATEST_RUN_TEST(test_jobresults_add);
}

GREATEST_MAIN_DEFS();

int
main(int argc, char **argv)
{
	GREATEST_MAIN_BEGIN();
	GREATEST_RUN_SUITE(suite_projects);
	GREATEST_RUN_SUITE(suite_workers);
	GREATEST_RUN_SUITE(suite_jobs);
	GREATEST_RUN_SUITE(suite_jobresults);
	GREATEST_MAIN_END();
}