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, char *data) {
196  write(fd, &first_byte, 1);
197  write(fd, data, strlen(data));
198}
199
200static void write_packet_reentry(int fd, char first_byte, char *data) {
201  write(fd, &first_byte, 1);
202
203  int length = strlen(data);
204  for (int i = 0; i < length; i++) {
205    write(fd, &data[i], 1);
206    semaphore_wait(reentry_semaphore);
207  }
208}
209
210TEST_F(HciHalH4Test, test_transmit) {
211  reset_for(transmit);
212
213  // Send a command packet
214  hal->transmit_data(DATA_TYPE_COMMAND, (uint8_t *)(sample_data1 + 1), strlen(sample_data1 + 1));
215  expect_socket_data(sockfd[1], DATA_TYPE_COMMAND, sample_data1 + 1);
216
217  // Send an acl packet
218  hal->transmit_data(DATA_TYPE_ACL, (uint8_t *)(sample_data2 + 1), strlen(sample_data2 + 1));
219  expect_socket_data(sockfd[1], DATA_TYPE_ACL, sample_data2 + 1);
220
221  // Send an sco packet
222  hal->transmit_data(DATA_TYPE_SCO, (uint8_t *)(sample_data3 + 1), strlen(sample_data3 + 1));
223  expect_socket_data(sockfd[1], DATA_TYPE_SCO, sample_data3 + 1);
224}
225
226TEST_F(HciHalH4Test, test_read_synchronous) {
227  reset_for(read_synchronous);
228
229  write_packet(sockfd[1], DATA_TYPE_ACL, acl_data);
230  write_packet(sockfd[1], HCI_BLE_EVENT, corrupted_data);
231  write_packet(sockfd[1], DATA_TYPE_SCO, sco_data);
232  write_packet(sockfd[1], DATA_TYPE_EVENT, event_data);
233
234  // Wait for all data to be received before calling the test good
235  semaphore_wait(done);
236  EXPECT_CALL_COUNT(data_ready_callback, 3);
237}
238
239TEST_F(HciHalH4Test, test_read_async_reentry) {
240  reset_for(read_async_reentry);
241
242  reentry_semaphore = semaphore_new(0);
243  reentry_i = 0;
244
245  write_packet_reentry(sockfd[1], DATA_TYPE_ACL, sample_data3);
246
247  // write_packet_reentry ensures the data has been received
248  semaphore_free(reentry_semaphore);
249}
250
251TEST_F(HciHalH4Test, test_type_byte_only_must_not_signal_data_ready) {
252  reset_for(type_byte_only);
253
254  char byte = DATA_TYPE_ACL;
255  write(sockfd[1], &byte, 1);
256
257  fd_set read_fds;
258
259  // Wait until the byte we wrote was picked up
260  do {
261    FD_ZERO(&read_fds);
262    FD_SET(sockfd[0], &read_fds);
263
264    struct timeval timeout;
265    timeout.tv_sec = 0;
266    timeout.tv_usec = 0;
267
268    select(sockfd[0] + 1, &read_fds, NULL, NULL, &timeout);
269  } while(FD_ISSET(sockfd[0], &read_fds));
270}
271