FOSSology  4.7.1
Open Source License Compliance by Open Source Software
testDatabase.c
Go to the documentation of this file.
1 /*
2  SPDX-FileCopyrightText: © 2013 Hewlett-Packard Development Company, L.P.
3 
4  SPDX-License-Identifier: GPL-2.0-only
5 */
11 /* include functions to test */
12 #include <testRun.h>
13 
14 /* scheduler includes */
15 #include <database.h>
16 #include <scheduler.h>
17 
18 /* library includes */
19 #include <utils.h>
20 
21 /* testing sql statements */
22 char sqltmp[1024] = {0};
23 extern char* check_scheduler_tables;
24 extern char* jobsql_processed;
25 
26 /* ************************************************************************** */
27 /* **** database function tests ******************************************** */
28 /* ************************************************************************** */
29 
38 {
39  scheduler_t* scheduler;
40  PGresult* db_result;
41  GString* sql;
42 
43  scheduler = scheduler_init(testdb, NULL);
44  database_init(scheduler);
45 
46  FO_ASSERT_PTR_NOT_NULL(scheduler->db_conn);
47 
48  sprintf(sqltmp, check_scheduler_tables, PQdb(scheduler->db_conn));
49  sql = g_string_new(sqltmp);
50  g_string_append(sql, "'users';");
51 
52  /* get the url for the fossology instance */
53  db_result = database_exec(scheduler, sql->str);
54  //printf("sql: %s\n", sql->str);
55  // TODO skip this test since the order reported here is random, also it will crash if PQntuples < 5
56  #if 0
57  if(PQresultStatus(db_result) == PGRES_TUPLES_OK && PQntuples(db_result) != 0)
58  {
59  //printf("result: %s\n", g_strdup(PQgetvalue(db_result, 0, 0)));
60  FO_ASSERT_STRING_EQUAL(g_strdup(PQgetvalue(db_result, 0, 0)), "user_pk");
61  FO_ASSERT_STRING_EQUAL(g_strdup(PQgetvalue(db_result, 1, 0)), "user_name");
62  FO_ASSERT_STRING_EQUAL(g_strdup(PQgetvalue(db_result, 2, 0)), "root_folder_fk");
63  FO_ASSERT_STRING_EQUAL(g_strdup(PQgetvalue(db_result, 3, 0)), "user_desc");
64  FO_ASSERT_STRING_EQUAL(g_strdup(PQgetvalue(db_result, 4, 0)), "user_seed");
65  }
66  #endif
67  PQclear(db_result);
68  g_string_free(sql, TRUE);
69  scheduler_destroy(scheduler);
70 }
71 
78 {
79  scheduler_t* scheduler;
80  gchar* sql = NULL;
81 
82  scheduler = scheduler_init(testdb, NULL);
83 
84  FO_ASSERT_PTR_NULL(scheduler->db_conn);
85  database_init(scheduler);
86  FO_ASSERT_PTR_NOT_NULL(scheduler->db_conn);
87 
88  sql = g_strdup_printf(jobsql_processed, 0, 123);
89 
90  database_exec_event(scheduler, sql);
91  scheduler_destroy(scheduler);
92 }
93 
103 {
104  scheduler_t* scheduler;
105  char sql[512];
106  PGresult* db_result;
107 
108  scheduler = scheduler_init(testdb, NULL);
109 
110  FO_ASSERT_PTR_NULL(scheduler->db_conn);
111  database_init(scheduler);
112  FO_ASSERT_PTR_NOT_NULL(scheduler->db_conn);
113 
114  Prepare_Testing_Data(scheduler);
115 
116  database_update_event(scheduler, NULL);
117  sprintf(sql, "SELECT * FROM job WHERE job_name = 'testing file' ORDER BY job_pk DESC LIMIT 1;");
118  db_result = database_exec(scheduler, sql);
119  if(PQresultStatus(db_result) == PGRES_TUPLES_OK && PQntuples(db_result) != 0)
120  {
121  FO_ASSERT_STRING_EQUAL(PQget(db_result, 0, "job_name"), "testing file");
122  FO_ASSERT_NOT_EQUAL(atoi(PQget(db_result, 0, "job_user_fk")), 0);
123  }
124  PQclear(db_result);
125 
126  database_reset_queue(scheduler);
127 
128  scheduler_destroy(scheduler);
129 }
130 
141 {
142  scheduler_t* scheduler;
143  job_t* job;
144  arg_int* params;
145  int jq_pk;
146  job_t tmp_job;
147 
148  scheduler = scheduler_init(testdb, NULL);
149 
150  FO_ASSERT_PTR_NULL(scheduler->db_conn);
151  database_init(scheduler);
152  FO_ASSERT_PTR_NOT_NULL(scheduler->db_conn);
153 
154  jq_pk = Prepare_Testing_Data(scheduler);
155 
156  params = g_new0(arg_int, 1);
157  params->second = jq_pk;
158  params->first = g_tree_lookup(scheduler->job_list, &params->second);
159  job = params->first;
160  if(params->first == NULL)
161  {
162  tmp_job.id = params->second;
163  tmp_job.status = JB_NOT_AVAILABLE;
164  tmp_job.running_agents = NULL;
165  tmp_job.message = NULL;
166 
167  job = &tmp_job;
168  }
169 
170  FO_ASSERT_STRING_EQUAL(job_status_strings[job->status], "JOB_NOT_AVAILABLE");
171  database_update_job(scheduler, job, JB_PAUSED);
172  //job = g_tree_lookup(scheduler->job_list, &params->second);
173  FO_ASSERT_STRING_EQUAL(job_status_strings[job->status], "JOB_NOT_AVAILABLE");
174 
175  g_free(params);
176  scheduler_destroy(scheduler);
177 }
178 
196 {
197  scheduler_t* scheduler;
198  host_t* host;
199  char sql[512];
200  PGresult* db_result;
201  int jq_pk1, jq_pk2, job_pk2, user_pk, upload_pk;
202 
203  scheduler = scheduler_init(testdb, NULL);
204  FO_ASSERT_PTR_NULL(scheduler->db_conn);
205  database_init(scheduler);
206  FO_ASSERT_PTR_NOT_NULL(scheduler->db_conn);
207 
208  /* Clean up any leftover job2 from a previous run. */
209  db_result = database_exec(scheduler,
210  "DELETE FROM jobqueue WHERE jq_job_fk IN "
211  "(SELECT job_pk FROM job WHERE job_name = 'testing file 2')");
212  SafePQclear(db_result);
213  db_result = database_exec(scheduler, "DELETE FROM job WHERE job_name = 'testing file 2'");
214  SafePQclear(db_result);
215 
216  /* job1 at high priority (9999) via the standard helper. */
217  jq_pk1 = Prepare_Testing_Data(scheduler);
218 
219  /* Retrieve user_pk and upload_pk from job1 to reuse in job2's INSERT. */
220  sprintf(sql,
221  "SELECT j.job_user_fk, j.job_upload_fk"
222  " FROM job j INNER JOIN jobqueue jq ON jq.jq_job_fk = j.job_pk"
223  " WHERE jq.jq_pk = %d",
224  jq_pk1);
225  db_result = database_exec(scheduler, sql);
226  user_pk = (PQresultStatus(db_result) == PGRES_TUPLES_OK && PQntuples(db_result) > 0)
227  ? atoi(PQgetvalue(db_result, 0, 0)) : 1;
228  upload_pk = (PQresultStatus(db_result) == PGRES_TUPLES_OK && PQntuples(db_result) > 0)
229  ? atoi(PQgetvalue(db_result, 0, 1)) : 0;
230  PQclear(db_result);
231 
232  /* job2 at priority 0: always ranked below job1 by ORDER BY priority DESC,
233  * so job1 is deterministically returned first when LIMIT=1. */
234  sprintf(sql,
235  "INSERT INTO job"
236  " (job_pk, job_user_fk, job_queued, job_priority, job_name, job_upload_fk)"
237  " VALUES (nextval('job_job_pk_seq'), %d, now(), 0, 'testing file 2', %d)"
238  " RETURNING job_pk",
239  user_pk, upload_pk);
240  db_result = database_exec(scheduler, sql);
241  job_pk2 = (PQresultStatus(db_result) == PGRES_TUPLES_OK && PQntuples(db_result) > 0)
242  ? atoi(PQgetvalue(db_result, 0, 0)) : 0;
243  PQclear(db_result);
244  FO_ASSERT_NOT_EQUAL(job_pk2, 0);
245 
246  sprintf(sql,
247  "INSERT INTO jobqueue"
248  " (jq_pk, jq_job_fk, jq_type, jq_args, jq_runonpfile,"
249  " jq_starttime, jq_endtime, jq_end_bits, jq_host)"
250  " VALUES (nextval('jobqueue_jq_pk_seq'), %d, 'ununpack', '0',"
251  " NULL, NULL, NULL, 0, NULL)"
252  " RETURNING jq_pk",
253  job_pk2);
254  db_result = database_exec(scheduler, sql);
255  jq_pk2 = (PQresultStatus(db_result) == PGRES_TUPLES_OK && PQntuples(db_result) > 0)
256  ? atoi(PQgetvalue(db_result, 0, 0)) : 0;
257  PQclear(db_result);
258  FO_ASSERT_NOT_EQUAL(jq_pk2, 0);
259 
260  /* Force checkout_limit=1: exposes the regression where the sole LIMIT slot
261  * is wasted by a re-fetched in-flight job. */
262  host = host_init("limit_test_host", "localhost", ".", 1);
263  host_insert(host, scheduler);
264 
265  /* First poll: LIMIT=1, NOT IN(0) → job1 (priority 9999) loaded. */
266  database_update_event(scheduler, NULL);
267  FO_ASSERT_PTR_NOT_NULL_FATAL(g_tree_lookup(scheduler->job_list, &jq_pk1));
268 
269  /* Second poll: LIMIT=1.
270  * Without NOT IN: job1 (jq_starttime IS NULL) re-fetched, skipped by
271  * g_tree_lookup, slot wasted → job2 never loaded. Regression.
272  * With NOT IN: job1 excluded → job2 loaded. Fix validated. */
273  database_update_event(scheduler, NULL);
274  FO_ASSERT_PTR_NOT_NULL(g_tree_lookup(scheduler->job_list, &jq_pk2));
275 
276  database_reset_queue(scheduler);
277  scheduler_destroy(scheduler);
278 }
279 
291 {
292  scheduler_t* scheduler;
293  job_t* job;
294  arg_int* params;
295  int jq_pk;
296  job_t tmp_job;
297 
298  scheduler = scheduler_init(testdb, NULL);
299 
300  FO_ASSERT_PTR_NULL(scheduler->db_conn);
301  database_init(scheduler);
302  FO_ASSERT_PTR_NOT_NULL(scheduler->db_conn);
303 
304  jq_pk = Prepare_Testing_Data(scheduler);
305 
306  params = g_new0(arg_int, 1);
307  params->second = jq_pk;
308  params->first = g_tree_lookup(scheduler->job_list, &params->second);
309  job = params->first;
310  if(params->first == NULL)
311  {
312  tmp_job.id = params->second;
313  tmp_job.status = JB_NOT_AVAILABLE;
314  tmp_job.running_agents = NULL;
315  tmp_job.message = NULL;
316 
317  job = &tmp_job;
318  }
319 
320  FO_ASSERT_STRING_EQUAL(job_status_strings[job->status], "JOB_NOT_AVAILABLE");
321 
322  database_job_processed(jq_pk, 2);
323  database_job_log(jq_pk, "test log");
324  database_job_priority(scheduler, job, 1);
325 
326  g_free(params);
327  scheduler_destroy(scheduler);
328 }
329 
338 {
339  scheduler_t* scheduler;
340  job_t* job;
341  int jq_pk;
342 
343  scheduler = scheduler_init(testdb, NULL);
344 
345  FO_ASSERT_PTR_NULL(scheduler->db_conn);
346  database_init(scheduler);
347  email_init(scheduler);
348  FO_ASSERT_PTR_NOT_NULL(scheduler->db_conn);
349 
350  jq_pk = Prepare_Testing_Data(scheduler);
351  job = job_init(scheduler->job_list, scheduler->job_queue, "ununpack", "localhost", -1, 0, 0, 0, 0, NULL);
352  job->id = jq_pk;
353 
354  database_update_job(scheduler, job, JB_FAILED);
355  FO_ASSERT_STRING_EQUAL(job_status_strings[job->status], "JOB_CHECKEDOUT");
356 
357  scheduler_destroy(scheduler);
358 }
359 /* ************************************************************************** */
360 /* **** suite declaration *************************************************** */
361 /* ************************************************************************** */
362 
363 CU_TestInfo tests_database[] =
364 {
365  {"Test database_init", test_database_init },
366  {"Test database_exec_event", test_database_exec_event },
367  {"Test database_update_event", test_database_update_event },
368  {"Test database_update_event excludes known", test_database_update_event_excludes_known },
369  {"Test database_update_job", test_database_update_job },
370  {"Test database_job", test_database_job },
371  CU_TEST_INFO_NULL
372 };
373 
374 CU_TestInfo tests_email[] =
375 {
376  {"Test email_notify", test_email_notify },
377  CU_TEST_INFO_NULL
378 };
379 
380 
381 
382 
void host_insert(host_t *host, scheduler_t *scheduler)
Inserts a new host into the scheduler structure.
Definition: host.c:91
host_t * host_init(char *name, char *address, char *agent_dir, int max)
Creates a new host, and adds it to the host list.
Definition: host.c:48
job_t * job_init(GTree *job_list, GSequence *job_queue, char *type, char *host, int id, int parent_id, int user_id, int group_id, int priority, char *jq_cmd_args)
Create a new job.
Definition: job.c:164
PGresult * database_exec(scheduler_t *scheduler, const char *sql)
Executes an sql statement for the scheduler.
Definition: database.c:804
void database_reset_queue(scheduler_t *scheduler)
Resets any jobs in the job queue that are not completed.
Definition: database.c:1002
void database_init(scheduler_t *scheduler)
Definition: database.c:771
void database_job_priority(scheduler_t *scheduler, job_t *job, int priority)
Changes the priority of a job queue entry in the database.
Definition: database.c:1102
void database_update_job(scheduler_t *scheduler, job_t *job, job_status status)
Change the status of a job in the database.
Definition: database.c:1020
void database_update_event(scheduler_t *scheduler, void *unused)
Checks the job queue for any new entries.
Definition: database.c:873
void database_job_log(int j_id, char *log_name)
Enters the name of the log file for a job into the database.
Definition: database.c:1087
void database_exec_event(scheduler_t *scheduler, char *sql)
Definition: database.c:828
void email_init(scheduler_t *scheduler)
Loads information about the email that will be sent for job notifications.
Definition: database.c:558
void database_job_processed(int j_id, int num)
Updates the number of items that a job queue entry has processed.
Definition: database.c:1073
scheduler_t * scheduler_init(gchar *sysconfigdir, log_t *log)
Create a new scheduler object.
Definition: scheduler.c:249
void scheduler_destroy(scheduler_t *scheduler)
Free any memory associated with a scheduler_t.
Definition: scheduler.c:364
#define SafePQclear(pgres)
Definition: scheduler.h:133
int Prepare_Testing_Data(scheduler_t *scheduler)
Definition: utils.c:23
const char * upload_pk
Definition: sqlstatements.h:82
Definition: event.h:46
Definition: host.h:26
The job structure.
Definition: job.h:52
int32_t id
The identifier for this job.
Definition: job.h:74
job_status status
The current status for the job.
Definition: job.h:62
gchar * message
Message that will be sent with job notification email.
Definition: job.h:70
GList * running_agents
The list of agents assigned to this job that are still working.
Definition: job.h:56
GTree * job_list
List of jobs that have been created.
Definition: scheduler.h:176
PGconn * db_conn
The database connection.
Definition: scheduler.h:180
GSequence * job_queue
heap of jobs that still need to be started
Definition: scheduler.h:177
void test_database_init()
Test for database_init()
Definition: testDatabase.c:37
char * check_scheduler_tables
Definition: sqlstatements.h:22
void test_database_update_job()
Test for database_update_job()
Definition: testDatabase.c:140
char * jobsql_processed
void test_database_update_event_excludes_known()
Test that database_update_event() excludes already-known jobs via the NOT IN clause.
Definition: testDatabase.c:195
void test_email_notify()
Test for email_notification()
Definition: testDatabase.c:337
void test_database_update_event()
Test for database_update_event()
Definition: testDatabase.c:102
void test_database_job()
Test for database_job_processed(),database_job_log(),database_job_priority()
Definition: testDatabase.c:290
void test_database_exec_event()
Test for database_exec_event()
Definition: testDatabase.c:77