FOSSology  4.7.1
Open Source License Compliance by Open Source Software
testJob.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 <agent.h>
16 #include <scheduler.h>
17 #include <job.h>
18 
19 #include <utils.h>
20 
21 /* standard */
22 #include <string.h>
23 
28  return Prepare_Testing_Data(scheduler);
29 }
30 
31 /* ************************************************************************** */
32 /* ********** job function tests ******************************************** */
33 /* ************************************************************************** */
34 
48 {
49  scheduler_t* scheduler;
50  job_t* job;
51  arg_int* params;
52  int jq_pk;
53 
54  scheduler = scheduler_init(testdb, NULL);
55 
56  FO_ASSERT_PTR_NULL(scheduler->db_conn);
57  database_init(scheduler);
58  FO_ASSERT_PTR_NOT_NULL_FATAL(scheduler->db_conn);
59 
60  jq_pk = Prepare_Testing_Data_Job(scheduler);
61 
62  database_update_event(scheduler, NULL);
63 
64  job = g_tree_lookup(scheduler->job_list, &jq_pk);
65  FO_ASSERT_PTR_NOT_NULL_FATAL(job);
66  job_verbose_event(scheduler, job);
67  FO_ASSERT_EQUAL(job->id, jq_pk);
68 
69  params = g_new0(arg_int, 1);
70  params->first = job;
71  params->second = jq_pk;
72  job_pause_event(scheduler, params);
73  FO_ASSERT_EQUAL(job->status, JB_PAUSED);
74 
75  params = g_new0(arg_int, 1);
76  params->first = job;
77  params->second = jq_pk;
78  job_restart_event(scheduler, params);
79  FO_ASSERT_EQUAL(job->status, JB_RESTART);
80 
81  params = g_new0(arg_int, 1);
82  params->first = job;
83  params->second = 1;
84  job_priority_event(scheduler, params);
85  FO_ASSERT_EQUAL(job->status, JB_RESTART);
86 
87  job_fail_event(scheduler, job);
88  FO_ASSERT_EQUAL(job->status, JB_FAILED);
89 
90  scheduler_update(scheduler);
91 
92  scheduler_destroy(scheduler);
93 }
94 
107 {
108  scheduler_t* scheduler;
109  job_t* job;
110  char* res = NULL;
111  uint32_t result = 0;
112  int jq_pk;
113 
114  scheduler = scheduler_init(testdb, NULL);
115  FO_ASSERT_PTR_NULL(scheduler->db_conn);
116  database_init(scheduler);
117  FO_ASSERT_PTR_NOT_NULL(scheduler->db_conn);
118 
119  jq_pk = Prepare_Testing_Data_Job(scheduler);
120 
121  database_update_event(scheduler, NULL);
122 
123  job = g_tree_lookup(scheduler->job_list, &jq_pk);
124  FO_ASSERT_PTR_NOT_NULL_FATAL(job);
125 
126  res = job_next(job);
127  FO_ASSERT_PTR_NOT_NULL(res);
128  /* The queue may contain other jobs from the shared DB; only verify non-NULL. */
129  job = peek_job(scheduler->job_queue);
130  FO_ASSERT_PTR_NOT_NULL_FATAL(job);
131  job = next_job(scheduler->job_queue);
132  FO_ASSERT_PTR_NOT_NULL_FATAL(job);
133  result = active_jobs(scheduler->job_list);
134  FO_ASSERT_EQUAL(result, 0);
135 
136  scheduler_destroy(scheduler);
137 }
138 
139 /* ************************************************************************** */
140 /* **** Regression tests for scheduler fixes ******************************** */
141 /* ************************************************************************** */
142 
143 /* max_run=0: isMaxLimitReached() always TRUE, no agents forked. */
144 #define STRESS_USERS 15
145 #define STRESS_UPLOADS 20
146 #define STRESS_N_JOBS (STRESS_USERS * STRESS_UPLOADS)
147 #define STRESS_BASE_ID 50000
148 
156 {
157  scheduler_t* scheduler;
158  int i, found;
159  int job_ids[STRESS_N_JOBS];
160  time_t old_time;
161  uint32_t saved_interval;
162 
163  scheduler = scheduler_init(testdb, NULL);
164  FO_ASSERT_PTR_NULL(scheduler->db_conn);
165  database_init(scheduler);
166  FO_ASSERT_PTR_NOT_NULL_FATAL(scheduler->db_conn);
167 
168  /* max_run=0: isMaxLimitReached() always TRUE -> skip loop, never fork. */
169  add_meta_agent(scheduler->meta_agents, "stress_agent", "echo", 0, 0);
170 
171  /* 0 disables the rate-limiter so the stale reaper fires on every call. */
172  saved_interval = CONF_agent_update_interval;
173  CONF_agent_update_interval = 0;
174 
175  /* Create jobs aged 5 s - past the grace period. */
176  old_time = time(NULL) - 5;
177  for (i = 0; i < STRESS_N_JOBS; i++)
178  {
179  job_t* j = job_init(scheduler->job_list, scheduler->job_queue,
180  "stress_agent", NULL, STRESS_BASE_ID + i, 0, 1, 1, 0, NULL);
181  FO_ASSERT_PTR_NOT_NULL_FATAL(j);
182  j->checkedout_at = old_time;
183  job_ids[i] = STRESS_BASE_ID + i;
184  }
185 
186  FO_ASSERT_EQUAL((int)g_sequence_get_length(scheduler->job_queue), STRESS_N_JOBS);
187  FO_ASSERT_EQUAL(g_tree_nnodes(scheduler->job_list), STRESS_N_JOBS);
188 
189  scheduler_update(scheduler);
190 
191  /* All must survive. */
192  found = 0;
193  for (i = 0; i < STRESS_N_JOBS; i++)
194  {
195  if (g_tree_lookup(scheduler->job_list, &job_ids[i]) != NULL)
196  found++;
197  }
198  FO_ASSERT_EQUAL(found, STRESS_N_JOBS);
199  FO_ASSERT_EQUAL((int)g_sequence_get_length(scheduler->job_queue), STRESS_N_JOBS);
200 
201  CONF_agent_update_interval = saved_interval;
202  scheduler_destroy(scheduler);
203 }
204 
212 {
213  scheduler_t* scheduler;
214  job_t* top;
215  uint32_t saved_interval;
216  int id_hi = STRESS_BASE_ID + 2000; /* priority -10 */
217  int id_mid = STRESS_BASE_ID + 2001; /* priority 0 */
218  int id_low = STRESS_BASE_ID + 2002; /* priority +10 */
219 
220  scheduler = scheduler_init(testdb, NULL);
221  FO_ASSERT_PTR_NULL(scheduler->db_conn);
222  database_init(scheduler);
223  FO_ASSERT_PTR_NOT_NULL_FATAL(scheduler->db_conn);
224 
225  add_meta_agent(scheduler->meta_agents, "prio_agent", "echo", 0, 0);
226 
227  saved_interval = CONF_agent_update_interval;
228  CONF_agent_update_interval = 0;
229 
230  /* Non-sorted insert order to stress priority sorting. */
231  job_init(scheduler->job_list, scheduler->job_queue,
232  "prio_agent", NULL, id_low, 0, 1, 1, 10, NULL);
233  job_init(scheduler->job_list, scheduler->job_queue,
234  "prio_agent", NULL, id_hi, 0, 1, 1, -10, NULL);
235  job_init(scheduler->job_list, scheduler->job_queue,
236  "prio_agent", NULL, id_mid, 0, 1, 1, 0, NULL);
237 
238  /* Highest-priority job must be at the front before scheduling. */
239  top = peek_job(scheduler->job_queue);
240  FO_ASSERT_PTR_NOT_NULL_FATAL(top);
241  FO_ASSERT_EQUAL(top->id, id_hi);
242 
243  /* Age all jobs past the stale threshold to exercise the reaper. */
244  {
245  int ids[3] = { id_hi, id_mid, id_low };
246  int k;
247  time_t old = time(NULL) - 5;
248  for (k = 0; k < 3; k++)
249  {
250  job_t* j = g_tree_lookup(scheduler->job_list, &ids[k]);
251  if (j) j->checkedout_at = old;
252  }
253  }
254 
255  scheduler_update(scheduler);
256 
257  /* Highest-priority job must still be at the front after scheduling. */
258  top = peek_job(scheduler->job_queue);
259  FO_ASSERT_PTR_NOT_NULL_FATAL(top);
260  FO_ASSERT_EQUAL(top->id, id_hi);
261 
262  /* All 3 must survive - stale reaper must not kill blocked jobs. */
263  FO_ASSERT_EQUAL(g_tree_nnodes(scheduler->job_list), 3);
264 
265  CONF_agent_update_interval = saved_interval;
266  scheduler_destroy(scheduler);
267 }
268 
273 {
274  agent_t fake;
275  memset(&fake, 0, sizeof(fake));
276 
277  fake.status = AG_CREATED;
278  fake.owner = NULL;
279 
280  agent_transition(&fake, AG_FAILED);
281 
282  FO_ASSERT_EQUAL(fake.status, AG_FAILED);
283 }
284 
293 {
294  meta_agent_t* ma;
295  int i;
296 
297  ma = meta_agent_init("rtest_unlimited", "echo", -1, 0);
298  FO_ASSERT_PTR_NOT_NULL_FATAL(ma);
299 
300  /* Simulate five concurrently running instances. */
301  for (i = 0; i < 5; i++)
303 
304  FO_ASSERT_EQUAL(ma->run_count, 5);
305 
306  /* max_run=-1: the (max_run >= 0) guard is FALSE -> not at limit. */
307  FO_ASSERT_FALSE(ma->max_run >= 0 && ma->max_run <= ma->run_count);
308 
309  /* Switch to max_run=0: limit is immediately reached even with run_count=0. */
310  ma->max_run = 0;
311  ma->run_count = 0;
312  FO_ASSERT_TRUE(ma->max_run >= 0 && ma->max_run <= ma->run_count);
313 
314  meta_agent_destroy(ma);
315 }
316 
317 /* ************************************************************************** */
318 /* **** suite declaration *************************************************** */
319 /* ************************************************************************** */
320 
321 CU_TestInfo tests_job[] =
322 {
323  {"Test job_event", test_job_event },
324  {"Test job_fun", test_job_fun },
325  {"Test 15-users-20-uploads no false stale kill",test_scheduler_high_load_no_false_stale},
326  {"Test priority order preserved after skip", test_scheduler_priority_order_preserved},
327  {"Test agent_transition null owner safe", test_agent_transition_null_owner_safe },
328  {"Test max_run=-1 means unlimited", test_meta_agent_negative_max_run_is_unlimited},
329  CU_TEST_INFO_NULL
330 };
void meta_agent_increase_count(meta_agent_t *ma)
Definition: agent.c:1741
meta_agent_t * meta_agent_init(char *name, char *cmd, int max, int spc)
Creates a new meta agent.
Definition: agent.c:894
int add_meta_agent(GTree *meta_agents, char *name, char *cmd, int max, int spc)
Definition: agent.c:1695
void agent_transition(agent_t *agent, agent_status new_status)
Definition: agent.c:1508
void meta_agent_destroy(meta_agent_t *ma)
Definition: agent.c:934
Header file with agent related operations.
void job_fail_event(scheduler_t *scheduler, job_t *job)
Events that causes a job to be marked a failed.
Definition: job.c:437
void job_restart_event(scheduler_t *scheduler, arg_int *params)
Definition: job.c:348
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
job_t * next_job(GSequence *job_queue)
Gets the next job from the job queue.
Definition: job.c:744
char * job_next(job_t *job)
Definition: job.c:673
job_t * peek_job(GSequence *job_queue)
Gets the job that is at the top of the queue if there is one.
Definition: job.c:764
void job_verbose_event(scheduler_t *scheduler, job_t *job)
Definition: job.c:250
void job_pause_event(scheduler_t *scheduler, arg_int *params)
Event to pause a job.
Definition: job.c:318
void job_priority_event(scheduler_t *scheduler, arg_int *params)
Definition: job.c:391
uint32_t active_jobs(GTree *job_list)
Gets the number of jobs that are not paused.
Definition: job.c:783
void database_init(scheduler_t *scheduler)
Definition: database.c:771
void database_update_event(scheduler_t *scheduler, void *unused)
Checks the job queue for any new entries.
Definition: database.c:846
void scheduler_update(scheduler_t *scheduler)
Update function called after every event.
Definition: scheduler.c:564
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
int Prepare_Testing_Data(scheduler_t *scheduler)
Definition: utils.c:23
Definition: agent.h:100
agent_status status
the state of execution the agent is currently in
Definition: agent.h:106
job_t * owner
the job that this agent is assigned to
Definition: agent.h:121
Definition: event.h:46
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
time_t checkedout_at
Timestamp when job entered JB_CHECKEDOUT (for stale detection grace period)
Definition: job.h:77
int max_run
the maximum number that can run at once -1 if no limit
Definition: agent.h:85
int run_count
the count of agents in running state
Definition: agent.h:90
GTree * job_list
List of jobs that have been created.
Definition: scheduler.h:172
PGconn * db_conn
The database connection.
Definition: scheduler.h:176
GTree * meta_agents
List of all meta agents available to the scheduler.
Definition: scheduler.h:156
GSequence * job_queue
heap of jobs that still need to be started
Definition: scheduler.h:173
void test_scheduler_priority_order_preserved(void)
Priority ordering must be preserved after a blocked-job skip.
Definition: testJob.c:211
void test_job_fun()
Test for job functions.
Definition: testJob.c:106
void test_job_event()
Test for job events.
Definition: testJob.c:47
void test_agent_transition_null_owner_safe(void)
agent_transition() must not crash when agent->owner is NULL.
Definition: testJob.c:272
void test_meta_agent_negative_max_run_is_unlimited(void)
Regression: max_run < 0 must mean unlimited, not "limit reached".
Definition: testJob.c:292
void test_scheduler_high_load_no_false_stale(void)
Jobs blocked at max_run must not be reaped as stale.
Definition: testJob.c:155
int Prepare_Testing_Data_Job(scheduler_t *scheduler)
Definition: testJob.c:27