1/****************************************************************************** 2 * 3 * Copyright (C) 2014 Google, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at: 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 ******************************************************************************/ 18 19#include <gtest/gtest.h> 20 21#include "AllocationTestHarness.h" 22 23extern "C" { 24#include <stdint.h> 25#include <sys/types.h> 26#include <sys/socket.h> 27#include <unistd.h> 28 29#include "osi/include/osi.h" 30#include "osi/include/semaphore.h" 31#include "hci_hal.h" 32#include "test_stubs.h" 33#include "vendor.h" 34} 35 36DECLARE_TEST_MODES( 37 init, 38 open, 39 close_fn, 40 transmit, 41 read_synchronous, 42 read_async_reentry, 43 type_byte_only 44); 45 46// Use as packet type to test stream_corrupted_during_le_scan_workaround() 47static const uint8_t HCI_BLE_EVENT = 0x3e; 48 49static char sample_data1[100] = "A point is that which has no part."; 50static char sample_data2[100] = "A line is breadthless length."; 51static char sample_data3[100] = "The ends of a line are points."; 52static char acl_data[100] = "A straight line is a line which lies evenly with the points on itself."; 53static char sco_data[100] = "A surface is that which has length and breadth only."; 54static char event_data[100] = "The edges of a surface are lines."; 55 56// Test data for stream_corrupted_during_le_scan_workaround() 57static char corrupted_data[] = { 0x5 /* length of remaining data */, 'H', 'e', 'l', 'l', 'o' }; 58 59static const hci_hal_t *hal; 60static int dummy_serial_fd; 61static int reentry_i = 0; 62 63static semaphore_t *done; 64static semaphore_t *reentry_semaphore; 65 66static void expect_packet_synchronous(serial_data_type_t type, char *packet_data) { 67 int length = strlen(packet_data); 68 for (int i = 0; i < length; i++) { 69 uint8_t byte; 70 EXPECT_EQ((size_t)1, hal->read_data(type, &byte, 1)); 71 EXPECT_EQ(packet_data[i], byte); 72 } 73 74 hal->packet_finished(type); 75} 76 77STUB_FUNCTION(int, vendor_send_command, (vendor_opcode_t opcode, void *param)) 78 DURING(open) AT_CALL(0) { 79 EXPECT_EQ(VENDOR_OPEN_USERIAL, opcode); 80 // Give back the dummy fd and the number 1 to say we opened 1 port 81 ((int *)param)[0] = dummy_serial_fd; 82 return 1; 83 } 84 85 DURING(close_fn) AT_CALL(0) { 86 EXPECT_EQ(VENDOR_CLOSE_USERIAL, opcode); 87 return 0; 88 } 89 90 UNEXPECTED_CALL; 91 return 0; 92} 93 94STUB_FUNCTION(void, data_ready_callback, (serial_data_type_t type)) 95 DURING(read_synchronous) { 96 AT_CALL(0) { 97 EXPECT_EQ(DATA_TYPE_ACL, type); 98 expect_packet_synchronous(type, acl_data); 99 return; 100 } 101 AT_CALL(1) { 102 EXPECT_EQ(DATA_TYPE_SCO, type); 103 expect_packet_synchronous(type, sco_data); 104 return; 105 } 106 AT_CALL(2) { 107 EXPECT_EQ(DATA_TYPE_EVENT, type); 108 expect_packet_synchronous(type, event_data); 109 semaphore_post(done); 110 return; 111 } 112 } 113 114 DURING(read_async_reentry) { 115 EXPECT_EQ(DATA_TYPE_ACL, type); 116 117 uint8_t byte; 118 size_t bytes_read; 119 while ((bytes_read = hal->read_data(type, &byte, 1)) != 0) { 120 EXPECT_EQ(sample_data3[reentry_i], byte); 121 semaphore_post(reentry_semaphore); 122 reentry_i++; 123 if (reentry_i == (int)strlen(sample_data3)) { 124 hal->packet_finished(type); 125 return; 126 } 127 } 128 129 return; 130 } 131 132 UNEXPECTED_CALL; 133} 134 135static void reset_for(TEST_MODES_T next) { 136 RESET_CALL_COUNT(vendor_send_command); 137 RESET_CALL_COUNT(data_ready_callback); 138 CURRENT_TEST_MODE = next; 139} 140 141class HciHalH4Test : public AllocationTestHarness { 142 protected: 143 virtual void SetUp() { 144 AllocationTestHarness::SetUp(); 145 hal = hci_hal_h4_get_test_interface(&vendor); 146 vendor.send_command = vendor_send_command; 147 callbacks.data_ready = data_ready_callback; 148 149 socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd); 150 dummy_serial_fd = sockfd[0]; 151 done = semaphore_new(0); 152 thread = thread_new("hal_test"); 153 154 reset_for(init); 155 EXPECT_TRUE(hal->init(&callbacks, thread)); 156 157 reset_for(open); 158 EXPECT_TRUE(hal->open()); 159 EXPECT_CALL_COUNT(vendor_send_command, 1); 160 } 161 162 virtual void TearDown() { 163 reset_for(close_fn); 164 hal->close(); 165 EXPECT_CALL_COUNT(vendor_send_command, 1); 166 167 semaphore_free(done); 168 thread_free(thread); 169 AllocationTestHarness::TearDown(); 170 } 171 172 int sockfd[2]; 173 vendor_t vendor; 174 thread_t *thread; 175 hci_hal_callbacks_t callbacks; 176}; 177 178static void expect_socket_data(int fd, char first_byte, char *data) { 179 int length = strlen(data) + 1; // + 1 for data type code 180 int i; 181 182 for (i = 0; i < length; i++) { 183 fd_set read_fds; 184 FD_ZERO(&read_fds); 185 FD_SET(fd, &read_fds); 186 select(fd + 1, &read_fds, NULL, NULL, NULL); 187 188 char byte; 189 read(fd, &byte, 1); 190 191 EXPECT_EQ(i == 0 ? first_byte : data[i - 1], byte); 192 } 193} 194 195static void write_packet(int fd, char first_byte, const void *data, 196 size_t datalen) { 197 write(fd, &first_byte, 1); 198 write(fd, data, datalen); 199} 200 201static void write_packet_reentry(int fd, char first_byte, const void *data, 202 size_t datalen) { 203 write(fd, &first_byte, 1); 204 205 for (size_t i = 0; i < datalen; i++) { 206 write(fd, static_cast<const uint8_t *>(data) + i, 1); 207 semaphore_wait(reentry_semaphore); 208 } 209} 210 211TEST_F(HciHalH4Test, test_transmit) { 212 reset_for(transmit); 213 214 // Send a command packet 215 hal->transmit_data(DATA_TYPE_COMMAND, (uint8_t *)(sample_data1 + 1), strlen(sample_data1 + 1)); 216 expect_socket_data(sockfd[1], DATA_TYPE_COMMAND, sample_data1 + 1); 217 218 // Send an acl packet 219 hal->transmit_data(DATA_TYPE_ACL, (uint8_t *)(sample_data2 + 1), strlen(sample_data2 + 1)); 220 expect_socket_data(sockfd[1], DATA_TYPE_ACL, sample_data2 + 1); 221 222 // Send an sco packet 223 hal->transmit_data(DATA_TYPE_SCO, (uint8_t *)(sample_data3 + 1), strlen(sample_data3 + 1)); 224 expect_socket_data(sockfd[1], DATA_TYPE_SCO, sample_data3 + 1); 225} 226 227TEST_F(HciHalH4Test, test_read_synchronous) { 228 reset_for(read_synchronous); 229 230 write_packet(sockfd[1], DATA_TYPE_ACL, acl_data, strlen(acl_data)); 231 write_packet(sockfd[1], HCI_BLE_EVENT, corrupted_data, 232 sizeof(corrupted_data)); 233 write_packet(sockfd[1], DATA_TYPE_SCO, sco_data, strlen(sco_data)); 234 write_packet(sockfd[1], DATA_TYPE_EVENT, event_data, strlen(event_data)); 235 236 // Wait for all data to be received before calling the test good 237 semaphore_wait(done); 238 EXPECT_CALL_COUNT(data_ready_callback, 3); 239} 240 241TEST_F(HciHalH4Test, test_read_async_reentry) { 242 reset_for(read_async_reentry); 243 244 reentry_semaphore = semaphore_new(0); 245 reentry_i = 0; 246 247 write_packet_reentry(sockfd[1], DATA_TYPE_ACL, sample_data3, 248 strlen(sample_data3)); 249 250 // write_packet_reentry ensures the data has been received 251 semaphore_free(reentry_semaphore); 252} 253 254TEST_F(HciHalH4Test, test_type_byte_only_must_not_signal_data_ready) { 255 reset_for(type_byte_only); 256 257 char byte = DATA_TYPE_ACL; 258 write(sockfd[1], &byte, 1); 259 260 fd_set read_fds; 261 262 // Wait until the byte we wrote was picked up 263 do { 264 FD_ZERO(&read_fds); 265 FD_SET(sockfd[0], &read_fds); 266 267 struct timeval timeout; 268 timeout.tv_sec = 0; 269 timeout.tv_usec = 0; 270 271 select(sockfd[0] + 1, &read_fds, NULL, NULL, &timeout); 272 } while(FD_ISSET(sockfd[0], &read_fds)); 273} 274