| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <lib/unittest/unittest.h> |
| |
| #include <lk/macros.h> |
| #include <stdarg.h> |
| #include <stddef.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <time.h> |
| #include <trusty_ipc.h> |
| #include <uapi/err.h> |
| |
| #define LOG_TAG "unittest" |
| |
| #include <lk/trace.h> |
| |
| #define MAX_PORT_BUF_SIZE 4096 /* max size of per port buffer */ |
| |
| #define TLOGI(fmt, ...) \ |
| do { \ |
| fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ##__VA_ARGS__); \ |
| } while (0) |
| |
| static handle_t ipc_printf_handle = INVALID_IPC_HANDLE; |
| |
| static int send_msg_wait(handle_t handle, struct ipc_msg* msg) { |
| int ret; |
| struct uevent ev; |
| |
| ret = send_msg(handle, msg); |
| if (ret != ERR_NOT_ENOUGH_BUFFER) { |
| return ret; |
| } |
| |
| ret = wait(handle, &ev, INFINITE_TIME); |
| if (ret < 0) { |
| return ret; |
| } |
| |
| if (ev.event & IPC_HANDLE_POLL_SEND_UNBLOCKED) { |
| return send_msg(handle, msg); |
| } |
| |
| if (ev.event & IPC_HANDLE_POLL_MSG) { |
| return ERR_BUSY; |
| } |
| |
| if (ev.event & IPC_HANDLE_POLL_HUP) { |
| return ERR_CHANNEL_CLOSED; |
| } |
| |
| return ret; |
| } |
| |
| enum test_message_header { |
| TEST_PASSED = 0, |
| TEST_FAILED = 1, |
| TEST_MESSAGE = 2, |
| TEST_MESSAGE_HEADER_COUNT = 3, |
| }; |
| |
| int unittest_printf(const char* fmt, ...) { |
| char buf[256]; |
| struct iovec tx_iov = {buf, 1}; |
| ipc_msg_t tx_msg = {1, &tx_iov, 0, NULL}; |
| va_list ap; |
| int ret; |
| int slen; |
| |
| if (ipc_printf_handle == INVALID_IPC_HANDLE) { |
| return 0; |
| } |
| |
| va_start(ap, fmt); |
| ret = vsnprintf(buf + 1, sizeof(buf) - 1, fmt, ap); |
| va_end(ap); |
| |
| if (ret < 0) { |
| return ret; |
| } |
| slen = MIN(ret, (int)sizeof(buf) - 1 - 1); |
| |
| buf[0] = TEST_MESSAGE; |
| tx_iov.iov_len = 1 + ret; |
| ret = send_msg_wait(ipc_printf_handle, &tx_msg); |
| if (ret < 0) { |
| return ret; |
| } |
| |
| return slen; |
| } |
| |
| /* |
| * Application entry point |
| */ |
| int unittest_main(struct unittest** tests, size_t test_count) { |
| int ret; |
| handle_t hset; |
| uevent_t evt = { |
| .event = ~0U, |
| }; |
| struct unittest* test; |
| uuid_t dummy_uuid; |
| |
| ret = handle_set_create(); |
| if (ret < 0) { |
| TLOGI("failed to create handle set: %d\n", ret); |
| return ret; |
| } |
| hset = ret; |
| |
| /* create control port and just wait on it */ |
| for (; test_count; test_count--) { |
| test = *tests++; |
| ret = port_create(test->port_name, 1, MAX_PORT_BUF_SIZE, |
| IPC_PORT_ALLOW_NS_CONNECT | IPC_PORT_ALLOW_TA_CONNECT); |
| if (ret < 0) { |
| TLOGI("failed to create port %s: %d\n", test->port_name, ret); |
| return ret; |
| } |
| test->_port_handle = (handle_t)ret; |
| evt.handle = test->_port_handle; |
| evt.cookie = test; |
| ret = handle_set_ctrl(hset, HSET_ADD, &evt); |
| if (ret < 0) { |
| TLOGI("failed to add %s to handle set: %d\n", test->port_name, ret); |
| return ret; |
| } |
| TLOGI("added port %s handle, %d, to handleset %d\n", test->port_name, |
| test->_port_handle, hset); |
| } |
| |
| /* and just wait forever for now */ |
| TLOGI("waiting forever\n"); |
| for (;;) { |
| ret = wait(hset, &evt, INFINITE_TIME); |
| test = evt.cookie; |
| TLOGI("got event (ret=%d): ev=%x handle=%d port=%s\n", ret, evt.event, |
| evt.handle, test->port_name); |
| if (ret < 0) |
| break; |
| if (evt.event & IPC_HANDLE_POLL_READY) { |
| /* get connection request */ |
| ret = accept(evt.handle, &dummy_uuid); |
| TLOGI("accept returned %d\n", ret); |
| if (ret >= 0) { |
| char tx_buffer[1]; |
| struct iovec tx_iov = { |
| tx_buffer, |
| sizeof(tx_buffer), |
| }; |
| ipc_msg_t tx_msg = {1, &tx_iov, 0, NULL}; |
| |
| /* then run unittest test */ |
| ipc_printf_handle = ret; |
| tx_buffer[0] = test->run_test(test) ? TEST_PASSED : TEST_FAILED; |
| ipc_printf_handle = INVALID_IPC_HANDLE; |
| |
| send_msg_wait(ret, &tx_msg); |
| |
| /* and close it */ |
| close(ret); |
| } |
| } |
| } |
| |
| return ret; |
| } |