File: utils.h

package info (click to toggle)
tango 10.0.2%2Bdfsg1-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 89,936 kB
  • sloc: cpp: 201,786; sh: 1,645; python: 953; java: 800; perl: 467; javascript: 447; xml: 325; makefile: 272; sql: 72; ruby: 24
file content (211 lines) | stat: -rw-r--r-- 7,781 bytes parent folder | download | duplicates (3)
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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#ifndef TANGO_TESTS_CATCH2_UTILS_UTILS_H
#define TANGO_TESTS_CATCH2_UTILS_UTILS_H

#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include <catch2/generators/catch_generators_range.hpp>
#include <catch2/matchers/catch_matchers_all.hpp>

#include "utils/auto_device_class.h"
#include "utils/test_server.h"
#include "utils/callback_mock.h"
#include "utils/matchers.h"
#include "utils/generators.h"

#include <tango/tango.h>

#include <memory>

namespace TangoTest
{

std::string make_nodb_fqtrl(int port, std::string_view device_name);

const char *get_current_log_file_path();

/* @brief Return a disc location where a FileDatabase can be created
 *
 */
std::string get_next_file_database_location();

// TODO: Multiple devices and/or multiple device servers
// TODO: Maybe we want a builder API for this
class Context
{
  public:
    /**
     * @brief Create a Tango Test Context with a single device server in nodb mode
     *
     * @param instance_name Name of the device server instance
     * @param class_name Name of the device class to instantiate
     * @param env environment entries of the form "key1=value1", "key2=value2"
     */
    Context(const std::string &instance_name, const std::string &class_name, std::vector<std::string> env = {});

    /**
     * @brief Create a Tango Test Context with a single device server in nodb mode
     *
     * @param instance_name Name of the device server instance
     * @param tmpl_name Name of the template device class to instantiate
     * @param idlversion IDL version of the device class to instantiate
     * @param env environment entries of the form "key1=value1", "key2=value2"
     */
    Context(const std::string &instance_name,
            const std::string &tmpl_name,
            int idlversion,
            std::vector<std::string> env = {});
    /**
     * @brief Create a Tango Test Context with a single device server in filedb mode
     *
     * TODO: Do not require users to pass the filedb_contents
     *
     * @param instance_name Name of the device server instance
     * @param tmpl_name Name of the template device class to instantiate
     * @param idlversion IDL version of the device class to instantiate
     * @param extra_filedb_contents Contents of the filedb to use
     * @param env environment entries of the form "key1=value1", "key2=value2"
     */
    Context(const std::string &instance_name,
            const std::string &tmpl_name,
            int idlversion,
            const std::string &extra_filedb_contents,
            std::vector<std::string> env = {});

    Context(const Context &) = delete;
    Context &operator=(Context &) = delete;

    ~Context();

    std::unique_ptr<Tango::DeviceProxy> get_proxy();
    std::unique_ptr<Tango::DeviceProxy> get_admin_proxy();

    /** Wait until the server stops.
     *
     *  Intended to be called if the server is being stopped by some means
     *  outside of the test infrastructure, e.g. the DServer Kill command.
     *
     *  @param timeout to wait for the server to stop
     *
     *  Returns the exit status of the server.
     *
     *  Throws: a `runtime_error` if the timeout is exceeded.
     */
    ExitStatus wait_for_exit(std::chrono::milliseconds timeout = TestServer::k_default_timeout);

    /** Stop the associated TestServer instance if it has been started.
     *
     *  If the instance has a non-zero exit status, then diagnostics will be
     *  output with the Catch2 WARN macro.
     *
     *  Returns when the server has stopped or the timeout has been reached
     *
     *  @param timeout if the server takes longer than this timeout,
     *  a warning log will be generated
     */
    void stop_server(std::chrono::milliseconds timeout = TestServer::k_default_timeout);

    /*
     * Return the disc location of the FileDatabase, throws if there is none.
     */
    std::string get_file_database_path();

