blob: 011079ae27c40b2a4e78ed63c6e5b0fb8d133bcb (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#pragma once
#include "transport.h"
#include <vespa/vespalib/util/rendezvous.h>
#include <vespa/vespalib/util/time.h>
#include <memory>
namespace fnet {
/**
* This class is used to control transport threads during unit
* testing.
*
* The TimeTools created by this class should be used when setting up
* all transports used in the test. The supplied TimeTools will make
* sure no thread ever blocks waiting for io-events and also make sure
* all threads observe the same externally controlled current
* time. After the transport layers are started, the attach function
* is used to start controlling event loop execution. While attached,
* calling the step function will run each transport thread event loop
* exactly once (in parallel), wait for pending dns resolving, wait
* for pending tls handshake work and advance the current time (the
* default 5ms will make sure 'time passes' and 'stuff happens' at a
* reasonable relative rate). It is important to call detach to
* release the transports before trying to shut them down.
*
* Note that both server and client should be controlled by the same
* debugger when testing rpc. Using external services will result in
* (synthetic) time passing too fast compared to stuff actually
* happening, since you do not control the other end-point in the same
* way.
*
* Take a look at the unit test for this class for an example of how
* to use it.
**/
class TransportDebugger
{
private:
struct Meet : vespalib::Rendezvous<bool,bool> {
Meet(size_t N) : vespalib::Rendezvous<bool,bool>(N) {}
void mingle() override;
};
vespalib::steady_time _time;
std::shared_ptr<Meet> _meet;
public:
TransportDebugger();
~TransportDebugger();
vespalib::steady_time time() const { return _time; }
TimeTools::SP time_tools() {
return TimeTools::make_debug(vespalib::duration::zero(), [this]() noexcept { return time(); });
}
void attach(std::initializer_list<std::reference_wrapper<FNET_Transport> > list);
void step(vespalib::duration time_passed = 5ms);
template <typename Pred>
bool step_until(Pred pred, vespalib::duration time_limit = 120s) {
auto start = time();
while (!pred() && ((time() - start) < time_limit)) {
step();
}
return pred();
}
void detach();
};
}
|