source: mainline/uspace/srv/sysman/test/job_queue.c@ af92309

Last change on this file since af92309 was dba056b, checked in by Matthieu Riolo <matthieu.riolo@…>, 6 years ago

sysman: Using exposees to detect asynchronous start

  • also fixed bug with reference counting of merged jobs
  • add test for the faulty behavior
  • Property mode set to 100644
File size: 5.4 KB
Line 
1/*
2 * Copyright (c) 2015 Michal Koutny
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <assert.h>
30#include <fibril.h>
31#include <pcut/pcut.h>
32#include <stdbool.h>
33
34#include "mock_unit.h"
35#include "../job.h"
36#include "../sysman.h"
37
38PCUT_INIT
39
40static bool initialized = false;
41
42static fid_t fibril_event_loop;
43
44static void job_finished_cb(void *object, void *arg)
45{
46 job_t *job = object;
47 job_t **job_ptr = arg;
48
49 /* Pass job reference to the caller */
50 *job_ptr = job;
51}
52
53PCUT_TEST_SUITE(job_queue);
54
55PCUT_TEST_BEFORE {
56 mock_create_units();
57 mock_set_units_state(STATE_STOPPED);
58
59 if (!initialized) {
60 sysman_events_init();
61 job_queue_init();
62
63#if 0
64 fibril_condvar_initialize(&async_finished_cv);
65 fibril_mutex_initialize(&async_finished_mtx);
66#endif
67
68 fibril_event_loop = fibril_create(sysman_events_loop, NULL);
69 fibril_add_ready(fibril_event_loop);
70
71 initialized = true;
72 }
73}
74
75PCUT_TEST_AFTER {
76 mock_destroy_units();
77}
78
79PCUT_TEST(single_start_sync) {
80 unit_type_vmts[UNIT_TARGET]->start = &mock_unit_vmt_start_sync;
81
82 unit_t *u = mock_units[UNIT_TARGET][0];
83 job_t *job = NULL;
84
85 int rc = sysman_run_job(u, STATE_STARTED, &job_finished_cb,
86 &job);
87 PCUT_ASSERT_INT_EQUALS(EOK, rc);
88
89 sysman_process_queue();
90 PCUT_ASSERT_NOT_NULL(job);
91 PCUT_ASSERT_EQUALS(STATE_STARTED, u->state);
92
93 job_del_ref(&job);
94}
95
96PCUT_TEST(single_start_async) {
97 unit_type_vmts[UNIT_TARGET]->start = &mock_unit_vmt_start_async;
98 unit_type_vmts[UNIT_TARGET]->exposee_created =
99 &mock_unit_vmt_exposee_created;
100
101 unit_t *u = mock_units[UNIT_TARGET][0];
102 job_t *job = NULL;
103
104 int rc = sysman_run_job(u, STATE_STARTED, &job_finished_cb, &job);
105 PCUT_ASSERT_INT_EQUALS(EOK, rc);
106
107 sysman_process_queue();
108 PCUT_ASSERT_EQUALS(STATE_STARTING, u->state);
109
110 sysman_raise_event(&sysman_event_unit_exposee_created, u);
111 sysman_process_queue();
112
113 PCUT_ASSERT_NOT_NULL(job);
114 PCUT_ASSERT_EQUALS(STATE_STARTED, u->state);
115
116 job_del_ref(&job);
117}
118
119PCUT_TEST(multipath_to_started_unit) {
120 /* Setup mock behavior */
121 unit_type_vmts[UNIT_SERVICE]->start = &mock_unit_vmt_start_sync;
122
123 unit_type_vmts[UNIT_MOUNT]->start = &mock_unit_vmt_start_async;
124 unit_type_vmts[UNIT_MOUNT]->exposee_created =
125 &mock_unit_vmt_exposee_created;
126
127 /* Define mock units */
128 unit_t *s0 = mock_units[UNIT_SERVICE][0];
129 unit_t *s1 = mock_units[UNIT_SERVICE][1];
130 unit_t *m0 = mock_units[UNIT_MOUNT][0];
131
132 /* All services require root fs */
133 mock_add_dependency(s0, m0);
134 mock_add_dependency(s1, m0);
135
136 /* S1 requires another mount and S0 */
137 mock_add_dependency(s1, s0);
138
139 /* Enforce initial state */
140 m0->state = STATE_STARTED;
141
142 /* Run test */
143 job_t *job = NULL;
144 int rc = sysman_run_job(s1, STATE_STARTED, &job_finished_cb, &job);
145 PCUT_ASSERT_INT_EQUALS(EOK, rc);
146
147 sysman_process_queue();
148
149 PCUT_ASSERT_NOT_NULL(job);
150 PCUT_ASSERT_EQUALS(STATE_STARTED, s0->state);
151 PCUT_ASSERT_EQUALS(STATE_STARTED, s1->state);
152}
153
154PCUT_TEST(merge_jobs_with_callback) {
155 /* Setup mock behavior */
156 unit_type_vmts[UNIT_SERVICE]->start = &mock_unit_vmt_start_async;
157 unit_type_vmts[UNIT_SERVICE]->exposee_created =
158 &mock_unit_vmt_exposee_created;
159
160 /* Define mock units */
161 unit_t *s0 = mock_units[UNIT_SERVICE][0];
162
163 /* Create and start first job */
164 job_t *j0 = NULL;
165 int rc = sysman_run_job(s0, STATE_STARTED, &job_finished_cb, &j0);
166 PCUT_ASSERT_INT_EQUALS(EOK, rc);
167
168 sysman_process_queue();
169 /* Job not finished */
170 PCUT_ASSERT_NULL(j0);
171
172
173 /*
174 * While s0 is starting in j0, create second job that should be merged
175 * into the existing one.
176 */
177 job_t *j1 = NULL;
178 rc = sysman_run_job(s0, STATE_STARTED, &job_finished_cb, &j1);
179 PCUT_ASSERT_INT_EQUALS(EOK, rc);
180
181 sysman_process_queue();
182 /* Job not finished */
183 PCUT_ASSERT_NULL(j1);
184
185 sysman_raise_event(&sysman_event_unit_exposee_created, s0);
186 sysman_process_queue();
187
188 PCUT_ASSERT_NOT_NULL(j0);
189 PCUT_ASSERT_NOT_NULL(j1);
190
191 /*
192 * Jobs were, merged so both callbacks should have been called with the
193 * same job
194 */
195 PCUT_ASSERT_EQUALS(j0, j1);
196
197 /* And there should be exactly two references (per each callback) */
198 job_del_ref(&j0);
199 job_del_ref(&j0);
200
201 PCUT_ASSERT_NULL(j0);
202}
203
204
205PCUT_EXPORT(job_queue);
Note: See TracBrowser for help on using the repository browser.