    /*
     * Return the name of the Tango device class
     */
    std::string get_class_name();

    /**
     * Get the server redirection file
     */
    const std::string &get_redirect_file() const;

    /** Restart the server if it has been stopped using the same port.
     *
     * @param timeout -- how long to wait for the server to start
     *
     * Throws: a `runtime_error` if the server cannot be restarted
     *
     * Expects: `stop_server()` has been called previously
     */
    void restart_server(std::chrono::milliseconds timeout = TestServer::k_default_timeout);

  private:
    std::optional<std::string> m_filedb_path = std::nullopt;
    TestServer m_server;
    std::string m_class_name;
    std::string m_instance_name;
    std::vector<std::string> m_extra_args;
    std::vector<std::string> m_extra_env;
};

namespace detail
{
constexpr const char *k_log_file_env_var = "TANGO_TEST_LOG_FILE";
// Setup a log appender to the file specified in the environment variable
// TANGO_TEST_LOG_FILE.  Each log is prefixed with `topic`, this allows
// multiple processes to log to this file at the same time.
//
// If the environment variable is not set, this does nothing.
//
// Expects: Tango::Logging::get_core_logger() != nullptr
void setup_topic_log_appender(std::string_view topic, const char *filename = nullptr);

// A unique identifier representing the random seed used by the test run to make
// it easier for the user to identify log files.  This is constructed during the
// testRunStarting Catch2 event.
extern std::string g_log_filename_prefix;

// Return a filename containing the test_case_name, starting with
// g_log_filename_prefix and ending with suffix.
//
// The filename will not exceed the path component size limit on the platform.
// And any spaces (' ') in the test_case_name will be replaced with underscores
// ('_').
std::string filename_from_test_case_name(std::string_view test_case_name, std::string_view suffix);
} // namespace detail

} // namespace TangoTest

/**
 * @brief Instantiate a TangoTest::AutoDeviceClass for template class DEVICE
 *
 * This macro expects that the DEVICE takes its base class as a template
 * parameter:
 *
 *     template<typename Base>
 *     class DEVICE : public Base {
 *         ...
 *     };
 *
 * It will instantiate a TangoTest::AutoDeviceClass with a base class using IDL
 * version MIN and onwards.
 *
 * @param DEVICE class template
 * @param MIN minimum DeviceImpl version to use
 */
#define TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE(DEVICE, MIN) TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_##MIN(DEVICE)

#define TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_1(DEVICE)                           \
    TANGO_TEST_AUTO_DEV_CLASS_INSTANTIATE(DEVICE<Tango::DeviceImpl>, DEVICE##_1) \
    TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_2(DEVICE)

#define TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_2(DEVICE)                             \
    TANGO_TEST_AUTO_DEV_CLASS_INSTANTIATE(DEVICE<Tango::Device_2Impl>, DEVICE##_2) \
    TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_3(DEVICE)

#define TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_3(DEVICE)                             \
    TANGO_TEST_AUTO_DEV_CLASS_INSTANTIATE(DEVICE<Tango::Device_3Impl>, DEVICE##_3) \
    TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_4(DEVICE)

#define TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_4(DEVICE)                             \
    TANGO_TEST_AUTO_DEV_CLASS_INSTANTIATE(DEVICE<Tango::Device_4Impl>, DEVICE##_4) \
    TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_5(DEVICE)

#define TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_5(DEVICE)                             \
    TANGO_TEST_AUTO_DEV_CLASS_INSTANTIATE(DEVICE<Tango::Device_5Impl>, DEVICE##_5) \
    TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_6(DEVICE)

#define TANGO_TEST_AUTO_DEV_TMPL_INSTANTIATE_6(DEVICE) \
    TANGO_TEST_AUTO_DEV_CLASS_INSTANTIATE(DEVICE<Tango::Device_6Impl>, DEVICE##_6)

#endif