From defe35c5436b9ec6364e538ebba541b24ad45ed0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Bokowy Date: Fri, 4 Sep 2020 22:24:22 +0200 Subject: [PATCH] Synchronize server-mock and test client code PCM test code assumes that requested PCM device is available upon snd_pcm_open(). Otherwise, we will face premature failure... --- test/inc/server.inc | 121 ++++++++++++++++++++++++++++++++++++------- test/server-mock.c | 35 ++++++++----- test/test-alsa-ctl.c | 4 +- test/test-alsa-pcm.c | 6 +-- 4 files changed, 129 insertions(+), 37 deletions(-) diff --git a/test/inc/server.inc b/test/inc/server.inc index 2bb2a6915..c32e82dd3 100644 --- a/test/inc/server.inc +++ b/test/inc/server.inc @@ -2,7 +2,7 @@ * server.inc * vim: ft=c * - * Copyright (c) 2016-2019 Arkadiusz Bokowy + * Copyright (c) 2016-2020 Arkadiusz Bokowy * * This file is a part of bluez-alsa. * @@ -10,37 +10,96 @@ * */ +#include +#include #include #include #include -#include #include #include -static char *bin_path = "."; +struct spawn_bluealsa_data { + + /* stderr from the BlueALSA server */ + FILE *f_stderr; -static void *spawn_bluealsa_server_stderr_proxy(void *data) { + pthread_mutex_t data_mtx; + pthread_cond_t data_updated; - FILE *f = (FILE *)data; + char *dbus_bus_address; + char *acquired_service_name; + unsigned int ready_count_a2dp; + unsigned int ready_count_sco; + +}; + +static char *strtrim(char *str) { + while (isspace(*str)) + str++; + if (*str == '\0') + return str; + char *end = &str[strlen(str) - 1]; + while (end > str && isspace(*end)) + end--; + end[1] = '\0'; + return str; +} + +static void *spawn_bluealsa_server_stderr_proxy(void *userdata) { + + struct spawn_bluealsa_data *data = userdata; char buffer[512]; + char *tmp; - while (fgets(buffer, sizeof(buffer), f) != NULL) + while (fgets(buffer, sizeof(buffer), data->f_stderr) != NULL) { fputs(buffer, stderr); - fclose(f); + pthread_mutex_lock(&data->data_mtx); + + if ((tmp = strstr(buffer, "DBUS_SYSTEM_BUS_ADDRESS=")) != NULL) { + data->dbus_bus_address = strtrim(strdup(tmp)); + pthread_cond_signal(&data->data_updated); + } + else if ((tmp = strstr(buffer, "BLUEALSA_DBUS_SERVICE_NAME=")) != NULL) { + data->acquired_service_name = strtrim(strdup(&tmp[27])); + pthread_cond_signal(&data->data_updated); + } + else if (strstr(buffer, "BLUEALSA_PCM_READY=A2DP:") != NULL) { + data->ready_count_a2dp++; + pthread_cond_signal(&data->data_updated); + } + else if (strstr(buffer, "BLUEALSA_PCM_READY=SCO:") != NULL) { + data->ready_count_sco++; + pthread_cond_signal(&data->data_updated); + } + + pthread_mutex_unlock(&data->data_mtx); + + } + + pthread_mutex_destroy(&data->data_mtx); + pthread_cond_destroy(&data->data_updated); + free(data->dbus_bus_address); + fclose(data->f_stderr); + free(data); return NULL; } +/* path with the server-mock binary */ +char *server_mock_path = "."; + /** * Spawn bluealsa server mock. * * @param service BlueALSA D-Bus service name. * @param timeout Timeout passed to the server-mock. + * @param wait_for_ready Block until PCMs are ready. * @param fuzzing Enable fuzzing - delayed startup. * @param source Start A2DP source. * @param sink Start A2DP sink. * @return PID of the bluealsa server mock. */ -pid_t spawn_bluealsa_server(const char *service, unsigned int timeout, bool fuzzing, bool source, bool sink) { +pid_t spawn_bluealsa_server(const char *service, unsigned int timeout, + bool wait_for_ready, bool fuzzing, bool source, bool sink) { char arg_service[32] = ""; if (service != NULL) @@ -60,7 +119,7 @@ pid_t spawn_bluealsa_server(const char *service, unsigned int timeout, bool fuzz }; char path[256]; - sprintf(path, "%s/server-mock", bin_path); + sprintf(path, "%s/server-mock", server_mock_path); int fds[2]; if (pipe(fds) == -1) @@ -76,21 +135,43 @@ pid_t spawn_bluealsa_server(const char *service, unsigned int timeout, bool fuzz close(fds[1]); - FILE *f = fdopen(fds[0], "r"); - char *line = NULL; - size_t size = 0; - ssize_t len; + struct spawn_bluealsa_data *data; + unsigned int count_a2dp = 0; + unsigned int count_sco = 0; + + if (source) + count_a2dp += 2; + if (sink) + count_a2dp += 2; - if ((len = getline(&line, &size, f)) == -1) + if ((data = calloc(1, sizeof(*data))) == NULL) + return -1; + + pthread_mutex_init(&data->data_mtx, NULL); + pthread_cond_init(&data->data_updated, NULL); + if ((data->f_stderr = fdopen(fds[0], "r")) == NULL) return -1; - if (strncmp(line, "DBUS_SYSTEM_BUS_ADDRESS", 23) == 0) { - line[len - 1] = '\0'; - putenv(line); - } pthread_t tid; - pthread_create(&tid, NULL, spawn_bluealsa_server_stderr_proxy, f); + pthread_create(&tid, NULL, spawn_bluealsa_server_stderr_proxy, data); + + pthread_mutex_lock(&data->data_mtx); + + /* wait for system bus address */ + while (data->dbus_bus_address == NULL) + pthread_cond_wait(&data->data_updated, &data->data_mtx); + putenv(data->dbus_bus_address); + + /* wait for service name acquisition */ + while (data->acquired_service_name == NULL) + pthread_cond_wait(&data->data_updated, &data->data_mtx); + + while (wait_for_ready && ( + data->ready_count_a2dp < count_a2dp || + data->ready_count_sco < count_sco)) + pthread_cond_wait(&data->data_updated, &data->data_mtx); + + pthread_mutex_unlock(&data->data_mtx); - usleep(100000); return pid; } diff --git a/test/server-mock.c b/test/server-mock.c index acc783cd4..a0ceba215 100644 --- a/test/server-mock.c +++ b/test/server-mock.c @@ -171,6 +171,7 @@ static struct ba_transport *test_transport_new_a2dp(struct ba_device *d, if (fuzzing) sleep(1); struct ba_transport *t = ba_transport_new_a2dp(d, type, owner, path, codec, configuration); + fprintf(stderr, "BLUEALSA_PCM_READY=A2DP:%s\n", batostr_(&d->addr)); t->acquire = test_transport_acquire; t->release = test_transport_release; return t; @@ -181,6 +182,7 @@ static struct ba_transport *test_transport_new_sco(struct ba_device *d, if (fuzzing) sleep(1); struct ba_transport *t = ba_transport_new_sco(d, type, owner, path, -1); + fprintf(stderr, "BLUEALSA_PCM_READY=SCO:%s\n", batostr_(&d->addr)); t->acquire = test_transport_acquire; t->release = test_transport_release; return t; @@ -266,6 +268,23 @@ void *test_bt_mock(void *userdata) { return NULL; } +static void dbus_name_acquired(GDBusConnection *conn, const char *name, void *userdata) { + (void)conn; + GMainLoop *loop = userdata; + + fprintf(stderr, "BLUEALSA_DBUS_SERVICE_NAME=%s\n", name); + + /* emulate dummy test HCI device */ + assert((a = ba_adapter_new(0)) != NULL); + + /* do not generate lots of data */ + config.sbc_quality = SBC_QUALITY_LOW; + + /* run actual BlueALSA mock thread */ + g_thread_new(NULL, test_bt_mock, loop); + +} + int main(int argc, char *argv[]) { int opt; @@ -312,16 +331,6 @@ int main(int argc, char *argv[]) { assert(bluealsa_config_init() == 0); assert((config.dbus = g_test_dbus_connection_new_sync(NULL)) != NULL); - assert(bluealsa_dbus_manager_register(NULL) != 0); - assert(g_bus_own_name_on_connection(config.dbus, service, - G_BUS_NAME_OWNER_FLAGS_NONE, NULL, NULL, NULL, NULL) != 0); - - /* do not generate lots of data */ - config.sbc_quality = SBC_QUALITY_LOW; - - /* emulate dummy test HCI device */ - assert((a = ba_adapter_new(0)) != NULL); - /* receive EPIPE error code */ struct sigaction sigact = { .sa_handler = SIG_IGN }; sigaction(SIGPIPE, &sigact, NULL); @@ -331,12 +340,14 @@ int main(int argc, char *argv[]) { sigaction(SIGUSR1, &sigact, NULL); sigaction(SIGUSR2, &sigact, NULL); + /* main loop with gracefull termination handlers */ GMainLoop *loop = g_main_loop_new(NULL, FALSE); g_unix_signal_add(SIGINT, main_loop_exit_handler, loop); g_unix_signal_add(SIGTERM, main_loop_exit_handler, loop); - /* run actual BlueALSA mock thread */ - g_thread_new(NULL, test_bt_mock, loop); + assert(bluealsa_dbus_manager_register(NULL) != 0); + assert(g_bus_own_name_on_connection(config.dbus, service, + G_BUS_NAME_OWNER_FLAGS_NONE, dbus_name_acquired, NULL, loop, NULL) != 0); g_main_loop_run(loop); diff --git a/test/test-alsa-ctl.c b/test/test-alsa-ctl.c index abfede26b..d1a51cf39 100644 --- a/test/test-alsa-ctl.c +++ b/test/test-alsa-ctl.c @@ -54,7 +54,7 @@ static int snd_ctl_open_bluealsa(snd_ctl_t **ctlp, const char *service, int mode START_TEST(test_control) { const char *service = "org.bluealsa.test"; - pid_t pid = spawn_bluealsa_server(service, 1, false, true, true); + pid_t pid = spawn_bluealsa_server(service, 1, true, false, true, true); snd_ctl_t *ctl = NULL; ck_assert_int_eq(snd_ctl_open_bluealsa(&ctl, service, 0), 0); @@ -89,7 +89,7 @@ int main(int argc, char *argv[]) { preload(argc, argv, ".libs/aloader.so"); /* test-alsa-ctl and server-mock shall be placed in the same directory */ - bin_path = dirname(argv[0]); + server_mock_path = dirname(argv[0]); Suite *s = suite_create(__FILE__); TCase *tc = tcase_create(__FILE__); diff --git a/test/test-alsa-pcm.c b/test/test-alsa-pcm.c index 78d4e9685..53914c87b 100644 --- a/test/test-alsa-pcm.c +++ b/test/test-alsa-pcm.c @@ -159,7 +159,7 @@ static int test_pcm_open(pid_t *pid, snd_pcm_t **pcm, snd_pcm_stream_t stream) { return snd_pcm_open(pcm, pcm_device, stream, 0); const char *service = "org.bluealsa.test"; - if ((*pid = spawn_bluealsa_server(service, 1, false, + if ((*pid = spawn_bluealsa_server(service, 1, true, false, stream == SND_PCM_STREAM_PLAYBACK, stream == SND_PCM_STREAM_CAPTURE)) == -1) return -1; @@ -813,7 +813,7 @@ START_TEST(test_playback_device_unplug) { ck_assert_int_eq(snd_pcm_close(pcm), 0); #endif - waitpid(pid, NULL, 0); + ck_assert_int_eq(test_pcm_close(pid, pcm), 0); } END_TEST @@ -856,7 +856,7 @@ int main(int argc, char *argv[]) { } /* test-alsa-pcm and server-mock shall be placed in the same directory */ - bin_path = dirname(argv[0]); + server_mock_path = dirname(argv[0]); Suite *s = suite_create(__FILE__); TCase *tc = tcase_create(__FILE__);