source: mainline/uspace/srv/sysman/test/job_closure.c@ be07995

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

sysman: Add support for closure creation with CLOSURE_ISOLATE flag

Now can create closures, that contain start jobs for all transitively dependent
jobs and stop for all others. (Next step: enqueue and execute.)

  • Property mode set to 100644
File size: 8.0 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 <pcut/pcut.h>
31#include <stdio.h>
32
33#include "../job_closure.h"
34#include "../repo.h"
35
36#include "mock_unit.h"
37
38PCUT_INIT
39
40
41static dyn_array_t exp_closure;
42static dyn_array_t act_closure;
43
44static bool same_job(job_t *expected, job_t *actual)
45{
46 return (expected->unit == actual->unit) &&
47 (expected->target_state == actual->target_state);
48}
49
50static bool same_jobs(dyn_array_t *expected, dyn_array_t *actual)
51{
52 if (expected->size != actual->size) {
53 printf("%s: |expected|, |actual| = %u, %u\n",
54 __func__, expected->size, actual->size);
55 return false;
56 }
57
58 /* Verify expected \subseteq actual (we've compared sizes) */
59 dyn_array_foreach(*expected, job_t *, it_exp) {
60 bool found = false;
61 dyn_array_foreach(*actual, job_t *, it_act) {
62 if (same_job(*it_exp, *it_act)) {
63 found = true;
64 break;
65 }
66 }
67 if (!found) {
68 printf("%s: expected job for %s\n",
69 __func__, unit_name((*it_exp)->unit));
70 return false;
71 }
72 }
73
74 return true;
75}
76
77static bool job_blocked(job_t *blocked_job, job_t *blocking_job)
78{
79 bool found = false;
80 dyn_array_foreach(blocking_job->blocked_jobs, job_t *, it) {
81 if (*it == blocked_job) {
82 found = true;
83 break;
84 }
85 }
86 return found;
87}
88
89static job_t *dummy_job(unit_t *unit, unit_state_t target_state)
90{
91 job_t *result = job_create(unit, target_state);
92 return result;
93}
94
95static void dummy_add_closure(dyn_array_t *closure)
96{
97 dyn_array_foreach(*closure, job_t *, it) {
98 (*it)->unit->job = *it;
99 }
100}
101
102static void destroy_job_closure(dyn_array_t *closure)
103{
104 dyn_array_foreach(*closure, job_t *, it) {
105 job_del_ref(&(*it));
106 }
107}
108
109PCUT_TEST_SUITE(job_closure);
110
111PCUT_TEST_BEFORE {
112 mock_create_units();
113 mock_set_units_state(STATE_STOPPED);
114
115 dyn_array_initialize(&exp_closure, job_t *);
116 int rc = dyn_array_reserve(&exp_closure, MAX_TYPES * MAX_UNITS);
117 assert(rc == EOK);
118
119 dyn_array_initialize(&act_closure, job_t *);
120 rc = dyn_array_reserve(&act_closure, MAX_TYPES * MAX_UNITS);
121 assert(rc == EOK);
122
123 repo_init();
124}
125
126PCUT_TEST_AFTER {
127 destroy_job_closure(&act_closure);
128 dyn_array_destroy(&act_closure);
129
130 destroy_job_closure(&exp_closure);
131 dyn_array_destroy(&exp_closure);
132
133 mock_destroy_units();
134}
135
136PCUT_TEST(job_closure_linear) {
137 unit_t *u0 = mock_units[UNIT_SERVICE][0];
138 unit_t *u1 = mock_units[UNIT_SERVICE][1];
139 unit_t *u2 = mock_units[UNIT_SERVICE][2];
140 unit_t *u3 = mock_units[UNIT_SERVICE][3];
141
142 /*
143 * u0 -> u1 -> u2 -> u3
144 */
145 mock_add_edge(u0, u1);
146 mock_add_edge(u1, u2);
147 mock_add_edge(u2, u3);
148
149 /* Intentionally omit u0 */
150 job_t *main_job = job_create(u1, STATE_STARTED);
151 assert(main_job);
152
153 int rc = job_create_closure(main_job, &act_closure, 0);
154 PCUT_ASSERT_INT_EQUALS(EOK, rc);
155
156 dyn_array_append(&exp_closure, job_t *, dummy_job(u1, STATE_STARTED));
157 dyn_array_append(&exp_closure, job_t *, dummy_job(u2, STATE_STARTED));
158 dyn_array_append(&exp_closure, job_t *, dummy_job(u3, STATE_STARTED));
159
160 dummy_add_closure(&act_closure);
161
162 PCUT_ASSERT_TRUE(same_jobs(&exp_closure, &act_closure));
163 PCUT_ASSERT_TRUE(job_blocked(u1->job, u2->job));
164 PCUT_ASSERT_TRUE(job_blocked(u2->job, u3->job));
165}
166
167PCUT_TEST(job_closure_fork) {
168 unit_t *u0 = mock_units[UNIT_SERVICE][0];
169 unit_t *u1 = mock_units[UNIT_SERVICE][1];
170 unit_t *u2 = mock_units[UNIT_SERVICE][2];
171 unit_t *u3 = mock_units[UNIT_SERVICE][3];
172
173 /*
174 * u0 -> u1 -> u2
175 * \-> u3
176 */
177 mock_add_edge(u0, u1);
178 mock_add_edge(u1, u2);
179 mock_add_edge(u1, u3);
180
181 job_t *main_job = job_create(u1, STATE_STARTED);
182 assert(main_job);
183
184 int rc = job_create_closure(main_job, &act_closure, 0);
185 PCUT_ASSERT_INT_EQUALS(EOK, rc);
186
187 dyn_array_append(&exp_closure, job_t *, dummy_job(u1, STATE_STARTED));
188 dyn_array_append(&exp_closure, job_t *, dummy_job(u2, STATE_STARTED));
189 dyn_array_append(&exp_closure, job_t *, dummy_job(u3, STATE_STARTED));
190
191 dummy_add_closure(&act_closure);
192
193 PCUT_ASSERT_TRUE(same_jobs(&exp_closure, &act_closure));
194 PCUT_ASSERT_TRUE(job_blocked(u1->job, u2->job));
195 PCUT_ASSERT_TRUE(job_blocked(u1->job, u3->job));
196}
197
198PCUT_TEST(job_closure_triangle) {
199 unit_t *u0 = mock_units[UNIT_SERVICE][0];
200 unit_t *u1 = mock_units[UNIT_SERVICE][1];
201 unit_t *u2 = mock_units[UNIT_SERVICE][2];
202 unit_t *u3 = mock_units[UNIT_SERVICE][3];
203
204 /*
205 * u0 -> u1 -> u2
206 * \ v
207 * \-> u3
208 */
209 mock_add_edge(u0, u1);
210 mock_add_edge(u1, u2);
211 mock_add_edge(u1, u3);
212 mock_add_edge(u2, u3);
213
214 job_t *main_job = job_create(u1, STATE_STARTED);
215 assert(main_job);
216
217 int rc = job_create_closure(main_job, &act_closure, 0);
218 PCUT_ASSERT_INT_EQUALS(EOK, rc);
219
220 dyn_array_append(&exp_closure, job_t *, dummy_job(u1, STATE_STARTED));
221 dyn_array_append(&exp_closure, job_t *, dummy_job(u2, STATE_STARTED));
222 dyn_array_append(&exp_closure, job_t *, dummy_job(u3, STATE_STARTED));
223
224 dummy_add_closure(&act_closure);
225
226 PCUT_ASSERT_TRUE(same_jobs(&exp_closure, &act_closure));
227 PCUT_ASSERT_TRUE(job_blocked(u1->job, u2->job));
228 PCUT_ASSERT_TRUE(job_blocked(u1->job, u3->job));
229 PCUT_ASSERT_TRUE(job_blocked(u2->job, u3->job));
230}
231
232PCUT_TEST(job_closure_isolate_linears) {
233 unit_t *u0 = mock_units[UNIT_SERVICE][0];
234 unit_t *u1 = mock_units[UNIT_SERVICE][1];
235 unit_t *u2 = mock_units[UNIT_SERVICE][2];
236 unit_t *u3 = mock_units[UNIT_SERVICE][3];
237 unit_t *u4 = mock_units[UNIT_SERVICE][4];
238 unit_t *u5 = mock_units[UNIT_SERVICE][5];
239 unit_t *u6 = mock_units[UNIT_SERVICE][6];
240 repo_begin_update();
241 for (int i = 0; i < 7; ++i) {
242 repo_add_unit(mock_units[UNIT_SERVICE][i]);
243 }
244 repo_commit();
245
246 /*
247 *
248 * u0 -> u1 -> u2
249 *
250 * u3 -> u4 -> u5
251 *
252 * u6
253 */
254 mock_add_edge(u0, u1);
255 mock_add_edge(u1, u2);
256
257 mock_add_edge(u3, u4);
258 mock_add_edge(u4, u5);
259
260 job_t *main_job = job_create(u1, STATE_STARTED);
261 assert(main_job);
262
263 int rc = job_create_closure(main_job, &act_closure, CLOSURE_ISOLATE);
264 PCUT_ASSERT_INT_EQUALS(EOK, rc);
265
266 dyn_array_append(&exp_closure, job_t *, dummy_job(u0, STATE_STOPPED));
267 dyn_array_append(&exp_closure, job_t *, dummy_job(u1, STATE_STARTED));
268 dyn_array_append(&exp_closure, job_t *, dummy_job(u2, STATE_STARTED));
269 dyn_array_append(&exp_closure, job_t *, dummy_job(u3, STATE_STOPPED));
270 dyn_array_append(&exp_closure, job_t *, dummy_job(u4, STATE_STOPPED));
271 dyn_array_append(&exp_closure, job_t *, dummy_job(u5, STATE_STOPPED));
272 dyn_array_append(&exp_closure, job_t *, dummy_job(u6, STATE_STOPPED));
273
274 dummy_add_closure(&act_closure);
275
276 PCUT_ASSERT_TRUE(same_jobs(&exp_closure, &act_closure));
277 PCUT_ASSERT_TRUE(job_blocked(u1->job, u2->job));
278
279 PCUT_ASSERT_TRUE(job_blocked(u5->job, u4->job));
280 PCUT_ASSERT_TRUE(job_blocked(u4->job, u3->job));
281
282 PCUT_ASSERT_INT_EQUALS(0, u6->job->blocking_jobs);
283 PCUT_ASSERT_INT_EQUALS(0, u0->job->blocking_jobs);
284}
285
286PCUT_EXPORT(job_closure);
Note: See TracBrowser for help on using the repository browser.