| /****************************************************************************** |
| * |
| * Copyright (C) 2014 Google, Inc. |
| * |
| * 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 <gtest/gtest.h> |
| |
| #include "AllocationTestHarness.h" |
| |
| #include <stdint.h> |
| #include <sys/types.h> |
| #include <sys/socket.h> |
| #include <unistd.h> |
| |
| #include "osi/include/osi.h" |
| #include "osi/include/semaphore.h" |
| #include "hci_hal.h" |
| #include "test_stubs.h" |
| #include "vendor.h" |
| |
| DECLARE_TEST_MODES( |
| init, |
| open, |
| close_fn, |
| transmit, |
| read_synchronous, |
| read_async_reentry |
| ); |
| |
| static char sample_data1[100] = "A point is that which has no part."; |
| static char sample_data2[100] = "A line is breadthless length."; |
| static char sample_data3[100] = "The ends of a line are points."; |
| static char acl_data[100] = "A straight line is a line which lies evenly with the points on itself."; |
| static char event_data[100] = "The edges of a surface are lines."; |
| |
| static const hci_hal_t *hal; |
| static int command_out_fd; |
| static int acl_out_fd; |
| static int acl_in_fd; |
| static int event_in_fd; |
| static int reentry_i = 0; |
| |
| static semaphore_t *done; |
| static semaphore_t *reentry_semaphore; |
| |
| static void expect_packet_synchronous(serial_data_type_t type, char *packet_data) { |
| int length = strlen(packet_data); |
| for (int i = 0; i < length; i++) { |
| uint8_t byte; |
| EXPECT_EQ((size_t)1, hal->read_data(type, &byte, 1)); |
| EXPECT_EQ(packet_data[i], byte); |
| } |
| |
| hal->packet_finished(type); |
| } |
| |
| STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void *param)) |
| DURING(open) AT_CALL(0) { |
| EXPECT_EQ(VENDOR_OPEN_USERIAL, opcode); |
| ((int *)param)[CH_CMD] = command_out_fd; |
| ((int *)param)[CH_ACL_OUT] = acl_out_fd; |
| ((int *)param)[CH_ACL_IN] = acl_in_fd; |
| ((int *)param)[CH_EVT] = event_in_fd; |
| return 4; |
| } |
| |
| DURING(close_fn) AT_CALL(0) { |
| EXPECT_EQ(VENDOR_CLOSE_USERIAL, opcode); |
| return 0; |
| } |
| |
| UNEXPECTED_CALL; |
| return 0; |
| } |
| |
| STUB_FUNCTION(void, data_ready_callback, (serial_data_type_t type)) |
| DURING(read_synchronous) { |
| AT_CALL(0) { |
| EXPECT_EQ(DATA_TYPE_ACL, type); |
| expect_packet_synchronous(type, acl_data); |
| semaphore_post(done); |
| return; |
| } |
| AT_CALL(1) { |
| EXPECT_EQ(DATA_TYPE_EVENT, type); |
| expect_packet_synchronous(type, event_data); |
| semaphore_post(done); |
| return; |
| } |
| } |
| |
| DURING(read_async_reentry) { |
| EXPECT_EQ(DATA_TYPE_ACL, type); |
| |
| uint8_t byte; |
| size_t bytes_read; |
| while ((bytes_read = hal->read_data(type, &byte, 1)) != 0) { |
| EXPECT_EQ(sample_data3[reentry_i], byte); |
| semaphore_post(reentry_semaphore); |
| reentry_i++; |
| if (reentry_i == (int)strlen(sample_data3)) { |
| hal->packet_finished(type); |
| return; |
| } |
| } |
| |
| return; |
| } |
| |
| UNEXPECTED_CALL; |
| } |
| |
| static void reset_for(TEST_MODES_T next) { |
| RESET_CALL_COUNT(vendor_send_command); |
| RESET_CALL_COUNT(data_ready_callback); |
| CURRENT_TEST_MODE = next; |
| } |
| |
| class HciHalMctTest : public AllocationTestHarness { |
| protected: |
| virtual void SetUp() { |
| AllocationTestHarness::SetUp(); |
| hal = hci_hal_mct_get_test_interface(&vendor); |
| vendor.send_command = vendor_send_command; |
| callbacks.data_ready = data_ready_callback; |
| |
| socketpair(AF_LOCAL, SOCK_STREAM, 0, command_sockfd); |
| socketpair(AF_LOCAL, SOCK_STREAM, 0, event_sockfd); |
| socketpair(AF_LOCAL, SOCK_STREAM, 0, acl_in_sockfd); |
| socketpair(AF_LOCAL, SOCK_STREAM, 0, acl_out_sockfd); |
| command_out_fd = command_sockfd[0]; |
| acl_out_fd = acl_out_sockfd[0]; |
| acl_in_fd = acl_in_sockfd[0]; |
| event_in_fd = event_sockfd[0]; |
| |
| done = semaphore_new(0); |
| thread = thread_new("hal_test"); |
| |
| reset_for(init); |
| EXPECT_TRUE(hal->init(&callbacks, thread)); |
| |
| reset_for(open); |
| EXPECT_TRUE(hal->open()); |
| EXPECT_CALL_COUNT(vendor_send_command, 1); |
| } |
| |
| virtual void TearDown() { |
| reset_for(close_fn); |
| hal->close(); |
| EXPECT_CALL_COUNT(vendor_send_command, 1); |
| |
| semaphore_free(done); |
| thread_free(thread); |
| AllocationTestHarness::TearDown(); |
| } |
| |
| int command_sockfd[2]; |
| int event_sockfd[2]; |
| int acl_in_sockfd[2]; |
| int acl_out_sockfd[2]; |
| vendor_t vendor; |
| thread_t *thread; |
| hci_hal_callbacks_t callbacks; |
| }; |
| |
| static void expect_socket_data(int fd, char *data) { |
| int length = strlen(data); |
| int i; |
| |
| for (i = 0; i < length; i++) { |
| fd_set read_fds; |
| FD_ZERO(&read_fds); |
| FD_SET(fd, &read_fds); |
| select(fd + 1, &read_fds, NULL, NULL, NULL); |
| |
| char byte; |
| read(fd, &byte, 1); |
| |
| EXPECT_EQ(data[i], byte); |
| } |
| } |
| |
| static void write_packet(int fd, char *data) { |
| write(fd, data, strlen(data)); |
| } |
| |
| static void write_packet_reentry(int fd, char *data) { |
| int length = strlen(data); |
| for (int i = 0; i < length; i++) { |
| write(fd, &data[i], 1); |
| semaphore_wait(reentry_semaphore); |
| } |
| } |
| |
| TEST_F(HciHalMctTest, test_transmit) { |
| reset_for(transmit); |
| |
| // Send a command packet |
| hal->transmit_data(DATA_TYPE_COMMAND, (uint8_t *)(sample_data1), strlen(sample_data1)); |
| expect_socket_data(command_sockfd[1], sample_data1); |
| |
| // Send an acl packet |
| hal->transmit_data(DATA_TYPE_ACL, (uint8_t *)(sample_data2), strlen(sample_data2)); |
| expect_socket_data(acl_out_sockfd[1], sample_data2); |
| } |
| |
| TEST_F(HciHalMctTest, test_read_synchronous) { |
| reset_for(read_synchronous); |
| |
| write_packet(acl_in_sockfd[1], acl_data); |
| semaphore_wait(done); |
| |
| write_packet(event_sockfd[1], event_data); |
| semaphore_wait(done); |
| |
| EXPECT_CALL_COUNT(data_ready_callback, 2); |
| } |
| |
| TEST_F(HciHalMctTest, test_read_async_reentry) { |
| reset_for(read_async_reentry); |
| |
| reentry_semaphore = semaphore_new(0); |
| reentry_i = 0; |
| |
| write_packet_reentry(acl_in_sockfd[1], sample_data3); |
| |
| // write_packet_reentry ensures the data has been received |
| semaphore_free(reentry_semaphore); |
| } |