#include "includes.h"
#include "lib/events/events.h"
#include "system/filesys.h"
+#include "system/network.h"
#include "torture/torture.h"
static int fde_count;
return true;
}
+struct test_fde_flags_state {
+ struct torture_context *tctx;
+ const char *backend;
+ struct tevent_context *ev;
+ int fd[2];
+ struct tevent_fd *fde;
+ struct tevent_timer *te;
+ bool finished;
+ int count;
+ uint16_t expected_flags;
+ int step;
+};
+
+static void test_fde_flags_te_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data);
+
+static void test_fde_flags_next_state(struct test_fde_flags_state *state)
+{
+ uint8_t byte = 'B';
+ ssize_t n;
+
+ switch (state->step) {
+ /*
+ * first start with all combinations in idle
+ * mode (there is nothing to read, but we are
+ * able to write).
+ */
+ case 0:
+ TEVENT_FD_NOT_WRITEABLE(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+ case 1:
+ TEVENT_FD_WANTERROR(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+ case 2:
+ TEVENT_FD_READABLE(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+ case 3:
+ TEVENT_FD_NOT_WANTERROR(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+ case 4:
+ TEVENT_FD_NOT_READABLE(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+ case 5:
+ TEVENT_FD_WRITEABLE(state->fde);
+ state->expected_flags = TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 6:
+ TEVENT_FD_READABLE(state->fde);
+ state->expected_flags = TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 7:
+ TEVENT_FD_WANTERROR(state->fde);
+ state->expected_flags = TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 8:
+ TEVENT_FD_NOT_READABLE(state->fde);
+ state->expected_flags = TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 9:
+ TEVENT_FD_NOT_WANTERROR(state->fde);
+ state->expected_flags = TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 10:
+ TEVENT_FD_NOT_WRITEABLE(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+
+ /*
+ * now test all combination, while there is
+ * something to read.
+ */
+ case 11:
+ n = write(state->fd[0], &byte, 1);
+//TODO
+ TEVENT_FD_WANTERROR(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+ case 12:
+ TEVENT_FD_WRITEABLE(state->fde);
+ state->expected_flags = TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 13:
+ TEVENT_FD_READABLE(state->fde);
+ state->expected_flags = TEVENT_FD_READ | TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 14:
+ TEVENT_FD_NOT_WANTERROR(state->fde);
+ state->expected_flags = TEVENT_FD_READ | TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 15:
+ TEVENT_FD_NOT_WRITEABLE(state->fde);
+ state->expected_flags = TEVENT_FD_READ;
+ state->count = 0;
+ break;
+ case 16:
+ TEVENT_FD_NOT_READABLE(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+
+ /*
+ * now test all combination, while there is
+ * something to read and the socket was closed.
+ */
+ case 17:
+ close(state->fd[0]);
+ state->fd[0] = -1;
+ TEVENT_FD_WANTERROR(state->fde);
+ state->expected_flags = TEVENT_FD_ERROR;
+ state->count = 0;
+ break;
+ case 18:
+ TEVENT_FD_WRITEABLE(state->fde);
+ state->expected_flags = TEVENT_FD_WRITE | TEVENT_FD_ERROR;
+ state->count = 0;
+ break;
+ case 19:
+ TEVENT_FD_READABLE(state->fde);
+ state->expected_flags = TEVENT_FD_READ | TEVENT_FD_WRITE | TEVENT_FD_ERROR;
+ state->count = 0;
+ break;
+ case 20:
+ TEVENT_FD_NOT_WANTERROR(state->fde);
+ state->expected_flags = TEVENT_FD_READ | TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 21:
+ TEVENT_FD_NOT_WRITEABLE(state->fde);
+ state->expected_flags = TEVENT_FD_READ;
+ state->count = 0;
+ break;
+ case 22:
+ TEVENT_FD_NOT_READABLE(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+
+ /*
+ * now test all combination, while there the
+ * socket is closed.
+ */
+ case 23:
+ n = read(state->fd[0], &byte, 1);
+//TODOtorture_assert_int_equal_goto
+
+ TEVENT_FD_WANTERROR(state->fde);
+ state->expected_flags = TEVENT_FD_ERROR;
+ state->count = 0;
+ break;
+ case 24:
+ TEVENT_FD_WRITEABLE(state->fde);
+ state->expected_flags = TEVENT_FD_WRITE | TEVENT_FD_ERROR;
+ state->count = 0;
+ break;
+ case 25:
+ TEVENT_FD_READABLE(state->fde);
+ state->expected_flags = TEVENT_FD_READ | TEVENT_FD_WRITE | TEVENT_FD_ERROR;
+ state->count = 0;
+ break;
+ case 26:
+ TEVENT_FD_NOT_WANTERROR(state->fde);
+ state->expected_flags = TEVENT_FD_READ | TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 27:
+ TEVENT_FD_NOT_WRITEABLE(state->fde);
+ state->expected_flags = TEVENT_FD_READ;
+ state->count = 0;
+ break;
+ case 28:
+ TEVENT_FD_NOT_READABLE(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+
+ /*
+ * now test all combination, while we have
+ * read the EOF from the socket.
+ */
+ case 29:
+ n = read(state->fd[0], &byte, 1);
+//TODOtorture_assert_int_equal_goto
+
+ TEVENT_FD_WANTERROR(state->fde);
+ state->expected_flags = TEVENT_FD_ERROR;
+ state->count = 0;
+ break;
+ case 30:
+ TEVENT_FD_WRITEABLE(state->fde);
+ state->expected_flags = TEVENT_FD_WRITE | TEVENT_FD_ERROR;
+ state->count = 0;
+ break;
+ case 31:
+ TEVENT_FD_READABLE(state->fde);
+ state->expected_flags = TEVENT_FD_READ | TEVENT_FD_WRITE | TEVENT_FD_ERROR;
+ state->count = 0;
+ break;
+ case 32:
+ TEVENT_FD_NOT_WANTERROR(state->fde);
+ state->expected_flags = TEVENT_FD_READ | TEVENT_FD_WRITE;
+ state->count = 0;
+ break;
+ case 33:
+ TEVENT_FD_NOT_WRITEABLE(state->fde);
+ state->expected_flags = TEVENT_FD_READ;
+ state->count = 0;
+ break;
+ case 34:
+ TEVENT_FD_NOT_READABLE(state->fde);
+ state->expected_flags = 0;
+ state->count = 0;
+ break;
+ default:
+ state->finished = true;
+ break;
+ }
+
+ /*
+ * just set up a timer as we do not expect
+ * fd activity.
+ */
+ if (state->expected_flags == 0) {
+ state->te = tevent_add_timer(state->ev, state->ev,
+ timeval_current_ofs(0, 500),
+ test_fde_flags_te_handler,
+ state);
+ }
+
+ state->step++;
+}
+
+static void test_fde_flags_fd1_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ struct test_fde_flags_state *state =
+ (struct test_fde_flags_state *)private_data;
+ bool ret;
+
+ torture_assert_int_equal_goto(state->tctx,
+ flags, state->expected_flags,
+ ret, fail, talloc_asprintf(state->tctx,
+ "incorrect flags on fd[1] step[%d]",
+ state->step));
+
+#define TEST_FDE_FLAGS_REPEAT_COUNT 5
+ state->count++;
+ if (state->count < TEST_FDE_FLAGS_REPEAT_COUNT) {
+ return;
+ }
+
+ test_fde_flags_next_state(state);
+ return;
+fail:
+ state->finished = true;
+}
+
+static void test_fde_flags_te_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_fde_flags_state *state =
+ (struct test_fde_flags_state *)private_data;
+ bool ret;
+
+ SMB_ASSERT(state->te == te);
+ TALLOC_FREE(state->te);
+
+ torture_assert_int_equal_goto(state->tctx,
+ 0, state->expected_flags,
+ ret, fail, talloc_asprintf(state->tctx,
+ "incorrect flags te event step[%d]",
+ state->step));
+
+ test_fde_flags_next_state(state);
+ return;
+fail:
+ state->finished = true;
+}
+
+static void test_fde_flags_te_failed(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tval,
+ void *private_data)
+{
+ struct test_fde_flags_state *state =
+ (struct test_fde_flags_state *)private_data;
+ bool ret;
+
+ torture_assert_int_equal_goto(state->tctx,
+ 0, 1,
+ ret, fail, talloc_asprintf(state->tctx,
+ "timeout after step[%d]",
+ state->step));
+
+fail:
+ state->finished = true;
+}
+
+static bool test_fde_flags(struct torture_context *tctx,
+ const void *test_data)
+{
+ struct test_fde_flags_state state;
+
+ ZERO_STRUCT(state);
+
+ state.tctx = tctx;
+ state.backend = (const char *)test_data;
+
+ state.ev = tevent_context_init_byname(tctx, state.backend);
+ if (state.ev == NULL) {
+ torture_comment(tctx, "event backend '%s' not supported\n",
+ state.backend);
+ return true;
+ }
+
+ torture_comment(tctx, "Testing event backend '%s'\n",
+ state.backend);
+
+ /* create a socket pair */
+ socketpair(AF_UNIX, SOCK_STREAM, 0, state.fd);
+
+ state.expected_flags = TEVENT_FD_WRITE;
+ state.count = 0;
+
+ state.fde = tevent_add_fd(state.ev, state.ev, state.fd[1],
+ state.expected_flags,
+ test_fde_flags_fd1_handler,
+ &state);
+ tevent_fd_set_auto_close(state.fde);
+
+ state.te = tevent_add_timer(state.ev, state.ev,
+ timeval_current_ofs(10, 0),
+ test_fde_flags_te_failed,
+ &state);
+
+ while (!state.finished) {
+ errno = 0;
+ if (tevent_loop_once(state.ev) == -1) {
+ talloc_free(state.ev);
+ torture_fail(tctx, talloc_asprintf(tctx,
+ "Failed event loop %s\n",
+ strerror(errno)));
+ }
+ }
+
+ torture_comment(tctx, "Done testing event backend '%s'\n",
+ state.backend);
+ talloc_free(state.ev);
+
+ return true;
+}
+
struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
{
struct torture_suite *suite = torture_suite_create(mem_ctx, "event");
torture_suite_add_simple_tcase_const(suite, list[i],
test_event_context,
(const void *)list[i]);
+ torture_suite_add_simple_tcase_const(suite, list[i],
+ test_fde_flags,
+ (const void *)list[i]);
}
return suite;