pebble/tests/fw/comm/test_kernel_le_client.c
2025-01-27 11:38:16 -08:00

297 lines
8.6 KiB
C

/*
* Copyright 2024 Google LLC
*
* 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 "clar.h"
#include "comm/ble/gap_le_advert.h"
#include "comm/ble/gap_le_task.h"
#include "comm/ble/gatt_client_subscriptions.h"
#include "comm/ble/kernel_le_client/kernel_le_client.h"
#include "comm/ble/kernel_le_client/test/test_definition.h"
#include "kernel/events.h"
#include "util/size.h"
// Stubs
////////////////////////////////////////////////////////////////////////////////////////////////////
#include "fake_system_task.h"
#include "stubs_logging.h"
#include "stubs_passert.h"
#include "stubs_pbl_malloc.h"
#include "stubs_rand_ptr.h"
#include "stubs_rtc.h"
void ams_create(void) {
}
void ams_destroy(void) {
}
void ancs_create(void) {
}
void ancs_destroy(void) {
}
void app_launch_handle_disconnection(void) {
}
BTBondingID bt_persistent_storage_get_ble_ancs_bonding(void) {
return 1;
}
bool bt_persistent_storage_is_ble_ancs_bonding(BTBondingID bonding) {
return true;
}
void gap_le_advert_unschedule_job_types(GAPLEAdvertisingJobTag *tag_types, size_t num_types) {
}
void gap_le_connect_cancel_all(GAPLEClient client) {
}
BTErrno gap_le_connect_cancel_by_bonding(BTBondingID bonding_id, GAPLEClient client) {
return BTErrnoOK;
}
BTErrno gap_le_connect_connect_by_bonding(BTBondingID bonding_id, bool auto_reconnect,
bool is_pairing_required, GAPLEClient client) {
return BTErrnoOK;
}
void gap_le_slave_reconnect_start(void) {
}
void gap_le_slave_reconnect_stop(void) {
}
BTErrno gatt_client_discovery_discover_all(const BTDeviceInternal *device) {
return BTErrnoOK;
}
uint16_t gatt_client_subscriptions_consume_notification(BLECharacteristic *characteristic_ref_out,
uint8_t *value_out,
uint16_t *value_length_in_out,
GAPLEClient client, bool *has_more_out) {
return 0;
}
bool gatt_client_subscriptions_get_notification_header(GAPLEClient client,
GATTBufferedNotificationHeader *header_out) {
return false;
}
void gatt_client_subscriptions_reschedule(GAPLEClient c) {
}
void launcher_task_add_callback(CallbackEventCallback callback, void *data) {
// Use fake_system_task as mock:
system_task_add_callback(callback, data);
}
void ppogatt_create(void) {
}
void ppogatt_destroy(void) {
}
void ppogatt_handle_buffer_empty(void) {
}
void bt_driver_reconnect_try_now(bool ignore_paused) {
}
void gatt_client_op_cleanup(GAPLEClient client) {
}
void ppogatt_reset_disconnect_counter(void) {
}
// Fakes & Helpers
////////////////////////////////////////////////////////////////////////////////////////////////////
static const BTDeviceInternal s_test_device = {
.address = (const BTDeviceAddress) {
.octets = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66},
},
};
typedef enum {
TestServiceInstanceComplete = 1,
TestServiceInstanceIncomplete = 2,
TestServiceInstanceUnsupported = 3,
} TestServiceInstance;
static BLEService s_service_handles[] = {
TestServiceInstanceComplete,
TestServiceInstanceIncomplete,
TestServiceInstanceUnsupported,
};
typedef enum {
TestCharacteristicInstanceCompleteOne = 11,
TestCharacteristicInstanceCompleteTwo = 12,
TestCharacteristicInstanceIncompleteOne = 21,
TestCharacteristicInstanceUnsupported = 33,
} TestCharacteristicInstance;
Uuid gatt_client_service_get_uuid(BLEService service_ref) {
switch (service_ref) {
case TestServiceInstanceComplete:
case TestServiceInstanceIncomplete:
return s_test_service_uuid;
case TestServiceInstanceUnsupported:
default:
return UUID_INVALID;
}
}
uint8_t gatt_client_service_get_characteristics_matching_uuids(BLEService service_ref,
BLECharacteristic characteristics_out[],
const Uuid matching_characteristic_uuids[],
uint8_t num_characteristics) {
cl_assert_equal_i(num_characteristics, TestCharacteristicCount);
switch (service_ref) {
case TestServiceInstanceComplete:
characteristics_out[0] = TestCharacteristicInstanceCompleteOne;
characteristics_out[1] = TestCharacteristicInstanceCompleteTwo;
return 2;
case TestServiceInstanceIncomplete:
characteristics_out[0] = TestCharacteristicInstanceIncompleteOne;
return 1;
case TestCharacteristicInstanceUnsupported:
characteristics_out[0] = TestCharacteristicInstanceUnsupported;
return 1;
default:
return 0;
}
}
static int s_read_responses_consumed_count;
void gatt_client_consume_read_response(uintptr_t object_ref,
uint8_t value_out[],
uint16_t value_length,
GAPLEClient client) {
++s_read_responses_consumed_count;
}
static int s_services_discovered_count;
void test_client_handle_service_discovered(BLECharacteristic *characteristics) {
++s_services_discovered_count;
}
void test_client_invalidate_all_references(void) {
}
void test_client_handle_service_removed(BLECharacteristic *characteristics,
uint8_t num_characteristics) {
}
static bool s_can_handle_characteristic;
bool test_client_can_handle_characteristic(BLECharacteristic characteristic) {
return s_can_handle_characteristic;
}
void test_client_handle_write_response(BLECharacteristic characteristic, BLEGATTError error) {
}
void test_client_handle_subscribe(BLECharacteristic characteristic,
BLESubscription subscription_type, BLEGATTError error) {
}
void test_client_handle_read_or_notification(BLECharacteristic characteristic, const uint8_t *value,
size_t value_length, BLEGATTError error) {
}
// Tests
////////////////////////////////////////////////////////////////////////////////////////////////////
void test_kernel_le_client__initialize(void) {
s_services_discovered_count = 0;
s_read_responses_consumed_count = 0;
s_can_handle_characteristic = false;
kernel_le_client_init();
}
void test_kernel_le_client__cleanup(void) {
kernel_le_client_deinit();
fake_system_task_callbacks_cleanup();
}
void test_kernel_le_client__read_response_consumed_even_if_client_is_gone(void) {
// Simulate the client goes away:
s_can_handle_characteristic = false;
PebbleEvent e = (PebbleEvent) {
.type = PEBBLE_BLE_GATT_CLIENT_EVENT,
.bluetooth.le.gatt_client = {
.object_ref = TestCharacteristicInstanceCompleteOne,
.value_length = 1,
.gatt_error = BLEGATTErrorSuccess,
.subtype = PebbleBLEGATTClientEventTypeCharacteristicRead,
},
};
kernel_le_client_handle_event(&e);
cl_assert_equal_i(s_read_responses_consumed_count, 1);
// When value_length is zero, the read response should NOT be consumed:
e.bluetooth.le.gatt_client.value_length = 0;
s_read_responses_consumed_count = 0;
kernel_le_client_handle_event(&e);
cl_assert_equal_i(s_read_responses_consumed_count, 0);
}
void test_kernel_le_client__service_added(void) {
uint8_t num_services_added = ARRAY_LENGTH(s_service_handles);
PebbleBLEGATTClientServiceEventInfo *info =
kernel_malloc(sizeof(PebbleBLEGATTClientServiceEventInfo) +
(num_services_added * sizeof(BLEService)));
*info = (PebbleBLEGATTClientServiceEventInfo) {
.status = BTErrnoOK,
.type = PebbleServicesAdded,
.device = s_test_device,
};
info->services_added_data.num_services_added = num_services_added;
memcpy(info->services_added_data.services, s_service_handles, sizeof(s_service_handles));
PebbleEvent e = (PebbleEvent) {
.type = PEBBLE_BLE_GATT_CLIENT_EVENT,
.bluetooth.le.gatt_client_service = {
.info = info,
.subtype = PebbleBLEGATTClientEventTypeServiceChange,
},
};
kernel_le_client_handle_event(&e);
// Found one complete service instance:
cl_assert_equal_i(s_services_discovered_count, 1);
kernel_free(info);
}
// FIXME: PBL-27751: Improve test coverage of kernel_le_client.c