blob: 239992ac25d5d11e3344ca2760402a14c86dcaf7 [file] [log] [blame]
#ifndef TESTS_PN_TEST_PROACTOR_HPP
#define TESTS_PN_TEST_PROACTOR_HPP
/*
* 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.
*/
/// @file
///
/// Wrapper for driving proactor tests.
#include "./pn_test.hpp"
#include <proton/proactor.h>
namespace pn_test {
// Get the listening port, l must be open.
std::string listening_port(pn_listener_t *l);
// Test proactor with an optional global handler.
// For connection and listener events, if pn_*_get_context() is non-NULL
// then it is cast to a handler and used instead of the global one.
struct proactor : auto_free<pn_proactor_t, pn_proactor_free> {
struct handler *handler;
proactor(struct handler *h = 0);
// Listen on addr using optional listener handler lh
pn_listener_t *listen(const std::string &addr = ":0", struct handler *lh = 0);
// Connect to addr use optional handler, and optionally providing the
// connection object.
pn_connection_t *connect(const std::string &addr, struct handler *h = 0,
pn_connection_t *c = 0);
// Connect to listenr's address useing optional handler.
pn_connection_t *connect(pn_listener_t *l, struct handler *h = 0,
pn_connection_t *c = 0) {
return connect(":" + pn_test::listening_port(l), h, c);
}
// Accept a connection, associate with optional connection handler.
pn_connection_t *accept(pn_listener_t *l, struct handler *h = 0);
// Wait for events and dispatch them until:
// * A handler returns true.
// * The `stop` event type is handled.
// Return the event-type of the last event handled or PN_EVENT_NONE
// if something went wrong.
pn_event_type_t run(pn_event_type_t stop = PN_EVENT_NONE);
// Dispatch immediately-available events until:
// * A handler returns true.
// * The `stop` event type is handled.
// * All available events are flushed.
//
// Returns the number of events processed and
// - PN_EVENT_NONE if all events were handled without stopping
// - The type of the last event handled otherwise
//
std::pair<int, pn_event_type_t> flush(pn_event_type_t stop = PN_EVENT_NONE);
// Alternate flushing this proactor and `other` until
// * A handler on this proactor returns true.
// * The `stop` event type is handled by this proactor.
// * Both proactors become idle.
//
// Return the event-type of the last event handled or PN_EVENT_NONE
// if the proactors are idle.
pn_event_type_t corun(proactor &other, pn_event_type_t stop = PN_EVENT_NONE);
// Wait for and handle a single event, return it's type.
pn_event_type_t wait_next();
private:
bool dispatch(pn_event_t *e);
};
// CHECK/REQUIRE macros to run a proactor up to an expected event and
// include the last condition in the error message if the expected event is not
// returned.
#define CHECK_RUN(P, E) \
CHECKED_IF((E) == (P).run(E)) {} \
else if ((P).handler) { \
FAIL_CHECK(*(P).handler->last_condition); \
}
#define REQUIRE_RUN(P, E) \
CHECKED_IF((E) == (P).run(E)) {} \
else if ((P).handler) { \
FAIL(*(P).handler->last_condition); \
}
#define CHECK_CORUN(P, O, E) \
CHECKED_IF((E) == (P).corun(O, E)) {} \
else if ((P).handler) { \
FAIL_CHECK(*(P).handler->last_condition); \
}
#define REQUIRE_CORUN(P, E) \
CHECKED_IF((E) == (P).corun(O, E)) {} \
else if ((P).handler_) { \
FAIL(*(P).handler_->last_condition); \
}
} // namespace pn_test
#endif // TESTS_PN_TEST_PROACTOR_HPP