1 /* Copyright 2020 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Tests for host flashrom utilities.
6 */
7
8 /* For strdup */
9 #define _POSIX_C_SOURCE 200809L
10
11 #include <fcntl.h>
12 #include <getopt.h>
13 #include <stdbool.h>
14 #include <stdint.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
18
19 #include "2common.h"
20 #include "2return_codes.h"
21 #include "common/tests.h"
22 #include "host_misc.h"
23 #include "flashrom.h"
24 #include "subprocess.h"
25
26 #define MOCK_TMPFILE_NAME "/tmp/vb2_unittest"
27 #define MOCK_ROM_CONTENTS "bloop123"
28
29 static bool flashrom_mock_success = true;
30 static enum { FLASHROM_NONE, FLASHROM_READ, FLASHROM_WRITE } captured_operation;
31 static enum {
32 FLASHROM_VERIFY_UNSPECIFIED,
33 FLASHROM_VERIFY_FAST,
34 } captured_verify;
35 static const char *captured_op_filename;
36 static const char *captured_region_param;
37 static const char *captured_programmer;
38 static uint8_t *captured_rom_contents;
39 static uint32_t captured_rom_size;
40
41 /* Mocked mkstemp for tests. */
mkstemp(char * template_name)42 int mkstemp(char *template_name)
43 {
44 strncpy(template_name, MOCK_TMPFILE_NAME, strlen(template_name));
45 return open(template_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
46 }
47
48 /* Mocked subprocess_run for tests. */
subprocess_run(const char * const argv[],struct subprocess_target * input,struct subprocess_target * output,struct subprocess_target * error)49 int subprocess_run(const char *const argv[],
50 struct subprocess_target *input,
51 struct subprocess_target *output,
52 struct subprocess_target *error)
53 {
54 int argc;
55 int opt;
56 int rv;
57 /* getopt_long wants an int instead of an enum, bummer... */
58 int captured_verify_int = FLASHROM_VERIFY_UNSPECIFIED;
59 struct option long_opts[] = {
60 {
61 .name = "noverify-all",
62 .has_arg = no_argument,
63 .flag = &captured_verify_int,
64 .val = FLASHROM_VERIFY_FAST,
65 },
66 };
67
68 /* Reset static variables to their defaults. */
69 captured_operation = FLASHROM_NONE;
70 captured_operation = FLASHROM_VERIFY_UNSPECIFIED;
71 captured_op_filename = NULL;
72 captured_region_param = NULL;
73 captured_programmer = NULL;
74 captured_rom_contents = NULL;
75 captured_rom_size = 0;
76 optind = 0;
77
78 /* Count the number of arguments, a required formalism for
79 getopt. */
80 for (argc = 0; argv[argc]; argc++)
81 continue;
82
83 /* We only understand the subset of arguments used by the
84 wrapper library. If it's updated to support more modes of
85 operation, this unit test code should be updated too. */
86 while ((opt = getopt_long(argc, (char *const *)argv,
87 ":p:r:w:i:", long_opts, NULL)) != -1) {
88 /* Always consume the next argument if it does not
89 start with a dash. We have to muck with getopt's
90 global variables to make this happen. */
91 if (opt == ':' && argv[optind] && argv[optind][0] != '-') {
92 optarg = strdup(argv[optind]);
93 optind++;
94 opt = optopt;
95 } else if (optarg && optarg[0] == '-') {
96 optarg = NULL;
97 optind--;
98 } else if (optarg) {
99 optarg = strdup(optarg);
100 }
101
102 switch (opt) {
103 case 'p':
104 captured_programmer = optarg;
105 break;
106 case 'r':
107 captured_operation = FLASHROM_READ;
108 captured_op_filename = optarg;
109 break;
110 case 'w':
111 captured_operation = FLASHROM_WRITE;
112 captured_op_filename = optarg;
113 break;
114 case 'i':
115 captured_region_param = optarg;
116 break;
117 case 0:
118 /* long option */
119 break;
120 default:
121 return 1;
122 }
123 }
124
125 if (optind != argc) {
126 /* Extra arguments we don't understand. */
127 return 1;
128 }
129
130 rv = !flashrom_mock_success;
131 captured_verify = captured_verify_int;
132
133 if (captured_operation == FLASHROM_READ) {
134 /* Write the mocked string we read from the ROM. */
135 rv |= vb2_write_file(MOCK_TMPFILE_NAME, MOCK_ROM_CONTENTS,
136 strlen(MOCK_ROM_CONTENTS));
137 } else if (captured_operation == FLASHROM_WRITE) {
138 /* Capture the buffer contents we wrote to the ROM. */
139 rv |= vb2_read_file(MOCK_TMPFILE_NAME, &captured_rom_contents,
140 &captured_rom_size);
141 }
142
143 return rv;
144 }
145
test_read_whole_chip(void)146 static void test_read_whole_chip(void)
147 {
148 struct firmware_image image = {
149 .programmer = "someprog",
150 };
151
152 TEST_SUCC(flashrom_read(&image, NULL),
153 "Flashrom read succeeds");
154 TEST_STR_EQ(captured_programmer, "someprog",
155 "Using specified programmer");
156 TEST_EQ(captured_operation, FLASHROM_READ, "Doing a read operation");
157 TEST_EQ(captured_verify, FLASHROM_VERIFY_UNSPECIFIED,
158 "Verification not enabled");
159 TEST_STR_EQ(captured_op_filename, MOCK_TMPFILE_NAME,
160 "Reading to correct file");
161 TEST_PTR_EQ(captured_region_param, NULL, "Not operating on a region");
162 TEST_EQ(image.size, strlen(MOCK_ROM_CONTENTS), "Contents correct size");
163 TEST_SUCC(memcmp(image.data, MOCK_ROM_CONTENTS, image.size),
164 "Buffer has correct contents");
165
166 free(image.data);
167 }
168
test_read_region(void)169 static void test_read_region(void)
170 {
171 struct firmware_image image = {
172 .programmer = "someprog",
173 };
174
175 TEST_SUCC(flashrom_read(&image, "SOME_REGION"),
176 "Flashrom read succeeds");
177 TEST_STR_EQ(captured_programmer, "someprog",
178 "Using specified programmer");
179 TEST_EQ(captured_operation, FLASHROM_READ, "Doing a read operation");
180 TEST_EQ(captured_verify, FLASHROM_VERIFY_UNSPECIFIED,
181 "Verification not enabled");
182 TEST_PTR_EQ(captured_op_filename, NULL,
183 "Not doing a read of the whole ROM");
184 TEST_STR_EQ(captured_region_param, "SOME_REGION:" MOCK_TMPFILE_NAME,
185 "Reading to correct file and from correct region");
186 TEST_EQ(image.size, strlen(MOCK_ROM_CONTENTS), "Contents correct size");
187 TEST_SUCC(memcmp(image.data, MOCK_ROM_CONTENTS, image.size),
188 "Buffer has correct contents");
189
190 free(image.data);
191 }
192
test_read_failure(void)193 static void test_read_failure(void)
194 {
195 struct firmware_image image = {
196 .programmer = "someprog",
197 };
198
199 flashrom_mock_success = false;
200 TEST_NEQ(flashrom_read(&image, "SOME_REGION"),
201 VB2_SUCCESS, "Flashrom read fails");
202 flashrom_mock_success = true;
203 }
204
test_write_whole_chip(void)205 static void test_write_whole_chip(void)
206 {
207 uint8_t buf[sizeof(MOCK_ROM_CONTENTS) - 1];
208 struct firmware_image image = {
209 .programmer = "someprog",
210 .data = buf,
211 .size = sizeof(buf),
212 };
213
214 memcpy(buf, MOCK_ROM_CONTENTS, sizeof(buf));
215
216 TEST_SUCC(flashrom_write(&image, NULL),
217 "Flashrom write succeeds");
218 TEST_STR_EQ(captured_programmer, "someprog",
219 "Using specified programmer");
220 TEST_EQ(captured_operation, FLASHROM_WRITE, "Doing a write operation");
221 TEST_EQ(captured_verify, FLASHROM_VERIFY_FAST,
222 "Fast verification enabled");
223 TEST_STR_EQ(captured_op_filename, MOCK_TMPFILE_NAME,
224 "Writing to correct file");
225 TEST_PTR_EQ(captured_region_param, NULL, "Not operating on a region");
226 TEST_EQ(captured_rom_size, strlen(MOCK_ROM_CONTENTS),
227 "Contents correct size");
228 TEST_SUCC(memcmp(captured_rom_contents, MOCK_ROM_CONTENTS,
229 captured_rom_size), "Buffer has correct contents");
230 }
231
test_write_region(void)232 static void test_write_region(void)
233 {
234 uint8_t buf[sizeof(MOCK_ROM_CONTENTS) - 1];
235 struct firmware_image image = {
236 .programmer = "someprog",
237 .data = buf,
238 .size = sizeof(buf),
239 };
240
241 memcpy(buf, MOCK_ROM_CONTENTS, sizeof(buf));
242
243 TEST_SUCC(flashrom_write(&image, "SOME_REGION"),
244 "Flashrom write succeeds");
245 TEST_STR_EQ(captured_programmer, "someprog",
246 "Using specified programmer");
247 TEST_EQ(captured_operation, FLASHROM_WRITE, "Doing a write operation");
248 TEST_EQ(captured_verify, FLASHROM_VERIFY_FAST,
249 "Fast verification enabled");
250 TEST_PTR_EQ(captured_op_filename, NULL,
251 "Not doing a write of the whole ROM");
252 TEST_STR_EQ(captured_region_param, "SOME_REGION:" MOCK_TMPFILE_NAME,
253 "Writing to correct file and from correct region");
254 TEST_EQ(captured_rom_size, strlen(MOCK_ROM_CONTENTS),
255 "Contents correct size");
256 TEST_SUCC(memcmp(captured_rom_contents, MOCK_ROM_CONTENTS,
257 captured_rom_size), "Buffer has correct contents");
258 }
259
test_write_failure(void)260 static void test_write_failure(void)
261 {
262 uint8_t buf[20] = { 0 };
263 struct firmware_image image = {
264 .programmer = "someprog",
265 .data = buf,
266 .size = sizeof(buf),
267 };
268
269 flashrom_mock_success = false;
270 TEST_NEQ(flashrom_write(&image, "SOME_REGION"),
271 VB2_SUCCESS, "Flashrom write fails");
272 flashrom_mock_success = true;
273 }
274
main(int argc,char * argv[])275 int main(int argc, char *argv[])
276 {
277 test_read_whole_chip();
278 test_read_region();
279 test_read_failure();
280 test_write_whole_chip();
281 test_write_region();
282 test_write_failure();
283
284 return gTestSuccess ? 0 : 255;
285 }
286