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

209 lines
6.9 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 "applib/app_message/app_message_internal.h"
#include "process_management/app_run_state.h"
#include "process_management/launcher_app_message.h"
#include "services/common/comm_session/session_internal.h"
#include "system/passert.h"
#include "util/dict.h"
#include "util/uuid.h"
extern void launcher_app_message_reset(void);
extern void launcher_app_message_protocol_msg_callback_deprecated(CommSession *session,
const uint8_t* data,
size_t length);
// Fakes
////////////////////////////////////
#include "fake_app_manager.h"
#include "fake_pbl_malloc.h"
#include "fake_session.h"
#include "fake_system_task.h"
// Stubs
////////////////////////////////////
#include "stubs_bt_lock.h"
#include "stubs_hexdump.h"
#include "stubs_logging.h"
#include "stubs_passert.h"
#include "stubs_rand_ptr.h"
AppRunStateCommand s_last_cmd;
Transport *s_transport;
CommSession *s_session;
#define APP_UUID_RAW 0x13, 0xEC, 0xC6, 0x7C, 0xCC, 0xB4, 0x4A, 0x96, \
0x9E, 0xA7, 0x50, 0xE5, 0x09, 0xCA, 0xF7, 0x3A
#define LAUNCHER_MESSAGE_ENDPOINT_ID (0x31)
#define RUN_STATE_KEY (1)
#define STATE_FETCH_KEY (2)
#define INVALID_KEY (0xffffffff)
#define RUNNING (1)
#define NOT_RUNNING (0)
#define TRANSACTION_ID (0xA5)
#define assert_ack(ack) \
fake_comm_session_process_send_next(); \
const AppMessageAck ack_message = { \
.header = { \
.command = ack ? CMD_ACK : CMD_NACK, \
.transaction_id = TRANSACTION_ID, \
}, \
}; \
fake_transport_assert_sent(s_transport, 0, LAUNCHER_MESSAGE_ENDPOINT_ID, \
(const uint8_t *)&ack_message, sizeof(ack_message));
void app_run_state_command(CommSession *session, AppRunStateCommand cmd, const Uuid *uuid) {
s_last_cmd = cmd;
Uuid expected_uuid = {APP_UUID_RAW};
cl_assert_equal_b(uuid, &expected_uuid);
if (cmd == APP_RUN_STATE_STATUS_COMMAND) {
launcher_app_message_send_app_state_deprecated(uuid, RUNNING);
}
}
// Helpers
////////////////////////////////////
static const uint8_t *prv_build_push_message(uint32_t key, uint8_t value, uint32_t *size) {
// Using static buffer is OK because tests are single-threaded
static uint8_t buffer[sizeof(AppMessagePush) + sizeof(Tuple) + sizeof(uint8_t)];
AppMessagePush *push_message = (AppMessagePush *)buffer;
*push_message = (const AppMessagePush) {
.header = {
.command = 0x01, // Push
.transaction_id = TRANSACTION_ID,
},
.uuid = {
APP_UUID_RAW
},
};
*size = sizeof(Dictionary) + sizeof(Tuple) + sizeof(uint8_t);
const Tuplet tuplet = TupletInteger(key, value);
cl_assert_equal_i(DICT_OK, dict_serialize_tuplets_to_buffer(&tuplet, 1,
(uint8_t *)&push_message->dictionary,
size));
// Including sizeof(AppMessagePush):
*size = sizeof(buffer);
return buffer;
}
static void prv_receive(uint32_t key, uint8_t value) {
uint32_t length = 0;
const uint8_t *msg= prv_build_push_message(key, value, &length);
launcher_app_message_protocol_msg_callback_deprecated(s_session, msg, length);
}
// Tests
////////////////////////////////////
void test_launcher_app_message__initialize(void) {
launcher_app_message_reset();
s_last_cmd = APP_RUN_STATE_INVALID_COMMAND;
fake_comm_session_init();
s_transport = fake_transport_create(TransportDestinationSystem, NULL, NULL);
s_session = fake_transport_set_connected(s_transport, true /* connected */);
}
void test_launcher_app_message__cleanup(void) {
fake_transport_destroy(s_transport);
s_transport = NULL;
s_session = NULL;
fake_comm_session_cleanup();
fake_system_task_callbacks_cleanup();
}
void test_launcher_app_message__ingore_too_short_message(void) {
uint8_t too_short = 0;
launcher_app_message_protocol_msg_callback_deprecated(s_session, &too_short, sizeof(too_short));
fake_comm_session_process_send_next();
fake_transport_assert_nothing_sent(s_transport);
}
void test_launcher_app_message__receive_unknown_key(void) {
prv_receive(INVALID_KEY, 0);
assert_ack(false);
}
void test_launcher_app_message__receive_push_start(void) {
prv_receive(RUN_STATE_KEY, RUNNING);
assert_ack(true);
cl_assert_equal_i(APP_RUN_STATE_RUN_COMMAND, s_last_cmd);
}
void test_launcher_app_message__receive_push_stop(void) {
prv_receive(RUN_STATE_KEY, NOT_RUNNING);
assert_ack(true);
cl_assert_equal_i(APP_RUN_STATE_STOP_COMMAND, s_last_cmd);
}
void test_launcher_app_message__receive_push_fetch_request(void) {
prv_receive(STATE_FETCH_KEY, RUNNING);
assert_ack(true);
cl_assert_equal_i(APP_RUN_STATE_STATUS_COMMAND, s_last_cmd);
}
void test_launcher_app_message__ignore_acks(void) {
const AppMessageAck ack_message = {
.header = {
.command = CMD_ACK,
.transaction_id = TRANSACTION_ID,
},
};
launcher_app_message_protocol_msg_callback_deprecated(s_session, (const uint8_t *)&ack_message,
sizeof(ack_message));
fake_comm_session_process_send_next();
fake_transport_assert_nothing_sent(s_transport);
}
void test_launcher_app_message__send_app_state(void) {
Uuid uuid = {APP_UUID_RAW};
bool running = true;
launcher_app_message_send_app_state_deprecated(&uuid, running);
// Even though the Launcher App Message documentation states that the value is a uint8_t,
// the original implementation used uint32_t for the outbound pushes... Let's keep that "bug":
uint8_t buffer[sizeof(AppMessagePush) + sizeof(Tuple) + sizeof(uint32_t)];
AppMessagePush *push_message = (AppMessagePush *)buffer;
*push_message = (const AppMessagePush) {
.header = {
.command = CMD_PUSH,
.transaction_id = 0,
},
.uuid = {APP_UUID_RAW},
};
uint32_t size = sizeof(Dictionary) + sizeof(Tuple) + sizeof(uint32_t);
const Tuplet tuplet = TupletInteger(RUN_STATE_KEY, (uint32_t) (running ? RUNNING : NOT_RUNNING));
PBL_ASSERTN(DICT_OK == dict_serialize_tuplets_to_buffer(&tuplet, 1,
(uint8_t *)&push_message->dictionary,
&size));
fake_comm_session_process_send_next();
fake_transport_assert_sent(s_transport, 0, LAUNCHER_MESSAGE_ENDPOINT_ID, buffer, sizeof(buffer));
}