]>
Commit | Line | Data |
---|---|---|
681c28a3 | 1 | #include "qemu/osdep.h" |
dd0029c0 JS |
2 | #include <sys/wait.h> |
3 | ||
4 | #include "libqtest.h" | |
5 | #include "libqos/libqos.h" | |
6 | #include "libqos/pci.h" | |
dd0029c0 JS |
7 | |
8 | /*** Test Setup & Teardown ***/ | |
9 | ||
10 | /** | |
11 | * Launch QEMU with the given command line, | |
12 | * and then set up interrupts and our guest malloc interface. | |
458f3b2c LV |
13 | * Never returns NULL: |
14 | * Terminates the application in case an error is encountered. | |
dd0029c0 | 15 | */ |
90e5add6 | 16 | QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap) |
dd0029c0 | 17 | { |
dd0029c0 | 18 | char *cmdline; |
dd0029c0 | 19 | |
790bbb97 | 20 | struct QOSState *qs = g_new(QOSState, 1); |
dd0029c0 | 21 | |
f1518d11 | 22 | cmdline = g_strdup_vprintf(cmdline_fmt, ap); |
dd0029c0 | 23 | qs->qts = qtest_start(cmdline); |
90e5add6 | 24 | qs->ops = ops; |
2ecd7e2f LV |
25 | if (ops) { |
26 | if (ops->init_allocator) { | |
27 | qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS); | |
28 | } | |
29 | if (ops->qpci_init && qs->alloc) { | |
30 | qs->pcibus = ops->qpci_init(qs->alloc); | |
31 | } | |
90e5add6 | 32 | } |
dd0029c0 JS |
33 | |
34 | g_free(cmdline); | |
35 | return qs; | |
36 | } | |
37 | ||
f1518d11 JS |
38 | /** |
39 | * Launch QEMU with the given command line, | |
40 | * and then set up interrupts and our guest malloc interface. | |
41 | */ | |
90e5add6 | 42 | QOSState *qtest_boot(QOSOps *ops, const char *cmdline_fmt, ...) |
f1518d11 JS |
43 | { |
44 | QOSState *qs; | |
45 | va_list ap; | |
46 | ||
47 | va_start(ap, cmdline_fmt); | |
90e5add6 | 48 | qs = qtest_vboot(ops, cmdline_fmt, ap); |
f1518d11 JS |
49 | va_end(ap); |
50 | ||
51 | return qs; | |
52 | } | |
53 | ||
dd0029c0 JS |
54 | /** |
55 | * Tear down the QEMU instance. | |
56 | */ | |
61ae5cf3 | 57 | void qtest_common_shutdown(QOSState *qs) |
dd0029c0 | 58 | { |
2ecd7e2f LV |
59 | if (qs->ops) { |
60 | if (qs->pcibus && qs->ops->qpci_free) { | |
61 | qs->ops->qpci_free(qs->pcibus); | |
62 | qs->pcibus = NULL; | |
63 | } | |
64 | if (qs->alloc && qs->ops->uninit_allocator) { | |
65 | qs->ops->uninit_allocator(qs->alloc); | |
66 | qs->alloc = NULL; | |
67 | } | |
dd0029c0 JS |
68 | } |
69 | qtest_quit(qs->qts); | |
70 | g_free(qs); | |
71 | } | |
122fdf2d | 72 | |
61ae5cf3 LV |
73 | void qtest_shutdown(QOSState *qs) |
74 | { | |
75 | if (qs->ops && qs->ops->shutdown) { | |
76 | qs->ops->shutdown(qs); | |
77 | } else { | |
78 | qtest_common_shutdown(qs); | |
79 | } | |
80 | } | |
81 | ||
085248ae JS |
82 | void set_context(QOSState *s) |
83 | { | |
84 | global_qtest = s->qts; | |
85 | } | |
86 | ||
87 | static QDict *qmp_execute(const char *command) | |
88 | { | |
89 | char *fmt; | |
90 | QDict *rsp; | |
91 | ||
92 | fmt = g_strdup_printf("{ 'execute': '%s' }", command); | |
93 | rsp = qmp(fmt); | |
94 | g_free(fmt); | |
95 | ||
96 | return rsp; | |
97 | } | |
98 | ||
99 | void migrate(QOSState *from, QOSState *to, const char *uri) | |
100 | { | |
101 | const char *st; | |
102 | char *s; | |
103 | QDict *rsp, *sub; | |
104 | bool running; | |
105 | ||
106 | set_context(from); | |
107 | ||
108 | /* Is the machine currently running? */ | |
109 | rsp = qmp_execute("query-status"); | |
110 | g_assert(qdict_haskey(rsp, "return")); | |
111 | sub = qdict_get_qdict(rsp, "return"); | |
112 | g_assert(qdict_haskey(sub, "running")); | |
113 | running = qdict_get_bool(sub, "running"); | |
114 | QDECREF(rsp); | |
115 | ||
116 | /* Issue the migrate command. */ | |
117 | s = g_strdup_printf("{ 'execute': 'migrate'," | |
118 | "'arguments': { 'uri': '%s' } }", | |
119 | uri); | |
120 | rsp = qmp(s); | |
121 | g_free(s); | |
122 | g_assert(qdict_haskey(rsp, "return")); | |
123 | QDECREF(rsp); | |
124 | ||
125 | /* Wait for STOP event, but only if we were running: */ | |
126 | if (running) { | |
127 | qmp_eventwait("STOP"); | |
128 | } | |
129 | ||
130 | /* If we were running, we can wait for an event. */ | |
131 | if (running) { | |
132 | migrate_allocator(from->alloc, to->alloc); | |
133 | set_context(to); | |
134 | qmp_eventwait("RESUME"); | |
135 | return; | |
136 | } | |
137 | ||
138 | /* Otherwise, we need to wait: poll until migration is completed. */ | |
139 | while (1) { | |
140 | rsp = qmp_execute("query-migrate"); | |
141 | g_assert(qdict_haskey(rsp, "return")); | |
142 | sub = qdict_get_qdict(rsp, "return"); | |
143 | g_assert(qdict_haskey(sub, "status")); | |
144 | st = qdict_get_str(sub, "status"); | |
145 | ||
146 | /* "setup", "active", "completed", "failed", "cancelled" */ | |
147 | if (strcmp(st, "completed") == 0) { | |
148 | QDECREF(rsp); | |
149 | break; | |
150 | } | |
151 | ||
152 | if ((strcmp(st, "setup") == 0) || (strcmp(st, "active") == 0)) { | |
153 | QDECREF(rsp); | |
154 | g_usleep(5000); | |
155 | continue; | |
156 | } | |
157 | ||
158 | fprintf(stderr, "Migration did not complete, status: %s\n", st); | |
159 | g_assert_not_reached(); | |
160 | } | |
161 | ||
162 | migrate_allocator(from->alloc, to->alloc); | |
163 | set_context(to); | |
164 | } | |
165 | ||
cb11e7b2 JS |
166 | bool have_qemu_img(void) |
167 | { | |
168 | char *rpath; | |
169 | const char *path = getenv("QTEST_QEMU_IMG"); | |
170 | if (!path) { | |
171 | return false; | |
172 | } | |
173 | ||
174 | rpath = realpath(path, NULL); | |
175 | if (!rpath) { | |
176 | return false; | |
177 | } else { | |
178 | free(rpath); | |
179 | return true; | |
180 | } | |
181 | } | |
182 | ||
122fdf2d JS |
183 | void mkimg(const char *file, const char *fmt, unsigned size_mb) |
184 | { | |
185 | gchar *cli; | |
186 | bool ret; | |
187 | int rc; | |
188 | GError *err = NULL; | |
189 | char *qemu_img_path; | |
190 | gchar *out, *out2; | |
cb11e7b2 | 191 | char *qemu_img_abs_path; |
122fdf2d JS |
192 | |
193 | qemu_img_path = getenv("QTEST_QEMU_IMG"); | |
cb11e7b2 JS |
194 | g_assert(qemu_img_path); |
195 | qemu_img_abs_path = realpath(qemu_img_path, NULL); | |
196 | g_assert(qemu_img_abs_path); | |
122fdf2d | 197 | |
cb11e7b2 | 198 | cli = g_strdup_printf("%s create -f %s %s %uM", qemu_img_abs_path, |
122fdf2d JS |
199 | fmt, file, size_mb); |
200 | ret = g_spawn_command_line_sync(cli, &out, &out2, &rc, &err); | |
201 | if (err) { | |
202 | fprintf(stderr, "%s\n", err->message); | |
203 | g_error_free(err); | |
204 | } | |
205 | g_assert(ret && !err); | |
206 | ||
207 | /* In glib 2.34, we have g_spawn_check_exit_status. in 2.12, we don't. | |
208 | * glib 2.43.91 implementation assumes that any non-zero is an error for | |
209 | * windows, but uses extra precautions for Linux. However, | |
210 | * 0 is only possible if the program exited normally, so that should be | |
211 | * sufficient for our purposes on all platforms, here. */ | |
212 | if (rc) { | |
213 | fprintf(stderr, "qemu-img returned status code %d\n", rc); | |
214 | } | |
215 | g_assert(!rc); | |
216 | ||
217 | g_free(out); | |
218 | g_free(out2); | |
219 | g_free(cli); | |
cb11e7b2 | 220 | free(qemu_img_abs_path); |
122fdf2d JS |
221 | } |
222 | ||
223 | void mkqcow2(const char *file, unsigned size_mb) | |
224 | { | |
225 | return mkimg(file, "qcow2", size_mb); | |
226 | } | |
72c85e94 JS |
227 | |
228 | void prepare_blkdebug_script(const char *debug_fn, const char *event) | |
229 | { | |
230 | FILE *debug_file = fopen(debug_fn, "w"); | |
231 | int ret; | |
232 | ||
233 | fprintf(debug_file, "[inject-error]\n"); | |
234 | fprintf(debug_file, "event = \"%s\"\n", event); | |
235 | fprintf(debug_file, "errno = \"5\"\n"); | |
236 | fprintf(debug_file, "state = \"1\"\n"); | |
237 | fprintf(debug_file, "immediately = \"off\"\n"); | |
238 | fprintf(debug_file, "once = \"on\"\n"); | |
239 | ||
240 | fprintf(debug_file, "[set-state]\n"); | |
241 | fprintf(debug_file, "event = \"%s\"\n", event); | |
242 | fprintf(debug_file, "new_state = \"2\"\n"); | |
243 | fflush(debug_file); | |
244 | g_assert(!ferror(debug_file)); | |
245 | ||
246 | ret = fclose(debug_file); | |
247 | g_assert(ret == 0); | |
248 | } | |
ab4f7057 JS |
249 | |
250 | void generate_pattern(void *buffer, size_t len, size_t cycle_len) | |
251 | { | |
252 | int i, j; | |
253 | unsigned char *tx = (unsigned char *)buffer; | |
254 | unsigned char p; | |
255 | size_t *sx; | |
256 | ||
257 | /* Write an indicative pattern that varies and is unique per-cycle */ | |
258 | p = rand() % 256; | |
259 | for (i = 0; i < len; i++) { | |
260 | tx[i] = p++ % 256; | |
261 | if (i % cycle_len == 0) { | |
262 | p = rand() % 256; | |
263 | } | |
264 | } | |
265 | ||
266 | /* force uniqueness by writing an id per-cycle */ | |
267 | for (i = 0; i < len / cycle_len; i++) { | |
268 | j = i * cycle_len; | |
269 | if (j + sizeof(*sx) <= len) { | |
270 | sx = (size_t *)&tx[j]; | |
271 | *sx = i; | |
272 | } | |
273 | } | |
274 | } |