tests: Add sequencing test

Add a small test (to be expanded later) to check behaviour of MCTP
packet sequencing.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
diff --git a/Makefile b/Makefile
index 6a7c46b..1084eec 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@
 
 test_util_objs = tests/test-utils.o
 
-tests = test_eid
+tests = test_eid test_seq
 
 test_targets = $(tests:%=tests/%)
 
diff --git a/tests/test_seq.c b/tests/test_seq.c
new file mode 100644
index 0000000..f9b282e
--- /dev/null
+++ b/tests/test_seq.c
@@ -0,0 +1,102 @@
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <libmctp.h>
+
+#include "test-utils.h"
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+struct test_ctx {
+	struct mctp			*mctp;
+	struct mctp_binding_test	*binding;
+	int				rx_count;
+	uint8_t				rx_data[4];
+	size_t				rx_len;
+};
+
+static void test_rx(uint8_t eid, void *data, void *msg, size_t len)
+{
+	struct test_ctx *ctx = data;
+
+	(void)eid;
+
+	ctx->rx_count++;
+
+	/* append incoming message data to the existing rx_data */
+	assert(len <= sizeof(ctx->rx_data));
+	assert(ctx->rx_len + len <= sizeof(ctx->rx_data));
+
+	memcpy(ctx->rx_data + ctx->rx_len, msg, len);
+	ctx->rx_len += len;
+}
+
+#define SEQ(x) (x << MCTP_HDR_SEQ_SHIFT)
+
+struct test {
+	int		n_packets;
+	uint8_t		flags_seq_tags[4];
+	int		exp_rx_count;
+	size_t		exp_rx_len;
+} tests[] = {
+	{
+		/* single packet */
+		.n_packets = 1,
+		.flags_seq_tags = {
+			SEQ(1) | MCTP_HDR_FLAG_SOM | MCTP_HDR_FLAG_EOM,
+		},
+		.exp_rx_count = 1,
+		.exp_rx_len = 1,
+	},
+};
+
+static void run_one_test(struct test_ctx *ctx, struct test *test)
+{
+	const mctp_eid_t local_eid = 8;
+	const mctp_eid_t remote_eid = 9;
+	struct {
+		struct mctp_hdr	hdr;
+		uint8_t		payload[1];
+	} pktbuf;
+	int i;
+
+	ctx->rx_count = 0;
+	ctx->rx_len = 0;
+
+	mctp_test_stack_init(&ctx->mctp, &ctx->binding, local_eid);
+
+	mctp_set_rx_all(ctx->mctp, test_rx, ctx);
+
+	for (i = 0; i < test->n_packets; i++) {
+		memset(&pktbuf, 0, sizeof(pktbuf));
+		pktbuf.hdr.dest = local_eid;
+		pktbuf.hdr.src = remote_eid;
+		pktbuf.hdr.flags_seq_tag = test->flags_seq_tags[i];
+		pktbuf.payload[0] = i;
+
+		mctp_binding_test_rx_raw(ctx->binding,
+				&pktbuf, sizeof(pktbuf));
+	}
+
+	assert(ctx->rx_count == test->exp_rx_count);
+	assert(ctx->rx_len == test->exp_rx_len);
+
+	/* ensure the payload data was reconstructed correctly */
+	for (i = 0; i < (int)ctx->rx_len; i++)
+		assert(ctx->rx_data[i] == i);
+}
+
+
+int main(void)
+{
+	struct test_ctx ctx;
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(tests); i++)
+		run_one_test(&ctx, &tests[i]);
+
+	return EXIT_SUCCESS;
+}