You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rspamd_upstream_test.c 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Copyright (c) 2014, Vsevolod Stakhov
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
  15. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  18. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "config.h"
  26. #include "main.h"
  27. #include "upstream.h"
  28. #include "ottery.h"
  29. const char *test_upstream_list = "microsoft.com:443:1,google.com:80:2,kernel.org:443:3";
  30. const char *new_upstream_list = "freebsd.org:80";
  31. char test_key[32];
  32. static void
  33. rspamd_upstream_test_method (struct upstream_list *ls,
  34. enum rspamd_upstream_rotation rot, const gchar *expected)
  35. {
  36. struct upstream *up;
  37. if (rot != RSPAMD_UPSTREAM_HASHED) {
  38. up = rspamd_upstream_get (ls, rot);
  39. g_assert (up != NULL);
  40. g_assert (strcmp (rspamd_upstream_name (up), expected) == 0);
  41. }
  42. else {
  43. up = rspamd_upstream_get (ls, RSPAMD_UPSTREAM_HASHED, test_key,
  44. sizeof (test_key));
  45. g_assert (up != NULL);
  46. g_assert (strcmp (rspamd_upstream_name (up), expected) == 0);
  47. }
  48. }
  49. static void
  50. rspamd_upstream_timeout_handler (int fd, short what, void *arg)
  51. {
  52. struct rspamd_dns_resolver *resolver = (struct rspamd_dns_resolver *)arg;
  53. rdns_resolver_release (resolver->r);
  54. }
  55. void
  56. rspamd_upstream_test_func (void)
  57. {
  58. struct upstream_list *ls, *nls;
  59. struct upstream *up, *upn;
  60. struct event_base *ev_base = event_init ();
  61. struct rspamd_dns_resolver *resolver;
  62. struct rspamd_config *cfg;
  63. gint i, success = 0;
  64. const gint assumptions = 100500;
  65. gdouble p;
  66. struct event ev;
  67. struct timeval tv;
  68. rspamd_inet_addr_t *addr, *next_addr, paddr;
  69. cfg = (struct rspamd_config *)g_malloc (sizeof (struct rspamd_config));
  70. bzero (cfg, sizeof (struct rspamd_config));
  71. cfg->cfg_pool = rspamd_mempool_new (rspamd_mempool_suggest_size ());
  72. cfg->dns_retransmits = 2;
  73. cfg->dns_timeout = 0.5;
  74. cfg->upstream_max_errors = 1;
  75. cfg->upstream_revive_time = 0.5;
  76. cfg->upstream_error_time = 2;
  77. resolver = dns_resolver_init (NULL, ev_base, cfg);
  78. rspamd_upstreams_library_init (resolver->r, ev_base);
  79. rspamd_upstreams_library_config (cfg);
  80. ls = rspamd_upstreams_create ();
  81. g_assert (rspamd_upstreams_parse_line (ls, test_upstream_list, 443, NULL));
  82. g_assert (rspamd_upstreams_count (ls) == 3);
  83. /* Test master-slave rotation */
  84. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_MASTER_SLAVE, "kernel.org");
  85. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_MASTER_SLAVE, "kernel.org");
  86. /* Test round-robin rotation */
  87. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org");
  88. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "google.com");
  89. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org");
  90. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "microsoft.com");
  91. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "google.com");
  92. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org");
  93. /* Test stable hashing */
  94. nls = rspamd_upstreams_create ();
  95. g_assert (rspamd_upstreams_parse_line (nls, test_upstream_list, 443, NULL));
  96. g_assert (rspamd_upstreams_parse_line (nls, new_upstream_list, 443, NULL));
  97. for (i = 0; i < assumptions; i ++) {
  98. ottery_rand_bytes (test_key, sizeof (test_key));
  99. up = rspamd_upstream_get (ls, RSPAMD_UPSTREAM_HASHED, test_key,
  100. sizeof (test_key));
  101. upn = rspamd_upstream_get (nls, RSPAMD_UPSTREAM_HASHED, test_key,
  102. sizeof (test_key));
  103. if (strcmp (rspamd_upstream_name (up), rspamd_upstream_name (upn)) == 0) {
  104. success ++;
  105. }
  106. }
  107. p = 1.0 - fabs (3.0 / 4.0 - (gdouble)success / (gdouble)assumptions);
  108. /*
  109. * P value is calculated as following:
  110. * when we add/remove M upstreams from the list, the probability of hash
  111. * miss should be close to the relation N / (N + M), where N is the size of
  112. * the previous upstreams list.
  113. */
  114. msg_debug ("p value for hash consistency: %.6f", p);
  115. g_assert (p > 0.9);
  116. rspamd_upstreams_destroy (nls);
  117. /*
  118. * Test v4/v6 priorities
  119. */
  120. nls = rspamd_upstreams_create ();
  121. g_assert (rspamd_upstreams_add_upstream (nls, "127.0.0.1", 0, NULL));
  122. up = rspamd_upstream_get (nls, RSPAMD_UPSTREAM_RANDOM);
  123. addr = g_malloc (sizeof (*addr));
  124. rspamd_parse_inet_address(&paddr, "127.0.0.2");
  125. g_assert (rspamd_upstream_add_addr (up, &paddr));
  126. rspamd_parse_inet_address(&paddr, "::1");
  127. g_assert (rspamd_upstream_add_addr (up, &paddr));
  128. addr = rspamd_upstream_addr (up);
  129. for (i = 0; i < 256; i ++) {
  130. next_addr = rspamd_upstream_addr (up);
  131. g_assert (addr->af == AF_INET);
  132. g_assert (next_addr->af == AF_INET);
  133. g_assert (addr != next_addr);
  134. addr = next_addr;
  135. }
  136. rspamd_upstreams_destroy (nls);
  137. /* Upstream fail test */
  138. evtimer_set (&ev, rspamd_upstream_timeout_handler, resolver);
  139. event_base_set (ev_base, &ev);
  140. up = rspamd_upstream_get (ls, RSPAMD_UPSTREAM_MASTER_SLAVE);
  141. rspamd_upstream_fail (up);
  142. g_assert (rspamd_upstreams_alive (ls) == 2);
  143. tv.tv_sec = 2;
  144. tv.tv_usec = 0;
  145. event_add (&ev, &tv);
  146. event_base_loop (ev_base, 0);
  147. g_assert (rspamd_upstreams_alive (ls) == 3);
  148. g_free (cfg);
  149. rspamd_upstreams_destroy (ls);
  150. }