summaryrefslogtreecommitdiff
path: root/extras/dispatch/tests
diff options
context:
space:
mode:
Diffstat (limited to 'extras/dispatch/tests')
-rw-r--r--extras/dispatch/tests/CMakeLists.txt34
-rw-r--r--extras/dispatch/tests/alloc_test.c86
-rw-r--r--extras/dispatch/tests/message_test.c119
-rw-r--r--extras/dispatch/tests/run_tests.c36
-rw-r--r--extras/dispatch/tests/server_test.c195
-rw-r--r--extras/dispatch/tests/test_case.h36
-rw-r--r--extras/dispatch/tests/timer_test.c388
-rw-r--r--extras/dispatch/tests/tool_test.c159
8 files changed, 1053 insertions, 0 deletions
diff --git a/extras/dispatch/tests/CMakeLists.txt b/extras/dispatch/tests/CMakeLists.txt
new file mode 100644
index 0000000000..10bf1eb43a
--- /dev/null
+++ b/extras/dispatch/tests/CMakeLists.txt
@@ -0,0 +1,34 @@
+##
+## Licensed to the Apache Software Foundation (ASF) under one
+## or more contributor license agreements. See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership. The ASF licenses this file
+## to you under the Apache License, Version 2.0 (the
+## "License"); you may not use this file except in compliance
+## with the License. You may obtain a copy of the License at
+##
+## http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing,
+## software distributed under the License is distributed on an
+## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+## KIND, either express or implied. See the License for the
+## specific language governing permissions and limitations
+## under the License.
+##
+
+##
+## Build test applications
+##
+set(test_SOURCES
+ alloc_test.c
+ message_test.c
+ run_tests.c
+ server_test.c
+ timer_test.c
+ tool_test.c
+ )
+
+add_executable(run_tests ${test_SOURCES})
+target_link_libraries(run_tests qpid-dispatch)
+
diff --git a/extras/dispatch/tests/alloc_test.c b/extras/dispatch/tests/alloc_test.c
new file mode 100644
index 0000000000..2406048209
--- /dev/null
+++ b/extras/dispatch/tests/alloc_test.c
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "test_case.h"
+#include <stdio.h>
+#include <string.h>
+#include "alloc_private.h"
+
+typedef struct {
+ int A;
+ int B;
+} object_t;
+
+dx_alloc_config_t config = {3, 7, 10};
+
+ALLOC_DECLARE(object_t);
+ALLOC_DEFINE_CONFIG(object_t, sizeof(object_t), 0, &config);
+
+
+static char* check_stats(dx_alloc_stats_t *stats, uint64_t ah, uint64_t fh, uint64_t ht, uint64_t rt, uint64_t rg)
+{
+ if (stats->total_alloc_from_heap != ah) return "Incorrect alloc-from-heap";
+ if (stats->total_free_to_heap != fh) return "Incorrect free-to-heap";
+ if (stats->held_by_threads != ht) return "Incorrect held-by-threads";
+ if (stats->batches_rebalanced_to_threads != rt) return "Incorrect rebalance-to-threads";
+ if (stats->batches_rebalanced_to_global != rg) return "Incorrect rebalance-to-global";
+ return 0;
+}
+
+
+static char* test_alloc_basic(void *context)
+{
+ object_t *obj[50];
+ int idx;
+ dx_alloc_stats_t *stats;
+ char *error;
+
+ for (idx = 0; idx < 20; idx++)
+ obj[idx] = new_object_t();
+
+ stats = alloc_stats_object_t();
+ error = check_stats(stats, 21, 0, 21, 0, 0);
+ if (error) return error;
+
+ for (idx = 0; idx < 20; idx++)
+ free_object_t(obj[idx]);
+
+ error = check_stats(stats, 21, 5, 6, 0, 5);
+ if (error) return error;
+
+ for (idx = 0; idx < 20; idx++)
+ obj[idx] = new_object_t();
+
+ error = check_stats(stats, 27, 5, 21, 3, 5);
+ if (error) return error;
+
+ return 0;
+}
+
+
+int alloc_tests(void)
+{
+ int result = 0;
+ dx_alloc_initialize();
+
+ TEST_CASE(test_alloc_basic, 0);
+
+ return result;
+}
+
diff --git a/extras/dispatch/tests/message_test.c b/extras/dispatch/tests/message_test.c
new file mode 100644
index 0000000000..590b7f6ed7
--- /dev/null
+++ b/extras/dispatch/tests/message_test.c
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "test_case.h"
+#include <stdio.h>
+#include <string.h>
+#include "message_private.h"
+#include <qpid/dispatch/iterator.h>
+#include <proton/message.h>
+
+
+static char* test_send_to_messenger(void *context)
+{
+ dx_message_t *msg = dx_allocate_message();
+ dx_message_content_t *content = MSG_CONTENT(msg);
+
+ dx_message_compose_1(msg, "test_addr_0", 0);
+ dx_buffer_t *buf = DEQ_HEAD(content->buffers);
+ if (buf == 0) return "Expected a buffer in the test message";
+
+ pn_message_t *pn_msg = pn_message();
+ int result = pn_message_decode(pn_msg, (const char*) dx_buffer_base(buf), dx_buffer_size(buf));
+ if (result != 0) return "Error in pn_message_decode";
+
+ if (strcmp(pn_message_get_address(pn_msg), "test_addr_0") != 0)
+ return "Address mismatch in received message";
+
+ pn_message_free(pn_msg);
+ dx_free_message(msg);
+
+ return 0;
+}
+
+
+static char* test_receive_from_messenger(void *context)
+{
+ pn_message_t *pn_msg = pn_message();
+ pn_message_set_address(pn_msg, "test_addr_1");
+
+ dx_buffer_t *buf = dx_allocate_buffer();
+ size_t size = dx_buffer_capacity(buf);
+ int result = pn_message_encode(pn_msg, (char*) dx_buffer_cursor(buf), &size);
+ if (result != 0) return "Error in pn_message_encode";
+ dx_buffer_insert(buf, size);
+
+ dx_message_t *msg = dx_allocate_message();
+ dx_message_content_t *content = MSG_CONTENT(msg);
+
+ DEQ_INSERT_TAIL(content->buffers, buf);
+ int valid = dx_message_check(msg, DX_DEPTH_ALL);
+ if (!valid) return "dx_message_check returns 'invalid'";
+
+ dx_field_iterator_t *iter = dx_message_field_iterator(msg, DX_FIELD_TO);
+ if (iter == 0) return "Expected an iterator for the 'to' field";
+
+ if (!dx_field_iterator_equal(iter, (unsigned char*) "test_addr_1"))
+ return "Mismatched 'to' field contents";
+
+ pn_message_free(pn_msg);
+ dx_free_message(msg);
+
+ return 0;
+}
+
+
+static char* test_insufficient_check_depth(void *context)
+{
+ pn_message_t *pn_msg = pn_message();
+ pn_message_set_address(pn_msg, "test_addr_2");
+
+ dx_buffer_t *buf = dx_allocate_buffer();
+ size_t size = dx_buffer_capacity(buf);
+ int result = pn_message_encode(pn_msg, (char*) dx_buffer_cursor(buf), &size);
+ if (result != 0) return "Error in pn_message_encode";
+ dx_buffer_insert(buf, size);
+
+ dx_message_t *msg = dx_allocate_message();
+ dx_message_content_t *content = MSG_CONTENT(msg);
+
+ DEQ_INSERT_TAIL(content->buffers, buf);
+ int valid = dx_message_check(msg, DX_DEPTH_DELIVERY_ANNOTATIONS);
+ if (!valid) return "dx_message_check returns 'invalid'";
+
+ dx_field_iterator_t *iter = dx_message_field_iterator(msg, DX_FIELD_TO);
+ if (iter) return "Expected no iterator for the 'to' field";
+
+ dx_free_message(msg);
+
+ return 0;
+}
+
+
+int message_tests(void)
+{
+ int result = 0;
+
+ TEST_CASE(test_send_to_messenger, 0);
+ TEST_CASE(test_receive_from_messenger, 0);
+ TEST_CASE(test_insufficient_check_depth, 0);
+
+ return result;
+}
+
diff --git a/extras/dispatch/tests/run_tests.c b/extras/dispatch/tests/run_tests.c
new file mode 100644
index 0000000000..a677c04577
--- /dev/null
+++ b/extras/dispatch/tests/run_tests.c
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+int tool_tests();
+int timer_tests();
+int alloc_tests();
+int server_tests();
+int message_tests();
+
+int main(int argc, char** argv)
+{
+ int result = 0;
+ result += tool_tests();
+ result += timer_tests();
+ result += alloc_tests();
+ result += server_tests();
+ result += message_tests();
+ return result;
+}
+
diff --git a/extras/dispatch/tests/server_test.c b/extras/dispatch/tests/server_test.c
new file mode 100644
index 0000000000..adeab62af9
--- /dev/null
+++ b/extras/dispatch/tests/server_test.c
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <qpid/dispatch/timer.h>
+#include "test_case.h"
+#include <qpid/dispatch/server.h>
+#include <qpid/dispatch/user_fd.h>
+#include <qpid/dispatch/threading.h>
+#include <qpid/dispatch/log.h>
+
+#define THREAD_COUNT 4
+#define OCTET_COUNT 100
+
+static sys_mutex_t *test_lock;
+
+static void *expected_context;
+static int call_count;
+static int threads_seen[THREAD_COUNT];
+static char stored_error[512];
+
+static int write_count;
+static int read_count;
+static int fd[2];
+static dx_user_fd_t *ufd_write;
+static dx_user_fd_t *ufd_read;
+
+
+static void thread_start(void *context, int thread_id)
+{
+ sys_mutex_lock(test_lock);
+ if (context != expected_context && !stored_error[0])
+ sprintf(stored_error, "Unexpected Context Value: %lx", (long) context);
+ if (thread_id >= THREAD_COUNT && !stored_error[0])
+ sprintf(stored_error, "Thread_ID too large: %d", thread_id);
+ if (thread_id < 0 && !stored_error[0])
+ sprintf(stored_error, "Thread_ID negative: %d", thread_id);
+
+ call_count++;
+ if (thread_id >= 0 && thread_id < THREAD_COUNT)
+ threads_seen[thread_id]++;
+
+ if (call_count == THREAD_COUNT)
+ dx_server_stop();
+ sys_mutex_unlock(test_lock);
+}
+
+
+static int conn_handler(void *context, dx_conn_event_t event, dx_connection_t *conn)
+{
+ return 0;
+}
+
+
+static void ufd_handler(void *context, dx_user_fd_t *ufd)
+{
+ long dir = (long) context;
+ char buffer;
+ ssize_t len;
+ static int in_read = 0;
+ static int in_write = 0;
+
+ if (dir == 0) { // READ
+ in_read++;
+ assert(in_read == 1);
+ if (!dx_user_fd_is_readable(ufd_read)) {
+ sprintf(stored_error, "Expected Readable");
+ dx_server_stop();
+ } else {
+ len = read(fd[0], &buffer, 1);
+ if (len == 1) {
+ read_count++;
+ if (read_count == OCTET_COUNT)
+ dx_server_stop();
+ }
+ dx_user_fd_activate_read(ufd_read);
+ }
+ in_read--;
+ } else { // WRITE
+ in_write++;
+ assert(in_write == 1);
+ if (!dx_user_fd_is_writeable(ufd_write)) {
+ sprintf(stored_error, "Expected Writable");
+ dx_server_stop();
+ } else {
+ write(fd[1], "X", 1);
+
+ write_count++;
+ if (write_count < OCTET_COUNT)
+ dx_user_fd_activate_write(ufd_write);
+ }
+ in_write--;
+ }
+}
+
+
+static void fd_test_start(void *context)
+{
+ dx_user_fd_activate_read(ufd_read);
+}
+
+
+static char* test_start_handler(void *context)
+{
+ int i;
+
+ dx_server_initialize(THREAD_COUNT);
+
+ expected_context = (void*) 0x00112233;
+ stored_error[0] = 0x0;
+ call_count = 0;
+ for (i = 0; i < THREAD_COUNT; i++)
+ threads_seen[i] = 0;
+
+ dx_server_set_conn_handler(conn_handler);
+ dx_server_set_start_handler(thread_start, expected_context);
+ dx_server_run();
+ dx_server_finalize();
+
+ if (stored_error[0]) return stored_error;
+ if (call_count != THREAD_COUNT) return "Incorrect number of thread-start callbacks";
+ for (i = 0; i < THREAD_COUNT; i++)
+ if (threads_seen[i] != 1) return "Incorrect count on one thread ID";
+
+ return 0;
+}
+
+
+static char* test_user_fd(void *context)
+{
+ int res;
+ dx_timer_t *timer;
+
+ dx_server_initialize(THREAD_COUNT);
+ dx_server_set_conn_handler(conn_handler);
+ dx_server_set_user_fd_handler(ufd_handler);
+ timer = dx_timer(fd_test_start, 0);
+ dx_timer_schedule(timer, 0);
+
+ stored_error[0] = 0x0;
+ res = pipe2(fd, O_NONBLOCK);
+ if (res != 0) return "Error creating pipe2";
+
+ ufd_write = dx_user_fd(fd[1], (void*) 1);
+ ufd_read = dx_user_fd(fd[0], (void*) 0);
+
+ dx_server_run();
+ dx_timer_free(timer);
+ dx_server_finalize();
+ close(fd[0]);
+ close(fd[1]);
+
+ if (stored_error[0]) return stored_error;
+ if (write_count - OCTET_COUNT > 2) sprintf(stored_error, "Excessively high Write Count: %d", write_count);
+ if (read_count != OCTET_COUNT) sprintf(stored_error, "Incorrect Read Count: %d", read_count);;
+
+ if (stored_error[0]) return stored_error;
+ return 0;
+}
+
+
+int server_tests(void)
+{
+ int result = 0;
+ test_lock = sys_mutex();
+ dx_log_set_mask(LOG_NONE);
+
+ TEST_CASE(test_start_handler, 0);
+ TEST_CASE(test_user_fd, 0);
+
+ sys_mutex_free(test_lock);
+ return result;
+}
+
diff --git a/extras/dispatch/tests/test_case.h b/extras/dispatch/tests/test_case.h
new file mode 100644
index 0000000000..6e36b440a5
--- /dev/null
+++ b/extras/dispatch/tests/test_case.h
@@ -0,0 +1,36 @@
+#ifndef _nexus_test_case_h_
+#define _nexus_test_case_h_ 1
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+typedef char* (*testcase_t)(void *context);
+
+#define TEST_CASE(T,C) do { \
+ char *r = T(C); \
+ printf("Test Case %s.%s: ", __FUNCTION__, #T); \
+ if (r) { \
+ printf("FAIL: %s\n", r); \
+ result++; \
+ } else \
+ printf("PASS\n"); \
+} while(0);
+
+
+#endif
+
diff --git a/extras/dispatch/tests/timer_test.c b/extras/dispatch/tests/timer_test.c
new file mode 100644
index 0000000000..3d199f2aa2
--- /dev/null
+++ b/extras/dispatch/tests/timer_test.c
@@ -0,0 +1,388 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <stdio.h>
+#include <qpid/dispatch/timer.h>
+#include "alloc_private.h"
+#include "timer_private.h"
+#include "test_case.h"
+#include <qpid/dispatch/threading.h>
+
+
+static unsigned long fire_mask;
+static dx_timer_list_t pending_timers;
+static sys_mutex_t *lock;
+static long time;
+static dx_timer_t *timers[16];
+
+
+void dx_server_timer_pending_LH(dx_timer_t *timer)
+{
+ DEQ_INSERT_TAIL(pending_timers, timer);
+}
+
+
+void dx_server_timer_cancel_LH(dx_timer_t *timer)
+{
+ if (timer->state == TIMER_PENDING)
+ DEQ_REMOVE(pending_timers, timer);
+}
+
+
+static int fire_head()
+{
+ sys_mutex_lock(lock);
+ int result = DEQ_SIZE(pending_timers);
+ dx_timer_t *timer = DEQ_HEAD(pending_timers);
+ if (timer) {
+ DEQ_REMOVE_HEAD(pending_timers);
+ dx_timer_idle_LH(timer);
+ fire_mask |= (unsigned long) timer->context;
+ }
+ sys_mutex_unlock(lock);
+ return result;
+}
+
+
+static char* test_quiet(void *context)
+{
+ fire_mask = 0;
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+
+ while(fire_head());
+
+ if (fire_mask != 0)
+ return "Expected zero timers fired";
+ return 0;
+}
+
+static char* test_immediate(void *context)
+{
+ while(fire_head());
+ fire_mask = 0;
+
+ dx_timer_schedule(timers[0], 0);
+
+ if (fire_mask != 0) return "Premature firing";
+ if (fire_head() > 1) return "Too many firings";
+ if (fire_mask != 1) return "Incorrect fire mask";
+
+ return 0;
+}
+
+
+static char* test_immediate_plus_delayed(void *context)
+{
+ while(fire_head());
+ fire_mask = 0;
+
+ dx_timer_schedule(timers[0], 0);
+ dx_timer_schedule(timers[1], 5);
+
+ if (fire_mask != 0) return "Premature firing";
+ if (fire_head() > 1) return "Too many firings";
+ if (fire_mask != 1) return "Incorrect fire mask 1";
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ time += 8;
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+
+ if (fire_head() < 1) return "Delayed Failed to fire";
+ if (fire_mask != 3) return "Incorrect fire mask 3";
+
+ return 0;
+}
+
+
+static char* test_single(void *context)
+{
+ while(fire_head());
+ fire_mask = 0;
+
+ dx_timer_schedule(timers[0], 2);
+ if (fire_head() > 0) return "Premature firing 1";
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ if (fire_head() > 0) return "Premature firing 2";
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ if (fire_head() < 1) return "Failed to fire";
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ if (fire_head() != 0) return "Spurious fires";
+
+ if (fire_mask != 1) return "Incorrect fire mask";
+ if (timers[0]->state != TIMER_IDLE) return "Expected idle timer state";
+
+ return 0;
+}
+
+
+static char* test_two_inorder(void *context)
+{
+ while(fire_head());
+ fire_mask = 0;
+
+ dx_timer_schedule(timers[0], 2);
+ dx_timer_schedule(timers[1], 4);
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ int count = fire_head();
+ if (count < 1) return "First failed to fire";
+ if (count > 1) return "Second fired prematurely";
+ if (fire_mask != 1) return "Incorrect fire mask 1";
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ if (fire_head() < 1) return "Second failed to fire";
+ if (fire_mask != 3) return "Incorrect fire mask 3";
+
+ return 0;
+}
+
+
+static char* test_two_reverse(void *context)
+{
+ while(fire_head());
+ fire_mask = 0;
+
+ dx_timer_schedule(timers[0], 4);
+ dx_timer_schedule(timers[1], 2);
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ int count = fire_head();
+ if (count < 1) return "First failed to fire";
+ if (count > 1) return "Second fired prematurely";
+ if (fire_mask != 2) return "Incorrect fire mask 2";
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ if (fire_head() < 1) return "Second failed to fire";
+ if (fire_mask != 3) return "Incorrect fire mask 3";
+
+ return 0;
+}
+
+
+static char* test_two_duplicate(void *context)
+{
+ while(fire_head());
+ fire_mask = 0;
+
+ dx_timer_schedule(timers[0], 2);
+ dx_timer_schedule(timers[1], 2);
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ int count = fire_head();
+ if (count != 2) return "Expected two firings";
+ fire_head();
+ if (fire_mask != 3) return "Incorrect fire mask 3";
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ if (fire_head() > 0) return "Spurious timer fires";
+
+ return 0;
+}
+
+
+static char* test_separated(void *context)
+{
+ int count;
+
+ while(fire_head());
+ fire_mask = 0;
+
+ dx_timer_schedule(timers[0], 2);
+ dx_timer_schedule(timers[1], 4);
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ count = fire_head();
+ if (count < 1) return "First failed to fire";
+ if (count > 1) return "Second fired prematurely";
+ if (fire_mask != 1) return "Incorrect fire mask 1";
+
+ dx_timer_schedule(timers[2], 2);
+ dx_timer_schedule(timers[3], 4);
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ count = fire_head();
+ fire_head();
+ if (count < 1) return "Second failed to fire";
+ if (count < 2) return "Third failed to fire";
+ if (fire_mask != 7) return "Incorrect fire mask 7";
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ count = fire_head();
+ if (count < 1) return "Fourth failed to fire";
+ if (fire_mask != 15) return "Incorrect fire mask 15";
+
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ count = fire_head();
+ if (count > 0) return "Spurious fire";
+
+ return 0;
+}
+
+
+static char* test_big(void *context)
+{
+ while(fire_head());
+ fire_mask = 0;
+
+ long durations[16] =
+ { 5, 8, 7, 6,
+ 14, 10, 16, 15,
+ 11, 12, 9, 12,
+ 1, 2, 3, 4};
+ unsigned long masks[18] = {
+ 0x1000,
+ 0x3000,
+ 0x7000,
+ 0xf000,
+ 0xf001,
+ 0xf009,
+ 0xf00d,
+ 0xf00f,
+ 0xf40f,
+ 0xf42f,
+ 0xf52f,
+ 0xff2f,
+ 0xff2f,
+ 0xff3f,
+ 0xffbf,
+ 0xffff,
+ 0xffff,
+ 0xffff
+ };
+
+ int i;
+ for (i = 0; i < 16; i++)
+ dx_timer_schedule(timers[i], durations[i]);
+ for (i = 0; i < 18; i++) {
+ sys_mutex_lock(lock);
+ dx_timer_visit_LH(time++);
+ sys_mutex_unlock(lock);
+ while(fire_head());
+ if (fire_mask != masks[i]) {
+ static char error[100];
+ sprintf(error, "Iteration %d: expected mask %04lx, got %04lx", i, masks[i], fire_mask);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+
+int timer_tests(void)
+{
+ int result = 0;
+ dx_alloc_initialize();
+
+ fire_mask = 0;
+ DEQ_INIT(pending_timers);
+ lock = sys_mutex();
+ dx_timer_initialize(lock);
+ time = 1;
+
+ timers[0] = dx_timer(0, (void*) 0x00000001);
+ timers[1] = dx_timer(0, (void*) 0x00000002);
+ timers[2] = dx_timer(0, (void*) 0x00000004);
+ timers[3] = dx_timer(0, (void*) 0x00000008);
+ timers[4] = dx_timer(0, (void*) 0x00000010);
+ timers[5] = dx_timer(0, (void*) 0x00000020);
+ timers[6] = dx_timer(0, (void*) 0x00000040);
+ timers[7] = dx_timer(0, (void*) 0x00000080);
+ timers[8] = dx_timer(0, (void*) 0x00000100);
+ timers[9] = dx_timer(0, (void*) 0x00000200);
+ timers[10] = dx_timer(0, (void*) 0x00000400);
+ timers[11] = dx_timer(0, (void*) 0x00000800);
+ timers[12] = dx_timer(0, (void*) 0x00001000);
+ timers[13] = dx_timer(0, (void*) 0x00002000);
+ timers[14] = dx_timer(0, (void*) 0x00004000);
+ timers[15] = dx_timer(0, (void*) 0x00008000);
+
+ TEST_CASE(test_quiet, 0);
+ TEST_CASE(test_immediate, 0);
+ TEST_CASE(test_immediate_plus_delayed, 0);
+ TEST_CASE(test_single, 0);
+ TEST_CASE(test_two_inorder, 0);
+ TEST_CASE(test_two_reverse, 0);
+ TEST_CASE(test_two_duplicate, 0);
+ TEST_CASE(test_separated, 0);
+ TEST_CASE(test_big, 0);
+
+ int i;
+ for (i = 0; i < 16; i++)
+ dx_timer_free(timers[i]);
+
+ dx_timer_finalize();
+
+ return result;
+}
+
diff --git a/extras/dispatch/tests/tool_test.c b/extras/dispatch/tests/tool_test.c
new file mode 100644
index 0000000000..7923ee3381
--- /dev/null
+++ b/extras/dispatch/tests/tool_test.c
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "test_case.h"
+#include <stdio.h>
+#include <string.h>
+#include <qpid/dispatch/ctools.h>
+
+typedef struct item_t {
+ DEQ_LINKS(struct item_t);
+ char letter;
+} item_t;
+
+DEQ_DECLARE(item_t, item_list_t);
+
+
+static char* list_well_formed(item_list_t list, char *key)
+{
+ item_t *ptr;
+ item_t *last = 0;
+ int size = DEQ_SIZE(list);
+ int count = 0;
+ char str[32];
+
+ ptr = DEQ_HEAD(list);
+ while (ptr) {
+ str[count] = ptr->letter;
+ count++;
+ if (DEQ_PREV(ptr) != last) return "Corrupt previous link";
+ last = ptr;
+ ptr = DEQ_NEXT(ptr);
+ }
+ str[count] = '\0';
+ if (strcmp(str, key) != 0) return "Invalid key";
+
+ if (count != size) return "Size different from number of items (forward)";
+
+ count = 0;
+ last = 0;
+ ptr = DEQ_TAIL(list);
+ while (ptr) {
+ count++;
+ if (DEQ_NEXT(ptr) != last) return "Corrupt next link";
+ last = ptr;
+ ptr = DEQ_PREV(ptr);
+ }
+
+ if (count != size) return "Size different from number of items (backward)";
+
+ return 0;
+}
+
+
+static char* test_deq_basic(void *context)
+{
+ item_list_t list;
+ item_t item[10];
+ item_t *ptr;
+ int idx;
+ char *subtest;
+
+ DEQ_INIT(list);
+ if (DEQ_SIZE(list) != 0) return "Expected zero initial size";
+
+ for (idx = 0; idx < 10; idx++) {
+ DEQ_ITEM_INIT(&item[idx]);
+ item[idx].letter = 'A' + idx;
+ DEQ_INSERT_TAIL(list, &item[idx]);
+ }
+ if (DEQ_SIZE(list) != 10) return "Expected 10 items in list";
+
+ ptr = DEQ_HEAD(list);
+ if (!ptr) return "Expected valid head item";
+ if (DEQ_PREV(ptr)) return "Head item has non-null previous link";
+ if (ptr->letter != 'A') return "Expected item A at the head";
+ if (DEQ_NEXT(ptr) == 0) return "Head item has null next link";
+ subtest = list_well_formed(list, "ABCDEFGHIJ");
+ if (subtest) return subtest;
+
+ DEQ_REMOVE_HEAD(list);
+ if (DEQ_SIZE(list) != 9) return "Expected 9 items in list";
+ ptr = DEQ_HEAD(list);
+ if (ptr->letter != 'B') return "Expected item B at the head";
+ subtest = list_well_formed(list, "BCDEFGHIJ");
+ if (subtest) return subtest;
+
+ DEQ_REMOVE_TAIL(list);
+ if (DEQ_SIZE(list) != 8) return "Expected 8 items in list";
+ ptr = DEQ_TAIL(list);
+ if (ptr->letter != 'I') return "Expected item I at the tail";
+ subtest = list_well_formed(list, "BCDEFGHI");
+ if (subtest) return subtest;
+
+ DEQ_REMOVE(list, &item[4]);
+ if (DEQ_SIZE(list) != 7) return "Expected 7 items in list";
+ subtest = list_well_formed(list, "BCDFGHI");
+ if (subtest) return subtest;
+
+ DEQ_REMOVE(list, &item[1]);
+ if (DEQ_SIZE(list) != 6) return "Expected 6 items in list";
+ subtest = list_well_formed(list, "CDFGHI");
+ if (subtest) return subtest;
+
+ DEQ_REMOVE(list, &item[8]);
+ if (DEQ_SIZE(list) != 5) return "Expected 5 items in list";
+ subtest = list_well_formed(list, "CDFGH");
+ if (subtest) return subtest;
+
+ DEQ_INSERT_HEAD(list, &item[8]);
+ if (DEQ_SIZE(list) != 6) return "Expected 6 items in list";
+ ptr = DEQ_HEAD(list);
+ if (ptr->letter != 'I') return "Expected item I at the head";
+ subtest = list_well_formed(list, "ICDFGH");
+ if (subtest) return subtest;
+
+ DEQ_INSERT_AFTER(list, &item[4], &item[7]);
+ if (DEQ_SIZE(list) != 7) return "Expected 7 items in list";
+ ptr = DEQ_TAIL(list);
+ if (ptr->letter != 'E') return "Expected item E at the head";
+ subtest = list_well_formed(list, "ICDFGHE");
+ if (subtest) return subtest;
+
+ DEQ_INSERT_AFTER(list, &item[1], &item[5]);
+ if (DEQ_SIZE(list) != 8) return "Expected 8 items in list";
+ subtest = list_well_formed(list, "ICDFBGHE");
+ if (subtest) return subtest;
+
+ if (item[0].prev || item[0].next) return "Unlisted item A has non-null pointers";
+ if (item[9].prev || item[9].next) return "Unlisted item J has non-null pointers";
+
+ return 0;
+}
+
+
+int tool_tests(void)
+{
+ int result = 0;
+
+ TEST_CASE(test_deq_basic, 0);
+
+ return result;
+}
+