2014-01-27 15:56:26

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFC] Initial avctp test

From: Andrei Emeltchenko <[email protected]>

This is initial invalid packet size test, sent as RFC since I am not
sure what might be tested for avctp.

Andrei Emeltchenko (1):
unit/avctp: Add initial AVCTP test setup

Makefile.am | 8 ++
unit/test-avctp.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 270 insertions(+)
create mode 100644 unit/test-avctp.c

--
1.8.3.2



2014-01-28 12:10:04

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [RFC] Initial avctp test

Hi Andrei,

>>> This is initial invalid packet size test, sent as RFC since I am not
>>> sure what might be tested for avctp.
>>>
>>> Andrei Emeltchenko (1):
>>> unit/avctp: Add initial AVCTP test setup
>>>
>>> Makefile.am | 8 ++
>>> unit/test-avctp.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>> 2 files changed, 270 insertions(+)
>>> create mode 100644 unit/test-avctp.c
>>>
>>> --
>>> 1.8.3.2
>>
>> You should follow the testing spec:
>> https://www.bluetooth.org/docman/handlers/DownloadDoc.ashx?doc_id=40404
>>
>> Please follow the same name convention that is used by the testing
>> spec and for now do not introduce any other test that is not part of
>> the testing spec.
>
> I have this AVCTP.TS spec but what might be tested for example with test
> case "TP/CCM/BV-01-C"?
>
> Even looking at session_cb() for AVCTP there seems to be only packet
> length check. In contrast for AVDTP there is command parser so you might
> be able to test something.
>
> Shall we test AVRCP instead?

AVRCP and AVCTP need to be tested. This is not one or the other. It is both.

Regards

Marcel


2014-01-28 10:36:44

by Andrei Emeltchenko

[permalink] [raw]
Subject: Re: [RFC] Initial avctp test

Hi Luiz,

On Mon, Jan 27, 2014 at 10:36:42AM -0800, Luiz Augusto von Dentz wrote:
> Hi Andrei,
>
> On Mon, Jan 27, 2014 at 7:56 AM, Andrei Emeltchenko
> <[email protected]> wrote:
> > From: Andrei Emeltchenko <[email protected]>
> >
> > This is initial invalid packet size test, sent as RFC since I am not
> > sure what might be tested for avctp.
> >
> > Andrei Emeltchenko (1):
> > unit/avctp: Add initial AVCTP test setup
> >
> > Makefile.am | 8 ++
> > unit/test-avctp.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 2 files changed, 270 insertions(+)
> > create mode 100644 unit/test-avctp.c
> >
> > --
> > 1.8.3.2
>
> You should follow the testing spec:
> https://www.bluetooth.org/docman/handlers/DownloadDoc.ashx?doc_id=40404
>
> Please follow the same name convention that is used by the testing
> spec and for now do not introduce any other test that is not part of
> the testing spec.

I have this AVCTP.TS spec but what might be tested for example with test
case "TP/CCM/BV-01-C"?

Even looking at session_cb() for AVCTP there seems to be only packet
length check. In contrast for AVDTP there is command parser so you might
be able to test something.

Shall we test AVRCP instead?

Best regards
Andrei Emeltchenko

2014-01-27 18:36:42

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [RFC] Initial avctp test

Hi Andrei,

On Mon, Jan 27, 2014 at 7:56 AM, Andrei Emeltchenko
<[email protected]> wrote:
> From: Andrei Emeltchenko <[email protected]>
>
> This is initial invalid packet size test, sent as RFC since I am not
> sure what might be tested for avctp.
>
> Andrei Emeltchenko (1):
> unit/avctp: Add initial AVCTP test setup
>
> Makefile.am | 8 ++
> unit/test-avctp.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 270 insertions(+)
> create mode 100644 unit/test-avctp.c
>
> --
> 1.8.3.2

You should follow the testing spec:
https://www.bluetooth.org/docman/handlers/DownloadDoc.ashx?doc_id=40404

Please follow the same name convention that is used by the testing
spec and for now do not introduce any other test that is not part of
the testing spec.

--
Luiz Augusto von Dentz

2014-01-27 15:56:27

by Andrei Emeltchenko

[permalink] [raw]
Subject: [RFC] unit/avctp: Add initial AVCTP test setup

From: Andrei Emeltchenko <[email protected]>

---
Makefile.am | 8 ++
unit/test-avctp.c | 262 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 270 insertions(+)
create mode 100644 unit/test-avctp.c

diff --git a/Makefile.am b/Makefile.am
index 3a1e6dc..1a44a9f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -273,6 +273,14 @@ unit_test_avdtp_SOURCES = unit/test-avdtp.c \
android/avdtp.c android/avdtp.h
unit_test_avdtp_LDADD = @GLIB_LIBS@

+unit_tests += unit/test-avctp
+
+unit_test_avctp_SOURCES = unit/test-avctp.c \
+ src/shared/util.h src/shared/util.c \
+ src/log.h src/log.c \
+ android/avctp.c android/avctp.h
+unit_test_avctp_LDADD = @GLIB_LIBS@
+
unit_tests += unit/test-gdbus-client

unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
diff --git a/unit/test-avctp.c b/unit/test-avctp.c
new file mode 100644
index 0000000..236b34a
--- /dev/null
+++ b/unit/test-avctp.c
@@ -0,0 +1,262 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Intel Corporation. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "src/shared/util.h"
+#include "src/log.h"
+
+#include "android/avctp.h"
+
+struct test_pdu {
+ bool valid;
+ bool fragmented;
+ const uint8_t *data;
+ size_t size;
+};
+
+struct test_data {
+ char *test_name;
+ struct test_pdu *pdu_list;
+};
+
+struct context {
+ GMainLoop *main_loop;
+ struct avctp *session;
+ guint source;
+ guint process;
+ int fd;
+ unsigned int pdu_offset;
+ const struct test_data *data;
+};
+
+#define data(args...) ((const unsigned char[]) { args })
+
+#define raw_pdu(args...) \
+ { \
+ .valid = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define frg_pdu(args...) \
+ { \
+ .valid = true, \
+ .fragmented = true, \
+ .data = data(args), \
+ .size = sizeof(data(args)), \
+ }
+
+#define define_test(name, function, args...) \
+ do { \
+ const struct test_pdu pdus[] = { \
+ args, { } \
+ }; \
+ static struct test_data data; \
+ data.test_name = g_strdup(name); \
+ data.pdu_list = g_malloc(sizeof(pdus)); \
+ memcpy(data.pdu_list, pdus, sizeof(pdus)); \
+ g_test_add_data_func(name, &data, function); \
+ } while (0)
+
+static void test_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ g_print("%s%s\n", prefix, str);
+}
+
+static void test_free(gconstpointer user_data)
+{
+ const struct test_data *data = user_data;
+
+ g_free(data->test_name);
+ g_free(data->pdu_list);
+}
+
+static gboolean context_quit(gpointer user_data)
+{
+ struct context *context = user_data;
+
+ if (context->process > 0)
+ g_source_remove(context->process);
+
+ g_main_loop_quit(context->main_loop);
+
+ return FALSE;
+}
+
+static gboolean send_pdu(gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ ssize_t len;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ len = write(context->fd, pdu->data, pdu->size);
+
+ if (g_test_verbose())
+ util_hexdump('<', pdu->data, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ if (pdu->fragmented)
+ return send_pdu(user_data);
+
+ context->process = 0;
+ return FALSE;
+}
+
+static void context_process(struct context *context)
+{
+ if (!context->data->pdu_list[context->pdu_offset].valid) {
+ context_quit(context);
+ return;
+ }
+
+ context->process = g_idle_add(send_pdu, context);
+}
+
+static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ unsigned char buf[512];
+ ssize_t len;
+ int fd;
+
+ g_print("%s\n", __func__);
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+ context->source = 0;
+ g_print("%s: cond %x\n", __func__, cond);
+ if (g_str_equal(context->data->test_name, "/Test small packet"))
+ return context_quit(context);
+
+ return FALSE;
+ }
+
+ fd = g_io_channel_unix_get_fd(channel);
+
+ len = read(fd, buf, sizeof(buf));
+
+ g_assert(len > 0);
+
+ if (g_test_verbose())
+ util_hexdump('>', buf, len, test_debug, "AVCTP: ");
+
+ g_assert_cmpint(len, ==, pdu->size);
+
+ g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
+
+ if (!pdu->fragmented)
+ context_process(context);
+
+ g_print("Test handler ended\n");
+
+ return TRUE;
+}
+
+static struct context *create_context(uint16_t version, gconstpointer data)
+{
+ struct context *context = g_new0(struct context, 1);
+ GIOChannel *channel;
+ int err, sv[2];
+
+ context->main_loop = g_main_loop_new(NULL, FALSE);
+ g_assert(context->main_loop);
+
+ err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+ g_assert(err == 0);
+
+ context->session = avctp_new(sv[0], 672, 672, version);
+ g_assert(context->session != NULL);
+
+ channel = g_io_channel_unix_new(sv[1]);
+
+ g_io_channel_set_close_on_unref(channel, TRUE);
+ g_io_channel_set_encoding(channel, NULL, NULL);
+ g_io_channel_set_buffered(channel, FALSE);
+
+ context->source = g_io_add_watch(channel,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ test_handler, context);
+ g_assert(context->source > 0);
+
+ g_io_channel_unref(channel);
+
+ context->fd = sv[1];
+ context->data = data;
+
+ return context;
+}
+
+static void execute_context(struct context *context)
+{
+ g_main_loop_run(context->main_loop);
+
+ if (context->source > 0)
+ g_source_remove(context->source);
+
+ g_main_loop_unref(context->main_loop);
+
+ test_free(context->data);
+ g_free(context);
+}
+
+static void test_server(gconstpointer data)
+{
+ struct context *context = create_context(0x0100, data);
+
+ g_idle_add(send_pdu, context);
+
+ execute_context(context);
+}
+
+int main(int argc, char *argv[])
+{
+ g_test_init(&argc, &argv, NULL);
+
+ if (g_test_verbose())
+ __btd_log_init("*", 0);
+
+ define_test("/Test small packet", test_server, raw_pdu(0x00, 0x00));
+
+ return g_test_run();
+}
--
1.8.3.2