diff options
author | Jack Rosenthal <jrosenth@chromium.org> | 2019-12-10 17:16:41 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-12-11 16:26:54 +0000 |
commit | 5a4c4776f0fcd9ecd2e5075522b383470f4c49ba (patch) | |
tree | 441e417654f5fa79fee84a7d44d5b00cabbf1323 /tests | |
parent | a914db93e24fc5f5d703430c310fbf4aa764eea1 (diff) | |
download | vboot-5a4c4776f0fcd9ecd2e5075522b383470f4c49ba.tar.gz |
lib/subprocess: add callback feature to the subprocess library
For the libflashrom-compatible interface I'm working on, I needed the
ability to process data from the flashrom subprocess in a callback
function.
This adds a new type of subprocess_target, TARGET_CALLBACK, which can
read and write to/from a callback function.
BUG=chromium:478356
BRANCH=none
TEST=provided unit tests
Change-Id: I20b71000fc2b6b297a8617d2b03d0e91813007d1
Signed-off-by: Jack Rosenthal <jrosenth@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1959944
Reviewed-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/subprocess_tests.c | 111 |
1 files changed, 110 insertions, 1 deletions
diff --git a/tests/subprocess_tests.c b/tests/subprocess_tests.c index 58c8f235..75d6e493 100644 --- a/tests/subprocess_tests.c +++ b/tests/subprocess_tests.c @@ -164,12 +164,119 @@ static void test_subprocess_small_output_buffer(void) static void test_subprocess_return_code_failure(void) { - const char *const argv[] = {"false"}; + const char *const argv[] = {"false", NULL}; TEST_NEQ(subprocess_run(argv, NULL, NULL, NULL), 0, "Return value of \"false\" is nonzero"); } +struct cb_ctx { + char buffer[49 * 1024]; + char *ptr; +}; + +static ssize_t input_cb(char *buf, size_t buf_sz, void *data) +{ + struct cb_ctx *ctx = (struct cb_ctx *)data; + size_t len = (ctx->buffer + sizeof(ctx->buffer)) - ctx->ptr; + if (len > buf_sz) + len = buf_sz; + memcpy(buf, ctx->ptr, len); + ctx->ptr += len; + return len; +} + +static void test_subprocess_input_from_cb(void) +{ + struct cb_ctx ctx; + char output_buffer[sizeof(ctx.buffer)]; + const char *const argv[] = {"cat", NULL}; + + /* Initialize the input buffer with some data */ + for (size_t i = 0; i < sizeof(ctx.buffer); i++) + ctx.buffer[i] = (char)i; + ctx.ptr = ctx.buffer; + + struct subprocess_target output = { + .type = TARGET_BUFFER, + .buffer = { + .buf = output_buffer, + .size = sizeof(output_buffer), + }, + }; + + struct subprocess_target input = { + .type = TARGET_CALLBACK, + .callback = { + .cb = input_cb, + .data = &ctx, + }, + }; + TEST_EQ(subprocess_run(argv, &input, &output, NULL), 0, + "Return value of \"cat\" is zero."); + TEST_EQ(memcmp(ctx.buffer, output_buffer, sizeof(output_buffer)), 0, + "The input buffer is equal to the output buffer."); + TEST_EQ(output.buffer.bytes_consumed, sizeof(output_buffer), + "The entire output buffer should have been used."); +} + +static ssize_t output_cb(char *buf, size_t buf_sz, void *data) +{ + struct cb_ctx *ctx = (struct cb_ctx *)data; + if (ctx->ptr + buf_sz > ctx->buffer + sizeof(ctx->buffer)) { + TEST_TRUE(0, "Test failed as there is not enough space in the " + "output buffer."); + return -1; + } + memcpy(ctx->ptr, buf, buf_sz); + ctx->ptr += buf_sz; + return 0; +} + +static void test_subprocess_output_to_cb(void) +{ + struct cb_ctx ctx; + char output_buffer[sizeof(ctx.buffer)]; + const char *const argv[] = { + "bc", "-l", NULL + }; + + ctx.ptr = ctx.buffer; + + struct subprocess_target input = { + .type = TARGET_BUFFER_NULL_TERMINATED, + .buffer = { + .buf = (char *)"for (i = 0; i <= 10000; i += 1) i\n", + }, + }; + + struct subprocess_target target_via_buffer = { + .type = TARGET_BUFFER, + .buffer = { + .buf = output_buffer, + .size = sizeof(output_buffer), + }, + }; + + struct subprocess_target target_via_cb = { + .type = TARGET_CALLBACK, + .callback = { + .cb = output_cb, + .data = &ctx, + }, + }; + + TEST_EQ(subprocess_run(argv, &input, &target_via_buffer, NULL), 0, + "Return value is zero when using buffer."); + TEST_EQ(subprocess_run(argv, &input, &target_via_cb, NULL), 0, + "Return value is zero when using callback."); + TEST_EQ(ctx.ptr - ctx.buffer, target_via_buffer.buffer.bytes_consumed, + "Both commmand invocations used the same number of bytes."); + TEST_EQ(memcmp(output_buffer, ctx.buffer, + target_via_buffer.buffer.bytes_consumed), + 0, "Both output buffers are equivalent."); +} + int main(int argc, char *argv[]) { test_subprocess_output_to_buffer(); @@ -178,6 +285,8 @@ int main(int argc, char *argv[]) test_subprocess_input_null_terminated(); test_subprocess_small_output_buffer(); test_subprocess_return_code_failure(); + test_subprocess_input_from_cb(); + test_subprocess_output_to_cb(); return gTestSuccess ? 0 : 255; } |