19 #include <libfossdbmanager.h> 26 #include <libfossdb.h> 31 #include <CUnit/CUnit.h> 33 #define TESTABLE2(x, y) x "line" #y "_run" 34 #define TESTABLE1(s, i) TESTABLE2(s,i) 35 #define TESTTABLE TESTABLE1("test_db_manager_",__LINE__) 45 PGresult* result = fo_dbManager_Exec_printf(
49 " FROM information_schema.tables " 59 if (PQntuples(result) == 0)
65 int exists = (strcmp(
"t", PQgetvalue(result, 0, 0)) == 0);
67 return exists ? 1 : 0;
71 int _assertFileLines(
const char* fileName,
const char* expectedContent,
int id)
74 int fd = open(fileName, O_RDONLY);
78 ssize_t n = read(fd, buffer,
sizeof(buffer) - 1);
82 int patternMatch = g_pattern_match_simple(expectedContent, buffer);
83 CU_ASSERT_TRUE(patternMatch);
84 #define SEP "\n------------------------\n" 87 printf(
"error expecting log matching" SEP
"%s" SEP
"in file: '%s' for test #%d\n", expectedContent, fileName,
id);
88 printf(SEP
"got" SEP
"%.*s" SEP,
MIN((
int)
sizeof(buffer), (
int) n), buffer);
96 CU_FAIL(
"can not read file");
97 printf(
"can not read '%s'\n", fileName);
102 CU_FAIL(
"can not open file");
103 printf(
"can not read '%s'\n", fileName);
108 void _setLogFileForTest(
fo_dbManager* dbManager,
char* logFile)
110 int logFd = open(logFile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
114 fo_dbManager_setLogFile(dbManager, logFile);
117 CU_FAIL(
"could not truncate logFile, can not test log output");
121 int _getTestTable(
fo_dbManager* dbManager,
char** resultTableName,
const char* columns)
125 while ((!result) && (i < 100))
127 result = g_strdup_printf(
"%s_%d", *resultTableName, i++);
128 int tableExists = _tableExists(dbManager, result);
133 }
else if (tableExists > 0)
141 PGresult* createResult = fo_dbManager_Exec_printf(
142 dbManager,
"CREATE TABLE %s (%s)", result, columns);
145 PQclear(createResult);
146 *resultTableName = result;
167 char* testTableName = TESTTABLE;
168 if (_getTestTable(dbManager, &testTableName,
"a int, b bigint, c varchar"))
172 char* queryInsert = g_strdup_printf(
173 "INSERT INTO %s (a,b,c) VALUES($1,$2,$3)", testTableName);
174 char* querySelect = g_strdup_printf(
175 "SELECT a,b,c FROM %s WHERE a = $1 AND b = $2 AND c = $3", testTableName);
177 CU_ASSERT_TRUE(COUNT > 1);
179 for (j = 0; j < COUNT; j++)
184 "testprepare:insert",
194 CU_ASSERT_EQUAL(first, stmtInsert);
197 CU_ASSERT_STRING_EQUAL(fo_dbManager_printStatement(stmtInsert),
198 "{ name: 'testprepare:insert', parameterTypes: [[0]={int, %d}, [1]={long, %ld}, [2]={char*, %s}]}");
202 "testprepare:select",
207 CU_ASSERT_STRING_EQUAL(fo_dbManager_printStatement(stmtSelect),
208 "{ name: 'testprepare:select', parameterTypes: [[0]={int, %d}, [1]={long, %ld}, [2]={char*, %s}]}");
212 char* c = g_strdup_printf(
"f%d", j);
219 CU_ASSERT_EQUAL_FATAL(PQntuples(result), 1);
220 CU_ASSERT_EQUAL(atoi(PQgetvalue(result, 0, 0)), a);
221 CU_ASSERT_EQUAL(atol(PQgetvalue(result, 0, 1)), b);
222 CU_ASSERT_STRING_EQUAL(PQgetvalue(result, 0, 2), c);
227 CU_FAIL(
"select failed");
232 CU_FAIL(
"insert failed");
239 fo_dbManager_Exec_printf(dbManager,
245 CU_FAIL(
"could not get test table");
252 PGresult* _insertPrepared(
fo_dbManager* dbManager,
char* queryInsert,
void** data,
int a,
long b)
256 "testprepare:insertPerf",
263 PGresult* _insertPreparedCached(
fo_dbManager* dbManager,
char* queryInsert,
void** data,
int a,
long b)
272 "testprepare:insertPerfCached",
281 PGresult* _insertPrintf(
fo_dbManager* dbManager,
char* queryInsert,
void** data,
int a,
long b)
283 return fo_dbManager_Exec_printf(
290 PGresult* _insertWithFunction(
291 PGresult* (* insertFunction)(
fo_dbManager*,
char*,
void**,
int,
long),
298 char* testTableNameVar = g_strdup(testTableName);
300 PGresult* result = NULL;
301 if (_getTestTable(dbManager, &testTableNameVar,
"a int, b bigint, c timestamp DEFAULT CURRENT_TIMESTAMP"))
303 char* queryInsertWithTable = g_strdup_printf(queryInsert, testTableNameVar);
307 for (j = 0; j < count; j++)
311 PGresult* insert = (*insertFunction)(
dbManager, queryInsertWithTable, &data, a, b);
317 CU_FAIL(
"insert failed");
322 result = fo_dbManager_Exec_printf(
324 "SELECT MAX(c) - MIN(c) FROM %s", testTableNameVar);
326 fo_dbManager_Exec_printf(dbManager,
332 CU_FAIL(
"could not get test table");
335 g_free(testTableNameVar);
351 char* testTableNamePrepared = TESTTABLE;
352 char* testTableNamePreparedCached = TESTTABLE;
353 char* testTableNamePrintf = TESTTABLE;
355 char* queryInsertPrepared =
"INSERT INTO %s (a,b) VALUES($1,$2)";
356 char* queryInsertPrintf =
"INSERT INTO %s (a,b) VALUES(%d,%ld)";
359 for (i = 0; i < 21; i++)
361 PGresult* (* insertFunction)(
fo_dbManager*
dbManager,
char* queryInsert,
void** data,
int a,
long b);
364 int count = 500 + 500 * (i / 3) * (i / 3);
370 insertFunction = _insertPrepared;
371 testTableName = testTableNamePrepared;
372 queryInsert = queryInsertPrepared;
374 dbManager = dbManager1;
377 insertFunction = _insertPreparedCached;
378 testTableName = testTableNamePreparedCached;
379 queryInsert = queryInsertPrepared;
380 name =
"prepared (ext.cache)";
381 dbManager = dbManager2;
384 insertFunction = _insertPrintf;
385 testTableName = testTableNamePrintf;
386 queryInsert = queryInsertPrintf;
388 dbManager = dbManager3;
392 printf(
"timing inserts: %d\t", count);
394 printf(
"%s: ", name);
396 PGresult* timeResult = _insertWithFunction(insertFunction, dbManager, queryInsert, testTableName, count);
400 if (PQntuples(timeResult) > 0)
402 printf(
"%s", PQgetvalue(timeResult, 0, 0));
405 CU_FAIL(
"error in querying timings");
410 CU_FAIL(
"error in querying timings");
424 void test_simple_inject()
432 char* testTableName = TESTTABLE;
433 if (_getTestTable(dbManager, &testTableName,
"a int, b bigint, c varchar"))
437 char* attemptInject = g_strdup_printf(
438 "a'; INSERT INTO %s (a,b,c) VALUES (42,0,'2",
442 char* escaped = fo_dbManager_StringEscape(dbManager, attemptInject);
443 PGresult* insert = fo_dbManager_Exec_printf(dbManager,
444 "INSERT INTO %s (a,b,c) VALUES (%d,%ld,'%s')",
453 PGresult* select = fo_dbManager_Exec_printf(dbManager,
459 int count = PQntuples(select);
463 CU_FAIL(
"no result, but 1 expected");
470 PQgetvalue(select, 0, 0),
471 strlen(
"a'; INSERT INTO")
476 CU_FAIL(
"could sql inject");
482 CU_FAIL(
"could not select");
488 CU_FAIL(
"could not insert valid values");
491 fo_dbManager_Exec_printf(dbManager,
497 CU_FAIL(
"could not get test table");
504 void test_fork_error()
506 fo_dbManager* dbManager = fo_dbManager_new_withConf(NULL,
"not a file.conf");
507 char* logFile =
"/tmp/" TESTTABLE;
508 _setLogFileForTest(dbManager, logFile);
510 fo_dbManager_fork(dbManager);
516 "FATAL: Can not open connection\n" 517 "Database conf file: not a file.conf, No such file or directory\n" 518 "While forking dbManager using config: 'not a file.conf'\n",
529 fo_dbManager* dbManager0 = fo_dbManager_new_withConf(pgConn, dbConf);
531 char* testTableName = TESTTABLE;
532 if (_getTestTable(dbManager0, &testTableName,
"a int, b bigint, c varchar"))
534 fo_dbManager* dbManager1 = fo_dbManager_fork(dbManager0);
536 CU_ASSERT_NOT_EQUAL(dbManager0, dbManager1);
537 CU_ASSERT_PTR_NOT_NULL(fo_dbManager_getWrappedConnection(dbManager1));
538 CU_ASSERT_NOT_EQUAL(fo_dbManager_getWrappedConnection(dbManager0),
539 fo_dbManager_getWrappedConnection(dbManager1));
541 char* queryInsert = g_strdup_printf(
542 "INSERT INTO %s (a,b,c) VALUES($1,$2,$3)", testTableName);
559 CU_ASSERT_PTR_NOT_NULL(stmtInsert1);
560 CU_ASSERT_NOT_EQUAL(stmtInsert0, stmtInsert1);
574 PQfinish(fo_dbManager_getWrappedConnection(dbManager1));
578 CU_FAIL(
"coud not fork dbManager");
580 fo_dbManager_Exec_printf(dbManager0,
586 CU_FAIL(
"could not get test table");
593 void _test_wrongQueries_runner(
char* (* test)(
fo_dbManager**,
const char*),
int testNumber)
599 fo_dbManager* dbManager = fo_dbManager_new_withConf(pgConn, dbConf);
601 char* testTable = g_strdup_printf(TESTTABLE
"runner_%d", testNumber);
602 int gotTable = _getTestTable(dbManager, &testTable,
"a int, b bigint");
606 fo_dbManager* dbManagerTest = fo_dbManager_fork(dbManager);
607 char* logFile = g_strdup_printf(
"./%s.log", testTable);
608 _setLogFileForTest(dbManagerTest, logFile);
610 char* expectedLog = (*test)(&dbManagerTest, testTable);
613 fo_dbManager_finish(dbManagerTest);
615 if (_assertFileLines(logFile, expectedLog, testNumber))
617 fo_dbManager_Exec_printf(dbManager,
"DROP TABLE %s", testTable);
621 fo_dbManager_finish(dbManager);
629 CU_FAIL(
"could not get test table");
630 printf(
"could not get test table" " for test %d\n", testNumber);
631 fo_dbManager_finish(dbManager);
635 char* _test_wrongQueries_SyntaxError0(
fo_dbManager** dbManager,
const char* testTableName)
637 CU_ASSERT_PTR_NULL(fo_dbManager_Exec_printf(*dbManager,
638 "CREATE TABLE 's' (id integer, 's' integer"));
641 "ERROR: * syntax error at or near \"'s'\"\n" 642 "* CREATE TABLE 's' (id integer, 's' integer\n" 644 "On: CREATE TABLE 's' (id integer, 's' integer\n" 649 char* _test_wrongQueries_SyntaxError(
fo_dbManager** dbManager,
const char* testTableName)
651 CU_ASSERT_PTR_NULL(fo_dbManager_Exec_printf(*dbManager,
652 "INSERT INTO wrong (id,'%s') VALUES (%d,5)",
657 "ERROR: * syntax error at or near \"'value'\"\n" 658 "* INSERT INTO wrong (id,'value') VALUES (6,5)\n" 660 "On: INSERT INTO wrong (id,'value') VALUES (6,5)\n" 664 char* _test_wrongQueries_noConnectionToServer(
fo_dbManager** dbManager,
const char* testTableName)
666 PQfinish(fo_dbManager_getWrappedConnection(*dbManager));
667 CU_ASSERT_PTR_NULL(fo_dbManager_Exec_printf(*dbManager,
668 "CREATE TABLE new_table_with_a_null_connection"));
674 "FATAL: no connection to the server\n" 675 "On: CREATE TABLE new_table_with_a_null_connection\n" 679 char* _test_wrongQueries_noConnectionToServerOnPrepare(
fo_dbManager** dbManager,
const char* testTableName)
681 PQfinish(fo_dbManager_getWrappedConnection(*dbManager));
683 char* query = g_strdup_printf(
"SELECT * FROM %s", testTableName);
691 CU_ASSERT_PTR_NULL(statement);
696 return g_strdup_printf(
697 "FATAL: no connection to the server\n" 698 "Preparing of '{ name: 'noConnPrepare', parameterTypes: []}' AS 'SELECT * FROM %s'\n",
703 char* _test_wrongQueries_noConnectionToServerOnExecute(
fo_dbManager** dbManager,
const char* testTableName)
705 char* query = g_strdup_printf(
"SELECT * FROM %s", testTableName);
713 CU_ASSERT_PTR_NOT_NULL_FATAL(statement);
715 PQfinish(fo_dbManager_getWrappedConnection(*dbManager));
723 "FATAL: no connection to the server\n" 724 "Executing prepared '{ name: 'noConn', parameterTypes: []}' with params {}\n" 728 char* _test_wrongQueries_noParametersFor1ParameterStmt(
fo_dbManager** dbManager,
const char* testTableName)
730 char* query = g_strdup_printf(
"SELECT a FROM %s WHERE a=$1", testTableName);
732 fo_dbManager_PrepareStamement(
741 "ERROR: ERROR: bind message supplies 0 parameters, but prepared statement \"name2\" requires 1\n" 742 "Executing prepared '{ name: 'name2', parameterTypes: []}' with params {}\n" 746 char* _test_wrongQueries_prepareWithNotExistingColumn(
fo_dbManager** dbManager,
const char* testTableName)
748 char* query = g_strdup_printf(
"SELECT c FROM %s WHERE a=$1", testTableName);
749 CU_ASSERT_PTR_NULL(fo_dbManager_PrepareStamement(
756 return g_strdup_printf(
757 "ERROR: * column \"c\" does not exist\n" 758 "*SELECT c FROM %s WHERE *\n" 760 "Preparing of '{ name: 'name', parameterTypes: []}' AS 'SELECT c FROM %s WHERE a=$1'\n",
761 testTableName, testTableName
765 char* _test_wrongQueries_2ParametersForNoParametersQuery(
fo_dbManager** dbManager,
const char* testTableName)
767 char* query = g_strdup_printf(
"SELECT a FROM %s WHERE a=1", testTableName);
769 fo_dbManager_PrepareStamement(
780 "ERROR: ERROR: bind message supplies 2 parameters, but prepared statement \"name3\" requires 0\n" 781 "Executing prepared '{ name: 'name3', parameterTypes: [[0]={int, %d}, [1]={size_t, %zu}]}' with params {[0]='5', [1]='6'}\n" 785 char* _test_wrongQueries_unparsableTypes(
fo_dbManager** dbManager,
const char* testTableName)
787 CU_ASSERT_PTR_NULL(fo_dbManager_PrepareStamement(
795 "FATAL: dbManager could not comprehend parameter types 'int, ,long'\n" 796 "Trying to prepare 'name4' as 'irrelevant'\n" 800 char* _test_wrongQueries_transactions(
fo_dbManager** dbManager,
const char* testTableName)
802 fo_dbManager_ignoreWarnings(*dbManager, 1);
804 CU_ASSERT_TRUE(fo_dbManager_begin(*dbManager));
805 CU_ASSERT_TRUE(fo_dbManager_begin(*dbManager));
807 PQclear(fo_dbManager_Exec_printf(*dbManager,
"INSERT INTO %s (a, b) VALUES (1,2)", testTableName));
808 CU_ASSERT_TRUE(fo_dbManager_commit(*dbManager));
810 CU_ASSERT_TRUE(fo_dbManager_begin(*dbManager));
811 PQclear(fo_dbManager_Exec_printf(*dbManager,
"INSERT INTO %s (a, b) VALUES (1,2)", testTableName));
812 PQclear(fo_dbManager_Exec_printf(*dbManager,
"INSERT INTO %s (a, c) VALUES (1,2)", testTableName));
813 PQclear(fo_dbManager_Exec_printf(*dbManager,
"INSERT INTO %s (a, b) VALUES (1,2)", testTableName));
815 CU_ASSERT_TRUE(fo_dbManager_rollback(*dbManager));
817 PGresult* res = fo_dbManager_Exec_printf(*dbManager,
"SELECT * FROM %s", testTableName);
819 CU_ASSERT_TRUE(PQntuples(res)==1);
822 return g_strdup_printf(
823 "ERROR: ERROR: column \"c\" of relation \"%s\" does not exist\n" 826 "On: INSERT INTO %s (a, c) VALUES (1,2)\n" 827 "ERROR: ERROR: current transaction is aborted, commands ignored until end of transaction block\n" 828 "On: INSERT INTO %s (a, b) VALUES (1,2)\n", testTableName, testTableName, testTableName
832 void test_wrongQueries()
835 _test_wrongQueries_runner(_test_wrongQueries_SyntaxError0, ++testNumber);
836 _test_wrongQueries_runner(_test_wrongQueries_SyntaxError, ++testNumber);
837 _test_wrongQueries_runner(_test_wrongQueries_noConnectionToServer, ++testNumber);
838 _test_wrongQueries_runner(_test_wrongQueries_noConnectionToServerOnPrepare, ++testNumber);
839 _test_wrongQueries_runner(_test_wrongQueries_noConnectionToServerOnExecute, ++testNumber);
840 _test_wrongQueries_runner(_test_wrongQueries_prepareWithNotExistingColumn, ++testNumber);
841 _test_wrongQueries_runner(_test_wrongQueries_noParametersFor1ParameterStmt, ++testNumber);
842 _test_wrongQueries_runner(_test_wrongQueries_2ParametersForNoParametersQuery, ++testNumber);
843 _test_wrongQueries_runner(_test_wrongQueries_unparsableTypes, ++testNumber);
844 _test_wrongQueries_runner(_test_wrongQueries_transactions, ++testNumber);
847 void test_executeNull()
856 void test_stringEscape_corners()
864 char* empty = fo_dbManager_StringEscape(dbManager,
"");
865 CU_ASSERT_PTR_NOT_NULL_FATAL(empty);
866 CU_ASSERT_EQUAL(strlen(empty), 0);
869 char* onlyQuotes = fo_dbManager_StringEscape(dbManager,
"''''''");
870 CU_ASSERT_PTR_NOT_NULL_FATAL(onlyQuotes);
871 CU_ASSERT_TRUE(strlen(onlyQuotes) > 0);
882 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"", &result));
883 CU_ASSERT_EQUAL(result->len, 0);
884 g_array_free(result, TRUE);
886 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
" ", &result));
887 CU_ASSERT_EQUAL(result->len, 0);
888 g_array_free(result, TRUE);
890 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"\n", &result));
891 CU_ASSERT_EQUAL(result->len, 0);
892 g_array_free(result, TRUE);
894 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
",", &result));
895 CU_ASSERT_EQUAL(result->len, 0);
896 g_array_free(result, TRUE);
898 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"int", &result));
899 CU_ASSERT_EQUAL(result->len, 1);
900 g_array_free(result, TRUE);
902 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
" int ", &result));
903 CU_ASSERT_EQUAL(result->len, 1);
904 g_array_free(result, TRUE);
906 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"long, int\t ,unsigned\n\t int ,long ", &result));
907 CU_ASSERT_EQUAL(result->len, 4);
908 g_array_free(result, TRUE);
910 CU_ASSERT_TRUE(fo_dbManager_parseParamStr(
"unsigned int", &result));
911 CU_ASSERT_EQUAL(result->len, 1);
912 g_array_free(result, TRUE);
914 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"unsignedint", &result));
915 CU_ASSERT_EQUAL(result->len, 0);
916 g_array_free(result, TRUE);
918 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"int,", &result));
919 CU_ASSERT_EQUAL(result->len, 0);
920 g_array_free(result, TRUE);
922 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"int,,long", &result));
923 CU_ASSERT_EQUAL(result->len, 0);
924 g_array_free(result, TRUE);
926 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"int, ,long", &result));
927 CU_ASSERT_EQUAL(result->len, 0);
928 g_array_free(result, TRUE);
930 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"int a", &result));
931 CU_ASSERT_EQUAL(result->len, 0);
932 g_array_free(result, TRUE);
934 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"i", &result));
935 CU_ASSERT_EQUAL(result->len, 0);
936 g_array_free(result, TRUE);
938 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"in", &result));
939 CU_ASSERT_EQUAL(result->len, 0);
940 g_array_free(result, TRUE);
942 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"inta", &result));
943 CU_ASSERT_EQUAL(result->len, 0);
944 g_array_free(result, TRUE);
946 CU_ASSERT_FALSE(fo_dbManager_parseParamStr(
"long, inta , int ,long", &result));
947 CU_ASSERT_EQUAL(result->len, 0);
948 g_array_free(result, TRUE);
954 CU_TestInfo libfossdbmanager_testcases[] =
956 {
"prepare", test_prepare},
957 {
"simple injection", test_simple_inject},
958 {
"handling of wrong queries", test_wrongQueries},
959 {
"execute a null statement", test_executeNull},
960 {
"strange string escaping", test_stringEscape_corners},
961 {
"parsing types", test_parsing},
963 {
"fork dbManager", test_fork},
964 {
"fork dbManager without configuration", test_fork_error},
PGconn * pgConn
Database connection.
PGresult * fo_dbManager_ExecPrepared(fo_dbManager_PreparedStatement *preparedStatement,...)
Execute a prepared statement.
#define MIN(a, b)
Min of two.
fo_dbManager * fo_dbManager_new(PGconn *dbConnection)
Create and initialize new fo_dbManager object.
char buffer[2048]
The last thing received from the scheduler.
fo_dbManager * dbManager
fo_dbManager object
void fo_dbManager_free(fo_dbManager *dbManager)
Un-allocate the memory from a DB manager.
int exists
Default not exists.
PGconn * fo_dbconnect(char *DBConfFile, char **ErrorBuf)
Connect to a database. The default is Db.conf.