8 #include <libfossdbmanager.h>
15 #include <libfossdb.h>
20 #include <CUnit/CUnit.h>
22 #define TESTABLE2(x, y) x "line" #y "_run"
23 #define TESTABLE1(s, i) TESTABLE2(s,i)
24 #define TESTTABLE TESTABLE1("test_db_manager_",__LINE__)
34 PGresult* result = fo_dbManager_Exec_printf(
38 " FROM information_schema.tables "
48 if (PQntuples(result) == 0)
54 int exists = (strcmp(
"t", PQgetvalue(result, 0, 0)) == 0);
60 int _assertFileLines(
const char* fileName,
const char* expectedContent,
int id)
63 int fd = open(fileName, O_RDONLY);
71 int patternMatch = g_pattern_match_simple(expectedContent,
buffer);
72 CU_ASSERT_TRUE(patternMatch);
73 #define SEP "\n------------------------\n"
76 printf(
"error expecting log matching" SEP
"%s" SEP
"in file: '%s' for test #%d\n", expectedContent, fileName,
id);
77 printf(SEP
"got" SEP
"%.*s" SEP,
MIN((
int)
sizeof(
buffer), (
int) n),
buffer);
85 CU_FAIL(
"can not read file");
86 printf(
"can not read '%s'\n", fileName);
91 CU_FAIL(
"can not open file");
92 printf(
"can not read '%s'\n", fileName);
99 int logFd = open(logFile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
103 fo_dbManager_setLogFile(
dbManager, logFile);
106 CU_FAIL(
"could not truncate logFile, can not test log output");
114 while ((!result) && (i < 100))
116 result = g_strdup_printf(
"%s_%d", *resultTableName, i++);
117 int tableExists = _tableExists(
dbManager, result);
122 }
else if (tableExists > 0)
130 PGresult* createResult = fo_dbManager_Exec_printf(
131 dbManager,
"CREATE TABLE %s (%s)", result, columns);
134 PQclear(createResult);
135 *resultTableName = result;
156 char* testTableName = TESTTABLE;
157 if (_getTestTable(
dbManager, &testTableName,
"a int, b bigint, c varchar"))
161 char* queryInsert = g_strdup_printf(
162 "INSERT INTO %s (a,b,c) VALUES($1,$2,$3)", testTableName);
163 char* querySelect = g_strdup_printf(
164 "SELECT a,b,c FROM %s WHERE a = $1 AND b = $2 AND c = $3", testTableName);
166 CU_ASSERT_TRUE(COUNT > 1);
168 for (j = 0; j < COUNT; j++)
173 "testprepare:insert",
183 CU_ASSERT_EQUAL(first, stmtInsert);
186 CU_ASSERT_STRING_EQUAL(fo_dbManager_printStatement(stmtInsert),
187 "{ name: 'testprepare:insert', parameterTypes: [[0]={int, %d}, [1]={long, %ld}, [2]={char*, %s}]}");
191 "testprepare:select",
196 CU_ASSERT_STRING_EQUAL(fo_dbManager_printStatement(stmtSelect),
197 "{ name: 'testprepare:select', parameterTypes: [[0]={int, %d}, [1]={long, %ld}, [2]={char*, %s}]}");
201 char* c = g_strdup_printf(
"f%d", j);
208 CU_ASSERT_EQUAL_FATAL(PQntuples(result), 1);
209 CU_ASSERT_EQUAL(atoi(PQgetvalue(result, 0, 0)), a);
210 CU_ASSERT_EQUAL(atol(PQgetvalue(result, 0, 1)), b);
211 CU_ASSERT_STRING_EQUAL(PQgetvalue(result, 0, 2), c);
216 CU_FAIL(
"select failed");
221 CU_FAIL(
"insert failed");
234 CU_FAIL(
"could not get test table");
245 "testprepare:insertPerf",
252 PGresult* _insertPreparedCached(
fo_dbManager*
dbManager,
char* queryInsert,
void** data,
int a,
long b)
261 "testprepare:insertPerfCached",
272 return fo_dbManager_Exec_printf(
279 PGresult* _insertWithFunction(
280 PGresult* (* insertFunction)(
fo_dbManager*,
char*,
void**,
int,
long),
287 char* testTableNameVar = g_strdup(testTableName);
289 PGresult* result = NULL;
290 if (_getTestTable(
dbManager, &testTableNameVar,
"a int, b bigint, c timestamp DEFAULT CURRENT_TIMESTAMP"))
292 char* queryInsertWithTable = g_strdup_printf(queryInsert, testTableNameVar);
296 for (j = 0; j < count; j++)
300 PGresult* insert = (*insertFunction)(
dbManager, queryInsertWithTable, &data, a, b);
306 CU_FAIL(
"insert failed");
311 result = fo_dbManager_Exec_printf(
313 "SELECT MAX(c) - MIN(c) FROM %s", testTableNameVar);
321 CU_FAIL(
"could not get test table");
324 g_free(testTableNameVar);
340 char* testTableNamePrepared = TESTTABLE;
341 char* testTableNamePreparedCached = TESTTABLE;
342 char* testTableNamePrintf = TESTTABLE;
344 char* queryInsertPrepared =
"INSERT INTO %s (a,b) VALUES($1,$2)";
345 char* queryInsertPrintf =
"INSERT INTO %s (a,b) VALUES(%d,%ld)";
348 for (i = 0; i < 21; i++)
350 PGresult* (* insertFunction)(
fo_dbManager*
dbManager,
char* queryInsert,
void** data,
int a,
long b);
353 int count = 500 + 500 * (i / 3) * (i / 3);
359 insertFunction = _insertPrepared;
360 testTableName = testTableNamePrepared;
361 queryInsert = queryInsertPrepared;
366 insertFunction = _insertPreparedCached;
367 testTableName = testTableNamePreparedCached;
368 queryInsert = queryInsertPrepared;
369 name =
"prepared (ext.cache)";
373 insertFunction = _insertPrintf;
374 testTableName = testTableNamePrintf;
375 queryInsert = queryInsertPrintf;
381 printf(
"timing inserts: %d\t", count);
383 printf(
"%s: ", name);
385 PGresult* timeResult = _insertWithFunction(insertFunction,
dbManager, queryInsert, testTableName, count);
389 if (PQntuples(timeResult) > 0)
391 printf(
"%s", PQgetvalue(timeResult, 0, 0));
394 CU_FAIL(
"error in querying timings");
399 CU_FAIL(
"error in querying timings");
413 void test_simple_inject()
421 char* testTableName = TESTTABLE;
422 if (_getTestTable(
dbManager, &testTableName,
"a int, b bigint, c varchar"))
426 char* attemptInject = g_strdup_printf(
427 "a'; INSERT INTO %s (a,b,c) VALUES (42,0,'2",
431 char* escaped = fo_dbManager_StringEscape(
dbManager, attemptInject);
432 PGresult* insert = fo_dbManager_Exec_printf(
dbManager,
433 "INSERT INTO %s (a,b,c) VALUES (%d,%ld,'%s')",
442 PGresult* select = fo_dbManager_Exec_printf(
dbManager,
448 int count = PQntuples(select);
452 CU_FAIL(
"no result, but 1 expected");
459 PQgetvalue(select, 0, 0),
460 strlen(
"a'; INSERT INTO")
465 CU_FAIL(
"could sql inject");
471 CU_FAIL(
"could not select");
477 CU_FAIL(
"could not insert valid values");
486 CU_FAIL(
"could not get test table");
493 void test_fork_error()
496 char* logFile =
"/tmp/" TESTTABLE;
505 "FATAL: Can not open connection\n"
506 "Database conf file: not a file.conf, No such file or directory\n"
507 "While forking dbManager using config: 'not a file.conf'\n",
520 char* testTableName = TESTTABLE;
521 if (_getTestTable(dbManager0, &testTableName,
"a int, b bigint, c varchar"))
523 fo_dbManager* dbManager1 = fo_dbManager_fork(dbManager0);
525 CU_ASSERT_NOT_EQUAL(dbManager0, dbManager1);
526 CU_ASSERT_PTR_NOT_NULL(fo_dbManager_getWrappedConnection(dbManager1));
527 CU_ASSERT_NOT_EQUAL(fo_dbManager_getWrappedConnection(dbManager0),
528 fo_dbManager_getWrappedConnection(dbManager1));
530 char* queryInsert = g_strdup_printf(
531 "INSERT INTO %s (a,b,c) VALUES($1,$2,$3)", testTableName);
548 CU_ASSERT_PTR_NOT_NULL(stmtInsert1);
549 CU_ASSERT_NOT_EQUAL(stmtInsert0, stmtInsert1);
563 PQfinish(fo_dbManager_getWrappedConnection(dbManager1));
567 CU_FAIL(
"coud not fork dbManager");
569 fo_dbManager_Exec_printf(dbManager0,
575 CU_FAIL(
"could not get test table");
582 void _test_wrongQueries_runner(
char* (* test)(
fo_dbManager**,
const char*),
int testNumber)
590 char* testTable = g_strdup_printf(TESTTABLE
"runner_%d", testNumber);
591 int gotTable = _getTestTable(
dbManager, &testTable,
"a int, b bigint");
596 char* logFile = g_strdup_printf(
"./%s.log", testTable);
597 _setLogFileForTest(dbManagerTest, logFile);
599 char* expectedLog = (*test)(&dbManagerTest, testTable);
602 fo_dbManager_finish(dbManagerTest);
604 if (_assertFileLines(logFile, expectedLog, testNumber))
606 fo_dbManager_Exec_printf(
dbManager,
"DROP TABLE %s", testTable);
618 CU_FAIL(
"could not get test table");
619 printf(
"could not get test table" " for test %d\n", testNumber);
626 CU_ASSERT_PTR_NULL(fo_dbManager_Exec_printf(*
dbManager,
627 "CREATE TABLE 's' (id integer, 's' integer"));
630 "ERROR: * syntax error at or near \"'s'\"\n"
631 "* CREATE TABLE 's' (id integer, 's' integer\n"
633 "On: CREATE TABLE 's' (id integer, 's' integer\n"
640 CU_ASSERT_PTR_NULL(fo_dbManager_Exec_printf(*
dbManager,
641 "INSERT INTO wrong (id,'%s') VALUES (%d,5)",
646 "ERROR: * syntax error at or near \"'value'\"\n"
647 "* INSERT INTO wrong (id,'value') VALUES (6,5)\n"
649 "On: INSERT INTO wrong (id,'value') VALUES (6,5)\n"
655 PQfinish(fo_dbManager_getWrappedConnection(*
dbManager));
656 CU_ASSERT_PTR_NULL(fo_dbManager_Exec_printf(*
dbManager,
657 "CREATE TABLE new_table_with_a_null_connection"));
663 "FATAL: no connection to the server\n"
664 "On: CREATE TABLE new_table_with_a_null_connection\n"
668 char* _test_wrongQueries_noConnectionToServerOnPrepare(
fo_dbManager**
dbManager,
const char* testTableName)
670 PQfinish(fo_dbManager_getWrappedConnection(*
dbManager));
672 char* query = g_strdup_printf(
"SELECT * FROM %s", testTableName);
680 CU_ASSERT_PTR_NULL(statement);
685 return g_strdup_printf(
686 "FATAL: no connection to the server\n"
687 "Preparing of '{ name: 'noConnPrepare', parameterTypes: []}' AS 'SELECT * FROM %s'\n",
692 char* _test_wrongQueries_noConnectionToServerOnExecute(
fo_dbManager**
dbManager,
const char* testTableName)
694 char* query = g_strdup_printf(
"SELECT * FROM %s", testTableName);
702 CU_ASSERT_PTR_NOT_NULL_FATAL(statement);
704 PQfinish(fo_dbManager_getWrappedConnection(*
dbManager));
712 "FATAL: no connection to the server\n"
713 "Executing prepared '{ name: 'noConn', parameterTypes: []}' with params {}\n"
717 char* _test_wrongQueries_noParametersFor1ParameterStmt(
fo_dbManager**
dbManager,
const char* testTableName)
719 char* query = g_strdup_printf(
"SELECT a FROM %s WHERE a=$1", testTableName);
721 fo_dbManager_PrepareStamement(
730 "ERROR: ERROR: bind message supplies 0 parameters, but prepared statement \"name2\" requires 1\n"
731 "Executing prepared '{ name: 'name2', parameterTypes: []}' with params {}\n"
735 char* _test_wrongQueries_prepareWithNotExistingColumn(
fo_dbManager**
dbManager,
const char* testTableName)
737 char* query = g_strdup_printf(
"SELECT c FROM %s WHERE a=$1", testTableName);
738 CU_ASSERT_PTR_NULL(fo_dbManager_PrepareStamement(
745 return g_strdup_printf(
746 "ERROR: * column \"c\" does not exist\n"
747 "*SELECT c FROM %s WHERE *\n"
749 "Preparing of '{ name: 'name', parameterTypes: []}' AS 'SELECT c FROM %s WHERE a=$1'\n",
750 testTableName, testTableName
754 char* _test_wrongQueries_2ParametersForNoParametersQuery(
fo_dbManager**
dbManager,
const char* testTableName)
756 char* query = g_strdup_printf(
"SELECT a FROM %s WHERE a=1", testTableName);
758 fo_dbManager_PrepareStamement(
769 "ERROR: ERROR: bind message supplies 2 parameters, but prepared statement \"name3\" requires 0\n"
770 "Executing prepared '{ name: 'name3', parameterTypes: [[0]={int, %d}, [1]={size_t, %zu}]}' with params {[0]='5', [1]='6'}\n"
776 CU_ASSERT_PTR_NULL(fo_dbManager_PrepareStamement(
784 "FATAL: dbManager could not comprehend parameter types 'int, ,long'\n"
785 "Trying to prepare 'name4' as 'irrelevant'\n"
791 fo_dbManager_ignoreWarnings(*
dbManager, 1);
793 CU_ASSERT_TRUE(fo_dbManager_begin(*
dbManager));
794 CU_ASSERT_TRUE(fo_dbManager_begin(*
dbManager));
796 PQclear(fo_dbManager_Exec_printf(*
dbManager,
"INSERT INTO %s (a, b) VALUES (1,2)", testTableName));
797 CU_ASSERT_TRUE(fo_dbManager_commit(*
dbManager));
799 CU_ASSERT_TRUE(fo_dbManager_begin(*
dbManager));
800 PQclear(fo_dbManager_Exec_printf(*
dbManager,
"INSERT INTO %s (a, b) VALUES (1,2)", testTableName));
801 PQclear(fo_dbManager_Exec_printf(*
dbManager,
"INSERT INTO %s (a, c) VALUES (1,2)", testTableName));
802 PQclear(fo_dbManager_Exec_printf(*
dbManager,
"INSERT INTO %s (a, b) VALUES (1,2)", testTableName));
804 CU_ASSERT_TRUE(fo_dbManager_rollback(*
dbManager));
806 PGresult* res = fo_dbManager_Exec_printf(*
dbManager,
"SELECT * FROM %s", testTableName);
808 CU_ASSERT_TRUE(PQntuples(res)==1);
811 return g_strdup_printf(
812 "ERROR: ERROR: column \"c\" of relation \"%s\" does not exist\n"
815 "On: INSERT INTO %s (a, c) VALUES (1,2)\n"
816 "ERROR: ERROR: current transaction is aborted, commands ignored until end of transaction block\n"
817 "On: INSERT INTO %s (a, b) VALUES (1,2)\n", testTableName, testTableName, testTableName
821 void test_wrongQueries()
824 _test_wrongQueries_runner(_test_wrongQueries_SyntaxError0, ++testNumber);
825 _test_wrongQueries_runner(_test_wrongQueries_SyntaxError, ++testNumber);
826 _test_wrongQueries_runner(_test_wrongQueries_noConnectionToServer, ++testNumber);
827 _test_wrongQueries_runner(_test_wrongQueries_noConnectionToServerOnPrepare, ++testNumber);
828 _test_wrongQueries_runner(_test_wrongQueries_noConnectionToServerOnExecute, ++testNumber);
829 _test_wrongQueries_runner(_test_wrongQueries_prepareWithNotExistingColumn, ++testNumber);
830 _test_wrongQueries_runner(_test_wrongQueries_noParametersFor1ParameterStmt, ++testNumber);
831 _test_wrongQueries_runner(_test_wrongQueries_2ParametersForNoParametersQuery, ++testNumber);
832 _test_wrongQueries_runner(_test_wrongQueries_unparsableTypes, ++testNumber);
833 _test_wrongQueries_runner(_test_wrongQueries_transactions, ++testNumber);
836 void test_executeNull()
845 void test_stringEscape_corners()
853 char* empty = fo_dbManager_StringEscape(
dbManager,
"");
854 CU_ASSERT_PTR_NOT_NULL_FATAL(empty);
855 CU_ASSERT_EQUAL(strlen(empty), 0);
858 char* onlyQuotes = fo_dbManager_StringEscape(
dbManager,
"''''''");
859 CU_ASSERT_PTR_NOT_NULL_FATAL(onlyQuotes);
860 CU_ASSERT_TRUE(strlen(onlyQuotes) > 0);
871 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"", &result));
872 CU_ASSERT_EQUAL(result->len, 0);
873 g_array_free(result, TRUE);
875 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
" ", &result));
876 CU_ASSERT_EQUAL(result->len, 0);
877 g_array_free(result, TRUE);
879 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"\n", &result));
880 CU_ASSERT_EQUAL(result->len, 0);
881 g_array_free(result, TRUE);
883 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
",", &result));
884 CU_ASSERT_EQUAL(result->len, 0);
885 g_array_free(result, TRUE);
887 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"int", &result));
888 CU_ASSERT_EQUAL(result->len, 1);
889 g_array_free(result, TRUE);
891 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
" int ", &result));
892 CU_ASSERT_EQUAL(result->len, 1);
893 g_array_free(result, TRUE);
895 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"long, int\t ,unsigned\n\t int ,long ", &result));
896 CU_ASSERT_EQUAL(result->len, 4);
897 g_array_free(result, TRUE);
899 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"unsigned int", &result));
900 CU_ASSERT_EQUAL(result->len, 1);
901 g_array_free(result, TRUE);
903 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"unsignedint", &result));
904 CU_ASSERT_EQUAL(result->len, 0);
905 g_array_free(result, TRUE);
907 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"int,", &result));
908 CU_ASSERT_EQUAL(result->len, 0);
909 g_array_free(result, TRUE);
911 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"int,,long", &result));
912 CU_ASSERT_EQUAL(result->len, 0);
913 g_array_free(result, TRUE);
915 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"int, ,long", &result));
916 CU_ASSERT_EQUAL(result->len, 0);
917 g_array_free(result, TRUE);
919 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"int a", &result));
920 CU_ASSERT_EQUAL(result->len, 0);
921 g_array_free(result, TRUE);
923 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"i", &result));
924 CU_ASSERT_EQUAL(result->len, 0);
925 g_array_free(result, TRUE);
927 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"in", &result));
928 CU_ASSERT_EQUAL(result->len, 0);
929 g_array_free(result, TRUE);
931 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"inta", &result));
932 CU_ASSERT_EQUAL(result->len, 0);
933 g_array_free(result, TRUE);
935 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"long, inta , int ,long", &result));
936 CU_ASSERT_EQUAL(result->len, 0);
937 g_array_free(result, TRUE);
943 CU_TestInfo libfossdbmanager_testcases[] =
945 {
"prepare", test_prepare},
946 {
"simple injection", test_simple_inject},
947 {
"handling of wrong queries", test_wrongQueries},
948 {
"execute a null statement", test_executeNull},
949 {
"strange string escaping", test_stringEscape_corners},
950 {
"parsing types", test_parsing},
952 {
"fork dbManager", test_fork},
953 {
"fork dbManager without configuration", test_fork_error},
PGconn * pgConn
Database connection.
PGconn * fo_dbconnect(char *DBConfFile, char **ErrorBuf)
Connect to a database. The default is Db.conf.
char buffer[2048]
The last thing received from the scheduler.
#define MIN(a, b)
Min of two.
fo_dbManager * dbManager
fo_dbManager object
PGresult * fo_dbManager_ExecPrepared(fo_dbManager_PreparedStatement *preparedStatement,...)
Execute a prepared statement.
fo_dbManager * fo_dbManager_new(PGconn *dbConnection)
Create and initialize new fo_dbManager object.
void fo_dbManager_free(fo_dbManager *dbManager)
Un-allocate the memory from a DB manager.
int exists
Default not exists.