summaryrefslogtreecommitdiffstats
path: root/src/stats/test-client-reader.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stats/test-client-reader.c')
-rw-r--r--src/stats/test-client-reader.c235
1 files changed, 235 insertions, 0 deletions
diff --git a/src/stats/test-client-reader.c b/src/stats/test-client-reader.c
new file mode 100644
index 0000000..e9eed0c
--- /dev/null
+++ b/src/stats/test-client-reader.c
@@ -0,0 +1,235 @@
+/* Copyright (c) 2019 Dovecot authors, see the included COPYING file */
+
+#include "test-stats-common.h"
+#include "master-service-private.h"
+#include "client-reader.h"
+#include "connection.h"
+#include "ostream.h"
+
+static struct connection_list *conn_list;
+
+struct test_connection {
+ struct connection conn;
+
+ unsigned int row_count;
+};
+
+static void test_reader_server_destroy(struct connection *conn)
+{
+ io_loop_stop(conn->ioloop);
+}
+
+static struct connection_settings client_set = {
+ .service_name_in = "stats-reader-server",
+ .service_name_out = "stats-reader-client",
+ .major_version = 2,
+ .minor_version = 0,
+ .allow_empty_args_input = TRUE,
+ .input_max_size = SIZE_MAX,
+ .output_max_size = SIZE_MAX,
+ .client = TRUE,
+};
+
+bool test_stats_callback(struct event *event,
+ enum event_callback_type type ATTR_UNUSED,
+ struct failure_context *ctx, const char *fmt ATTR_UNUSED,
+ va_list args ATTR_UNUSED)
+{
+ if (stats_metrics != NULL) {
+ stats_metrics_event(stats_metrics, event, ctx);
+ struct event_filter *filter =
+ stats_metrics_get_event_filter(stats_metrics);
+ return !event_filter_match(filter, event, ctx);
+ }
+ return TRUE;
+}
+
+static const char *settings_blob_1 =
+"metric=test\n"
+"metric/test/metric_name=test\n"
+"metric/test/filter=event=test\n"
+"\n";
+
+static int test_reader_server_input_args(struct connection *conn ATTR_UNUSED,
+ const char *const *args)
+{
+ if (args[0] == NULL)
+ return -1;
+
+ test_assert_strcmp(args[0], "test");
+ test_assert_strcmp(args[1], "1");
+
+ return 1;
+}
+
+static void test_dump_metrics(void)
+{
+ int fds[2];
+
+ test_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+
+ struct connection *conn = i_new(struct connection, 1);
+
+ struct ioloop *loop = io_loop_create();
+
+ client_reader_create(fds[1]);
+ connection_init_client_fd(conn_list, conn, "stats", fds[0], fds[0]);
+ o_stream_nsend_str(conn->output, "DUMP\tcount\n");
+
+ io_loop_run(loop);
+ connection_deinit(conn);
+ i_free(conn);
+
+ /* allow client-reader to finish up */
+ io_loop_set_running(loop);
+ io_loop_handler_run(loop);
+
+ io_loop_destroy(&loop);
+}
+
+static void test_client_reader(void)
+{
+ const struct connection_vfuncs client_vfuncs = {
+ .input_args = test_reader_server_input_args,
+ .destroy = test_reader_server_destroy,
+ };
+
+ test_begin("client reader");
+
+ /* register some stats */
+ test_init(settings_blob_1);
+
+ client_readers_init();
+ conn_list = connection_list_init(&client_set, &client_vfuncs);
+
+ /* push event in */
+ struct event *event = event_create(NULL);
+ event_add_category(event, &test_category);
+ event_set_name(event, "test");
+ test_event_send(event);
+ event_unref(&event);
+
+ test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == 1);
+ test_assert(get_stats_dist_field("test", STATS_DIST_SUM) > 0);
+
+ /* check output from reader */
+ test_dump_metrics();
+
+ test_deinit();
+
+ client_readers_deinit();
+ connection_list_deinit(&conn_list);
+
+ test_end();
+}
+
+static const char *settings_blob_2 =
+"metric=test\n"
+"metric/test/metric_name=test\n"
+"metric/test/filter=event=test\n"
+"metric/test/group_by=test_name\n"
+"\n";
+
+static int
+test_reader_server_input_args_group_by(struct connection *conn,
+ const char *const *args)
+{
+ struct test_connection *tconn =
+ container_of(conn, struct test_connection, conn);
+
+ if (args[0] == NULL)
+ return -1;
+
+ tconn->row_count++;
+
+ if (tconn->row_count == 1) {
+ test_assert_strcmp(args[0], "test");
+ test_assert_strcmp(args[1], "1");
+ } else if (tconn->row_count == 2) {
+ test_assert_strcmp(args[0], "test_alpha");
+ test_assert_strcmp(args[1], "1");
+ }
+ return 1;
+}
+
+static void test_dump_metrics_group_by(void)
+{
+ int fds[2];
+
+ test_assert(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == 0);
+
+ struct test_connection *conn = i_new(struct test_connection, 1);
+
+ struct ioloop *loop = io_loop_create();
+
+ client_reader_create(fds[1]);
+ connection_init_client_fd(conn_list, &conn->conn, "stats", fds[0], fds[0]);
+ o_stream_nsend_str(conn->conn.output, "DUMP\tcount\n");
+
+ io_loop_run(loop);
+ connection_deinit(&conn->conn);
+ i_free(conn);
+
+ io_loop_set_running(loop);
+ io_loop_handler_run(loop);
+
+ io_loop_destroy(&loop);
+}
+
+static void test_client_reader_group_by(void)
+{
+ const struct connection_vfuncs client_vfuncs = {
+ .input_args = test_reader_server_input_args_group_by,
+ .destroy = test_reader_server_destroy,
+ };
+
+ test_begin("client reader (group by)");
+
+ /* register some stats */
+ test_init(settings_blob_2);
+
+ client_readers_init();
+ conn_list = connection_list_init(&client_set, &client_vfuncs);
+
+ /* push event in */
+ struct event *event = event_create(NULL);
+ event_add_category(event, &test_category);
+ event_set_name(event, "test");
+ event_add_str(event, "event_name", "alpha");
+ test_event_send(event);
+ event_unref(&event);
+
+ test_assert(get_stats_dist_field("test", STATS_DIST_COUNT) == 1);
+ test_assert(get_stats_dist_field("test", STATS_DIST_SUM) > 0);
+
+ /* check output from reader */
+ test_dump_metrics_group_by();
+
+ test_deinit();
+
+ client_readers_deinit();
+ connection_list_deinit(&conn_list);
+
+ test_end();
+}
+
+int main(void) {
+ /* fake master service to pretend destroying
+ connections. */
+ struct master_service local_master_service = {
+ .stopping = TRUE,
+ .total_available_count = 100,
+ .service_count_left = 100,
+ };
+ void (*const test_functions[])(void) = {
+ test_client_reader,
+ test_client_reader_group_by,
+ NULL
+ };
+
+ master_service = &local_master_service;
+
+ int ret = test_run(test_functions);
+
+ return ret;
+}