aboutsummaryrefslogtreecommitdiff
path: root/src/test/test_circuitlist.c
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2013-07-10 15:07:32 -0400
committerNick Mathewson <nickm@torproject.org>2013-07-10 15:26:34 -0400
commitec6c155f827000e337796f1f1c54299fbc5cf72a (patch)
treee165ed24d0bc530ab25710214e0a63e2f052ed1e /src/test/test_circuitlist.c
parentb6e8c74667cf723c5ef4d081fc901752e05f9a9b (diff)
downloadtor-ec6c155f827000e337796f1f1c54299fbc5cf72a.tar
tor-ec6c155f827000e337796f1f1c54299fbc5cf72a.tar.gz
Add some basic unit tests for the circuit map data structure.
These show off the new mocking code by mocking the circuitmux code so that we can test the circuit map code in isolation.
Diffstat (limited to 'src/test/test_circuitlist.c')
-rw-r--r--src/test/test_circuitlist.c168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/test/test_circuitlist.c b/src/test/test_circuitlist.c
new file mode 100644
index 000000000..718f0cda5
--- /dev/null
+++ b/src/test/test_circuitlist.c
@@ -0,0 +1,168 @@
+/* Copyright (c) 2013, The Tor Project, Inc. */
+/* See LICENSE for licensing information */
+
+#define TOR_CHANNEL_INTERNAL_
+#define CIRCUITLIST_PRIVATE
+#include "or.h"
+#include "channel.h"
+#include "circuitlist.h"
+#include "test.h"
+
+static channel_t *
+new_fake_channel(void)
+{
+ channel_t *chan = tor_malloc_zero(sizeof(channel_t));
+ channel_init(chan);
+ return chan;
+}
+
+static struct {
+ int ncalls;
+ void *cmux;
+ void *circ;
+ cell_direction_t dir;
+} cam;
+
+static void
+circuitmux_attach_mock(circuitmux_t *cmux, circuit_t *circ,
+ cell_direction_t dir)
+{
+ ++cam.ncalls;
+ cam.cmux = cmux;
+ cam.circ = circ;
+ cam.dir = dir;
+}
+
+static struct {
+ int ncalls;
+ void *cmux;
+ void *circ;
+} cdm;
+
+static void
+circuitmux_detach_mock(circuitmux_t *cmux, circuit_t *circ)
+{
+ ++cdm.ncalls;
+ cdm.cmux = cmux;
+ cdm.circ = circ;
+}
+
+#define GOT_CMUX_ATTACH(mux_, circ_, dir_) do { \
+ tt_int_op(cam.ncalls, ==, 1); \
+ tt_ptr_op(cam.cmux, ==, (mux_)); \
+ tt_ptr_op(cam.circ, ==, (circ_)); \
+ tt_ptr_op(cam.dir, ==, (dir_)); \
+ memset(&cam, 0, sizeof(cam)); \
+ } while (0)
+
+#define GOT_CMUX_DETACH(mux_, circ_) do { \
+ tt_int_op(cdm.ncalls, ==, 1); \
+ tt_ptr_op(cdm.cmux, ==, (mux_)); \
+ tt_ptr_op(cdm.circ, ==, (circ_)); \
+ memset(&cdm, 0, sizeof(cdm)); \
+ } while (0)
+
+
+static void
+test_clist_maps(void *arg)
+{
+ channel_t *ch1 = new_fake_channel();
+ channel_t *ch2 = new_fake_channel();
+ channel_t *ch3 = new_fake_channel();
+ or_circuit_t *or_c1=NULL, *or_c2=NULL;
+
+ MOCK(circuitmux_attach_circuit, circuitmux_attach_mock);
+ MOCK(circuitmux_detach_circuit, circuitmux_detach_mock);
+ memset(&cam, 0, sizeof(cam));
+ memset(&cdm, 0, sizeof(cdm));
+
+ ch1->cmux = (void*)0x1001;
+ ch2->cmux = (void*)0x1002;
+ ch3->cmux = (void*)0x1003;
+
+ or_c1 = or_circuit_new(100, ch2);
+ tt_assert(or_c1);
+ GOT_CMUX_ATTACH(ch2->cmux, or_c1, CELL_DIRECTION_IN);
+ tt_int_op(or_c1->p_circ_id, ==, 100);
+ tt_ptr_op(or_c1->p_chan, ==, ch2);
+
+ or_c2 = or_circuit_new(100, ch1);
+ tt_assert(or_c2);
+ GOT_CMUX_ATTACH(ch1->cmux, or_c2, CELL_DIRECTION_IN);
+ tt_int_op(or_c2->p_circ_id, ==, 100);
+ tt_ptr_op(or_c2->p_chan, ==, ch1);
+
+ circuit_set_n_circid_chan(TO_CIRCUIT(or_c1), 200, ch1);
+ GOT_CMUX_ATTACH(ch1->cmux, or_c1, CELL_DIRECTION_OUT);
+
+ circuit_set_n_circid_chan(TO_CIRCUIT(or_c2), 200, ch2);
+ GOT_CMUX_ATTACH(ch2->cmux, or_c2, CELL_DIRECTION_OUT);
+
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch1), ==, TO_CIRCUIT(or_c1));
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
+ /* Try the same thing again, to test the "fast" path. */
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, TO_CIRCUIT(or_c1));
+ tt_assert(circuit_id_in_use_on_channel(100, ch2));
+ tt_assert(! circuit_id_in_use_on_channel(101, ch2));
+
+ /* Try changing the circuitid and channel of that circuit. */
+ circuit_set_p_circid_chan(or_c1, 500, ch3);
+ GOT_CMUX_DETACH(ch2->cmux, TO_CIRCUIT(or_c1));
+ GOT_CMUX_ATTACH(ch3->cmux, TO_CIRCUIT(or_c1), CELL_DIRECTION_IN);
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch2), ==, NULL);
+ tt_assert(! circuit_id_in_use_on_channel(100, ch2));
+ tt_ptr_op(circuit_get_by_circid_channel(500, ch3), ==, TO_CIRCUIT(or_c1));
+
+ /* Now let's see about destroy handling. */
+ tt_assert(! circuit_id_in_use_on_channel(205, ch2));
+ tt_assert(circuit_id_in_use_on_channel(200, ch2));
+ channel_note_destroy_pending(ch2, 200);
+ channel_note_destroy_pending(ch2, 205);
+ channel_note_destroy_pending(ch1, 100);
+ tt_assert(circuit_id_in_use_on_channel(205, ch2))
+ tt_assert(circuit_id_in_use_on_channel(200, ch2));
+ tt_assert(circuit_id_in_use_on_channel(100, ch1));
+
+ tt_assert(TO_CIRCUIT(or_c2)->n_delete_pending != 0);
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, TO_CIRCUIT(or_c2));
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, TO_CIRCUIT(or_c2));
+
+ /* Okay, now free ch2 and make sure that the circuit ID is STILL not
+ * usable, because we haven't declared the destroy to be nonpending */
+ tt_int_op(cdm.ncalls, ==, 0);
+ circuit_free(TO_CIRCUIT(or_c2));
+ or_c2 = NULL; /* prevent free */
+ tt_int_op(cdm.ncalls, ==, 2);
+ memset(&cdm, 0, sizeof(cdm));
+ tt_assert(circuit_id_in_use_on_channel(200, ch2));
+ tt_assert(circuit_id_in_use_on_channel(100, ch1));
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
+
+ /* Now say that the destroy is nonpending */
+ channel_note_destroy_not_pending(ch2, 200);
+ tt_ptr_op(circuit_get_by_circid_channel(200, ch2), ==, NULL);
+ channel_note_destroy_not_pending(ch1, 100);
+ tt_ptr_op(circuit_get_by_circid_channel(100, ch1), ==, NULL);
+ tt_assert(! circuit_id_in_use_on_channel(200, ch2));
+ tt_assert(! circuit_id_in_use_on_channel(100, ch1));
+
+
+done:
+ tor_free(ch1);
+ tor_free(ch2);
+ tor_free(ch3);
+ if (or_c1)
+ circuit_free(TO_CIRCUIT(or_c1));
+ if (or_c2)
+ circuit_free(TO_CIRCUIT(or_c2));
+ UNMOCK(circuitmux_attach_circuit);
+ UNMOCK(circuitmux_detach_circuit);
+}
+
+
+struct testcase_t circuitlist_tests[] = {
+ { "maps", test_clist_maps, TT_FORK, NULL, NULL },
+ END_OF_TESTCASES
+};