---
Makefile.test | 21 +++++++++
tests/test-queue.cfg | 8 ++++
tests/test_queue.c | 117
+++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 146 insertions(+)
diff --git a/Makefile.test b/Makefile.test
new file mode 100644
index 000000000..41dd03c71
--- /dev/null
+++ b/Makefile.test
@@ -0,0 +1,21 @@
+include Makefile
+
+tests/haproxy_test.c: src/haproxy.c
+ sed -e 's/^int main(/int __main(/' < $< > $@
+
+tests/test_queue.o: tests/test_queue.c $(DEP)
+ $(CC) $(COPTS) \
+ -DBUILD_TARGET='"$(strip $(TARGET))"' \
+ -DBUILD_ARCH='"$(strip $(ARCH))"' \
+ -DBUILD_CPU='"$(strip $(CPU))"' \
+ -DBUILD_CC='"$(strip $(CC))"' \
+ -DBUILD_CFLAGS='"$(strip $(VERBOSE_CFLAGS))"' \
+ -DBUILD_OPTIONS='"$(strip $(BUILD_OPTIONS))"' \
+ -c -o $@ $<
+
+tests/test_queue: tests/test_queue.o $(OPTIONS_OBJS) $(EBTREE_OBJS) $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(filter-out src/haproxy.o,$^) $(LDOPTS)
+
+.PHONY: test
+test: tests/test_queue
+ ./tests/test_queue
diff --git a/tests/test-queue.cfg b/tests/test-queue.cfg
new file mode 100644
index 000000000..903cf22d0
--- /dev/null
+++ b/tests/test-queue.cfg
@@ -0,0 +1,8 @@
+defaults
+ timeout client 5s
+ timeout server 5s
+ timeout connect 5s
+
+listen l1
+ bind :8001
+ server s1 127.0.0.1:8888 maxconn 1
diff --git a/tests/test_queue.c b/tests/test_queue.c
new file mode 100644
index 000000000..a92bd0233
--- /dev/null
+++ b/tests/test_queue.c
@@ -0,0 +1,117 @@
+#include "haproxy_test.c"
+
+#include <proto/queue.h>
+#include <proto/server.h>
+#include <proto/proxy.h>
+#include <proto/session.h>
+#include <proto/stream.h>
+
+#include <stdio.h>
+
+// Usage:
+// make -f Makefile.test USE_THREAD=1 DEBUG=-DDEBUG_THREAD TARGET=XXX test
+
+#ifndef USE_THREAD
+#error USE_THREAD is not set (USE_THREAD=1)
+#endif
+#ifndef DEBUG_THREAD
+#error DEBUG_THREAD is not set (DEBUG=-DDEBUG_THREAD)
+#endif
+
+struct test_spec_pendconn {
+ int key;
+ int locked;
+};
+
+struct test_spec {
+ struct test_spec_pendconn pendconns[3];
+ int expected;
+};
+
+int main(void)
+{
+ int argc = 3;
+ char *argv[] = {"haproxy","-f","tests/test-queue.cfg"};
+ init(argc, argv);
+
+ struct proxy *px;
+ struct server *srv;
+ struct stream *strm;
+
+ for (px = proxies_list; px; px = px->next)
+ if (!strcmp(px->id, "l1"))
+ break;
+ srv = px->srv;
+
+ struct test_spec tests[] = {
+ /* 0 1 2 */
+ /* [0123456789ABCDEF],[0123456789ABCDEF],[0123456789ABCDEF] */
+ /* [........|...*...],[........|.......],[........|.......] */ {{{0x0c}},0},
+ /* [...*....|.......],[........|.......],[........|.......] */ {{{0x03}},0},
+ /* [...*....|.......],[...*....|.......],[........|.......] */ {{{0x03},{0x13}},0},
+ /* [...*....|...*...],[........|.......],[........|.......] */ {{{0x03},{0x0c}},1},
+ /* [...*....|X..*...],[........|.......],[........|.......] */ {{{0x03},{0x09,1},{0x0c}},2},
+ /* [...*....|...X...],[........|.......],[........|.......] */ {{{0x03},{0x0c,1}},0},
+ /* [...*....|...X...],[...X....|.......],[........|.......] */ {{{0x03},{0x0c,1},{0x13,1}},0},
+ /* [........|...X...],[...X....|...*...],[........|.......] */ {{{0x0c,1},{0x13,1},{0x1c}},2},
+ /* [........|...X...],[...*....|...X...],[........|.......] */ {{{0x0c,1},{0x13},{0x1c,1}},1},
+ /* [........|...X...],[...*....|.......],[........|.......] */ {{{0x0c,1},{0x13}},1},
+ /* [........|...X...],[...*....|...*...],[........|.......] */ {{{0x0c,1},{0x13},{0x1c}},2},
+ /* [........|.......],[...*....|.......],[........|.......] */ {{{0x13}},0},
+ /* [........|.......],[...*....|...*...],[........|.......] */ {{{0x13},{0x1c}},1},
+ /* [........|.......],[........|...*...],[........|.......] */ {{{0x1c}},0},
+ /* [........|.......],[...*....|.......],[........|.......] */ {{{0x13}},0},
+ /* [........|...X...],[...*....|.......],[..*.....|.......] */ {{{0x0c,1},{0x13},{0x22}},1},
+ /* [........|...X...],[........|.......],[........|.......] */ {{{0x0c,1}},-1},
+ /* [........*...*...],[........|.......],[........|.......] */ {{{0x08},{0x0c}},0},
+ /* [...*....*.......],[........|.......],[........|.......] */ {{{0x03},{0x08}},1},
+ /* [........|.......],[...*....*.......],[........|.......] */ {{{0x13},{0x1c}},1},
+ };
+
+ now_ms = 0x00000;
+ struct eb32_node *node;
+ struct test_spec test;
+ for (int i = 0; i < sizeof(tests)/sizeof(tests[0]); i++ ) {
+ while ((node = eb32_first(&px->pendconns)))
+ eb32_delete(node);
+ srv->served = 0;
+
+ test = tests[i];
+ struct pendconn *pcs[sizeof(test.pendconns)/sizeof(test.pendconns[0])];
+
+ for (int j = 0; j < sizeof(test.pendconns)/sizeof(test.pendconns[0]); j++) {
+ if (!test.pendconns[j].key) {
+ pcs[j] = NULL;
+ break;
+ }
+
+ strm = stream_new(session_new(px, NULL, NULL), NULL);
+ strm->priority_class = (test.pendconns[j].key >> 4) - 0x7ff;
+ strm->priority_offset = (test.pendconns[j].key & 0xf) * 0x10000;
+ if (strm->priority_offset >= 0x80000)
+ strm->priority_offset -= 0x100000;
+
+ pcs[j] = pendconn_add(strm);
+
+ if (test.pendconns[j].locked) {
+ HA_SPIN_LOCK(PENDCONN_LOCK, &pcs[j]->lock);
+ pcs[j]->lock.info.owner <<= 1;
+ }
+ }
+
+ process_srv_queue(srv);
+ int actual = -1;
+ for (int j = 0; j < sizeof(test.pendconns)/sizeof(test.pendconns[0]); j++) {
+ if (pcs[j] == NULL)
+ break;
+ if (pcs[j]->srv == srv) {
+ actual = j;
+ break;
+ }
+ }
+ if (actual != test.expected)
+ printf("%d Failed. Expected=%d Actual=%d\n", i, test.expected, actual);
+ else
+ printf("%d Passed. Result=%d\n", i, actual);
+ }
+}