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