From: Aki Tuomi Date: Fri, 17 Sep 2021 06:58:04 +0000 (+0300) Subject: lib-sql: Add initial unit tests X-Git-Tag: 2.4.0~4725 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=db25a4d8c7f38c0d91b5fb0ba8931900759501d0;p=thirdparty%2Fdovecot%2Fcore.git lib-sql: Add initial unit tests --- diff --git a/src/lib-sql/Makefile.am b/src/lib-sql/Makefile.am index aeddec11ec..06c971094a 100644 --- a/src/lib-sql/Makefile.am +++ b/src/lib-sql/Makefile.am @@ -1,4 +1,4 @@ -noinst_LTLIBRARIES = libsql.la libdriver_test.la +noinst_LTLIBRARIES = libdriver_test.la libsql.la SQL_DRIVER_PLUGINS = @@ -36,6 +36,7 @@ sql_drivers = @sql_drivers@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-test \ -I$(top_srcdir)/src/lib-settings \ $(SQL_CFLAGS) @@ -141,3 +142,29 @@ install-exec-local: done; \ done endif + +test_libs = \ + $(noinst_LTLIBRARIES) \ + ../lib-settings/libsettings.la \ + ../lib-test/libtest.la \ + ../lib/liblib.la + +check_PROGRAMS = test-sql + +test_sql_SOURCES = test-sql.c +test_sql_LDADD = $(test_libs) +test_sql_DEPENDENCIES = $(test_libs) + +if BUILD_SQLITE +check_PROGRAMS += test-sql-sqlite +test_sql_sqlite_SOURCES = test-sql-sqlite.c +test_sql_sqlite_LDADD = $(SQLITE_LIB) $(pkglib_LTLIBRARIES) $(test_libs) +test_sql_sqlite_DEPENDENCIES = $(SQLITE_LIB) $(pkglib_LTLIBRARIES) $(test_libs) +endif + +noinst_PROGRAMS = $(check_PROGRAMS) + +check-local: + for bin in $(check_PROGRAMS); do \ + if ! $(RUN_TEST) ./$$bin; then exit 1; fi; \ + done diff --git a/src/lib-sql/test-sql-sqlite.c b/src/lib-sql/test-sql-sqlite.c new file mode 100644 index 0000000000..2ad3ab9d95 --- /dev/null +++ b/src/lib-sql/test-sql-sqlite.c @@ -0,0 +1,75 @@ +/* Copyright (c) 2021 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "sql-api-private.h" +#include "test-common.h" +#include "sql-api.h" + +void driver_sqlite_init(void); +void driver_sqlite_deinit(void); + +static const char sql_create_db[] = +"CREATE TABLE bar(\n" +" foo VARCHAR(255)\n" +");\n"; + +static void setup_database(struct sql_db *sql) +{ + sql_disconnect(sql); + i_unlink_if_exists("test-database.db"); + sql_exec(sql, sql_create_db); +} + +static void test_sql_sqlite(void) +{ + test_begin("test sql api"); + + const struct sql_settings set = { + .driver = "sqlite", + .connect_string = "test-database.db journal_mode=wal", + }; + struct sql_db *sql = NULL; + const char *error = NULL; + + sql_drivers_init(); + driver_sqlite_init(); + + test_assert(sql_init_full(&set, &sql, &error) == 0 && + sql != NULL && + error == NULL); + setup_database(sql); + + /* insert data */ + struct sql_transaction_context *t = sql_transaction_begin(sql); + sql_update(t, "INSERT INTO bar VALUES(\"value1\")"); + sql_update(t, "INSERT INTO bar VALUES(\"value2\")"); + test_assert(sql_transaction_commit_s(&t, &error) == 0); + + struct sql_result *cursor = sql_query_s(sql, "SELECT foo FROM bar"); + + test_assert(sql_result_next_row(cursor) == SQL_RESULT_NEXT_OK); + test_assert_ucmp(sql_result_get_fields_count(cursor), ==, 1); + test_assert_strcmp(sql_result_get_field_name(cursor, 0), "foo"); + test_assert_strcmp(sql_result_get_field_value(cursor, 0), "value1"); + test_assert(sql_result_next_row(cursor) == SQL_RESULT_NEXT_OK); + test_assert_ucmp(sql_result_get_fields_count(cursor), ==, 1); + test_assert_strcmp(sql_result_get_field_name(cursor, 0), "foo"); + test_assert_strcmp(sql_result_get_field_value(cursor, 0), "value2"); + test_assert(sql_result_next_row(cursor) == SQL_RESULT_NEXT_LAST); + + sql_result_unref(cursor); + sql_unref(&sql); + + driver_sqlite_deinit(); + sql_drivers_deinit(); + + test_end(); +} + +int main(void) { + static void (*const test_functions[])(void) = { + test_sql_sqlite, + NULL + }; + return test_run(test_functions); +} diff --git a/src/lib-sql/test-sql.c b/src/lib-sql/test-sql.c new file mode 100644 index 0000000000..9dcaaaa464 --- /dev/null +++ b/src/lib-sql/test-sql.c @@ -0,0 +1,139 @@ +/* Copyright (c) 2021 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "test-common.h" +#include "sql-api.h" +#include "driver-test.h" + +static struct sql_db *setup_sql(void) +{ + const struct sql_settings set = { + .driver = "sqlite", + .connect_string = "", + }; + struct sql_db *sql = NULL; + const char *error = NULL; + + sql_drivers_init(); + sql_driver_test_register(); + + test_assert(sql_init_full(&set, &sql, &error) == 0 && + sql != NULL && + error == NULL); + + test_assert(sql_connect(sql) == 0); + sql_disconnect(sql); + return sql; +} + +static void deinit_sql(struct sql_db **_sql) +{ + struct sql_db *sql = *_sql; + if (sql == NULL) + return; + *_sql = NULL; + + sql_driver_test_clear_expected_results(sql); + sql_unref(&sql); + + sql_driver_test_unregister(); + sql_drivers_deinit(); +} + +#define setup_result_1(sql) \ + struct test_driver_result_set rset_1 = { \ + .rows = 2, \ + .cols = 1, \ + .col_names = (const char *[]){"foo", NULL}, \ + .row_data = (const char **[]){ \ + (const char*[]){"value1", NULL}, \ + (const char*[]){"value2", NULL}, \ + }, \ + }; \ + struct test_driver_result result_1 = { \ + .nqueries = 1, \ + .queries = (const char *[]){"SELECT foo FROM bar"}, \ + .result = &rset_1 \ + }; \ + sql_driver_test_add_expected_result(sql, &result_1); + +static void test_result_1(struct sql_result *cursor) +{ + test_assert(sql_result_next_row(cursor) == SQL_RESULT_NEXT_OK); + test_assert_ucmp(sql_result_get_fields_count(cursor), ==, 1); + test_assert_strcmp(sql_result_get_field_name(cursor, 0), "foo"); + test_assert_strcmp(sql_result_get_field_value(cursor, 0), "value1"); + test_assert(sql_result_next_row(cursor) == SQL_RESULT_NEXT_OK); + test_assert_ucmp(sql_result_get_fields_count(cursor), ==, 1); + test_assert_strcmp(sql_result_get_field_name(cursor, 0), "foo"); + test_assert_strcmp(sql_result_get_field_value(cursor, 0), "value2"); + test_assert(sql_result_next_row(cursor) == SQL_RESULT_NEXT_LAST); +} + +static void test_sql_api(void) +{ + test_begin("sql api"); + + struct sql_db *sql = setup_sql(); + setup_result_1(sql); + struct sql_result *cursor = sql_query_s(sql, "SELECT foo FROM bar"); + + test_result_1(cursor); + + sql_result_unref(cursor); + + deinit_sql(&sql); + + test_end(); +} + +static void test_sql_stmt_api(void) +{ + test_begin("sql statement api"); + + struct sql_db *sql = setup_sql(); + setup_result_1(sql); + + struct sql_statement *stmt = + sql_statement_init(sql, "SELECT foo FROM bar"); + struct sql_result *cursor = sql_statement_query_s(&stmt); + + test_result_1(cursor); + + sql_result_unref(cursor); + + deinit_sql(&sql); + test_end(); +} + +static void test_sql_stmt_prepared_api(void) +{ + test_begin("sql prepared statement api"); + + struct sql_db *sql = setup_sql(); + setup_result_1(sql); + + struct sql_prepared_statement *prep_stmt = + sql_prepared_statement_init(sql, "SELECT foo FROM bar"); + struct sql_statement *stmt = + sql_statement_init_prepared(prep_stmt); + sql_prepared_statement_unref(&prep_stmt); + struct sql_result *cursor = sql_statement_query_s(&stmt); + + test_result_1(cursor); + + sql_result_unref(cursor); + + deinit_sql(&sql); + test_end(); +} + +int main(void) { + static void (*const test_functions[])(void) = { + test_sql_api, + test_sql_stmt_api, + test_sql_stmt_prepared_api, + NULL + }; + return test_run(test_functions); +}