Skip to content

Commit

Permalink
Synchronize server-mock and test client code
Browse files Browse the repository at this point in the history
PCM test code assumes that requested PCM device is available upon
snd_pcm_open(). Otherwise, we will face premature failure...
  • Loading branch information
arkq committed Sep 5, 2020
1 parent a918a3f commit defe35c
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 37 deletions.
121 changes: 101 additions & 20 deletions test/inc/server.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,104 @@
* 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.
*
* This project is licensed under the terms of the MIT license.
*
*/

#include <ctype.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

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)
Expand All @@ -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)
Expand All @@ -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;
}
35 changes: 23 additions & 12 deletions test/server-mock.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);

Expand Down
4 changes: 2 additions & 2 deletions test/test-alsa-ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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__);
Expand Down
6 changes: 3 additions & 3 deletions test/test-alsa-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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__);
Expand Down

0 comments on commit defe35c

Please sign in to comment.