Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
325 andreas 1
/*
2
 * Copyright (C) 2023 by Andreas Theofilu <andreas@theosys.at>
3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
#include <cstring>
326 andreas 19
#include <iomanip>
20
#include <fstream>
325 andreas 21
 
22
#include "testmode.h"
23
#include "tpagemanager.h"
326 andreas 24
#include "tdirectory.h"
325 andreas 25
#include "tconfig.h"
326 andreas 26
#include "tresources.h"
325 andreas 27
#include "terror.h"
328 andreas 28
#ifdef __ANDROID__
29
#include <android/log.h>
30
#endif
325 andreas 31
 
326 andreas 32
#define TIMEOUT     5000000  // Microseconds (5 seconds)
33
#define DELAY       100      // Wait this amount of microseconds
34
 
35
using std::string;
325 andreas 36
using std::strncpy;
37
using std::min;
326 andreas 38
using std::atomic;
39
using std::vector;
40
using std::cout;
41
using std::endl;
42
using std::ifstream;
43
using namespace dir;
325 andreas 44
 
326 andreas 45
atomic<bool> __success{false};
46
atomic<bool> __done{false};
47
bool _testmode{false};
48
string gLastCommand;
327 andreas 49
_TestMode *_gTestMode{nullptr};
326 andreas 50
 
51
extern amx::TAmxNet *gAmxNet;
52
 
53
_TestMode::_TestMode(const string& path)
54
    : mPath(path)
55
{
325 andreas 56
#if TESTMODE == 1
326 andreas 57
    DECL_TRACER("_TestMode::_TestMode(const string& path)");
325 andreas 58
 
326 andreas 59
    TDirectory dir(mPath);
60
    dir.scanFiles(".tst");
61
    size_t num = dir.getNumEntries();
62
    size_t pos = 0;
63
 
64
    while (pos < num)
65
    {
66
        DFILES_T f = dir.getEntry(pos);
67
 
68
        if (dir.testText(f.attr))
69
            mCmdFiles.push_back(f.name);
70
 
71
        pos++;
72
    }
325 andreas 73
#endif
74
}
75
 
326 andreas 76
_TestMode::~_TestMode()
325 andreas 77
{
326 andreas 78
    DECL_TRACER("_TestMode::~_TestMode()");
79
 
80
    _gTestMode = nullptr;
81
    gLastCommand.clear();
82
    prg_stopped = true;
83
    killed = true;
84
 
85
    if (gAmxNet)
86
        gAmxNet->stop();
87
 
88
    if (gPageManager)
89
        gPageManager->callShutdown();
90
}
91
 
92
void _TestMode::run()
93
{
94
#if TESTMODE == 1
95
    DECL_TRACER("_TestMode::run()");
96
 
97
    if (isRunning)
98
        return;
99
 
100
    try
101
    {
102
        mThread = std::thread([=] { this->start(); });
103
        mThread.detach();
104
    }
105
    catch (std::exception& e)
106
    {
107
        MSG_ERROR("Error spawning thread: " << e.what());
108
    }
109
#endif
110
}
111
 
112
void _TestMode::start()
113
{
114
    isRunning = true;
115
    DECL_TRACER("_TestMode::start()");
116
 
117
    vector<string>::iterator iter;
118
 
119
    for (iter = mCmdFiles.begin(); iter != mCmdFiles.end(); ++iter)
120
    {
121
        _TESTCMD tcmd;
122
 
123
        try
124
        {
125
            ifstream is(*iter);
126
            char buffer[4096];
327 andreas 127
            int line = 1;
326 andreas 128
            tcmd.command.clear();
129
            tcmd.result.clear();
130
            tcmd.compare = false;
131
 
132
            while (is.getline(buffer, sizeof(buffer)))
133
            {
134
                if (buffer[0] == '#')
135
                    continue;
136
 
137
                if (startsWith(buffer, "command="))
138
                {
139
                    string scmd(buffer);
140
 
141
                    size_t pos = scmd.find("=");
142
                    tcmd.command = scmd.substr(pos + 1);
143
                }
144
                else if (startsWith(buffer, "result="))
145
                {
146
                    string scmd(buffer);
147
 
148
                    size_t pos = scmd.find("=");
149
                    tcmd.result = scmd.substr(pos + 1);
150
                }
151
                else if (startsWith(buffer, "compare="))
152
                {
153
                    string scmd(buffer);
154
 
155
                    size_t pos = scmd.find("=");
156
                    string res = scmd.substr(pos + 1);
157
                    tcmd.compare = isTrue(res);
158
                }
327 andreas 159
                else if (startsWith(buffer, "exec"))
160
                {
161
                    if (tcmd.command.empty())
162
                    {
163
                       MSG_WARNING("Nothing to execute on line " << line << "!");
164
                       line++;
165
                       continue;
166
                    }
167
 
168
                    inform("Testing command: " + tcmd.command);
169
                    inject(1, tcmd.command);
170
                    testSuccess(tcmd);
171
 
172
                    tcmd.command.clear();
173
                    tcmd.result.clear();
174
                    tcmd.compare = false;
175
                }
176
 
177
                line++;
326 andreas 178
            }
179
 
180
            is.close();
181
        }
182
        catch (std::exception& e)
183
        {
184
            MSG_ERROR("Error on file " << *iter << ": " << e.what());
185
            continue;
186
        }
187
    }
327 andreas 188
/*
326 andreas 189
    inform("Testing command: ^MUT-1");
190
    inject(1, "^MUT-1");
191
    testSuccess();
192
 
193
    inform("Testing command: ^MUT-0");
194
    inject(1, "^MUT-0");
195
    testSuccess();
327 andreas 196
*/
326 andreas 197
    isRunning = false;
198
    delete this;
199
}
200
 
201
void _TestMode::inject(int port, const string& c)
202
{
325 andreas 203
    if (!gPageManager)
204
        return;
205
 
326 andreas 206
    gLastCommand = c;
325 andreas 207
    int channel = TConfig::getChannel();
208
    int system = TConfig::getSystem();
209
 
210
    amx::ANET_COMMAND cmd;
211
    cmd.MC = 0x000c;
212
    cmd.device1 = channel;
213
    cmd.port1 = port;
214
    cmd.system = system;
215
    cmd.data.message_string.system = system;
216
    cmd.data.message_string.device = channel;
217
    cmd.data.message_string.port = port;    // Must be the address port of button
326 andreas 218
    cmd.data.message_string.type = DTSZ_STRING;    // Char string
325 andreas 219
    cmd.data.message_string.length = min(c.length(), sizeof(cmd.data.message_string.content));
326 andreas 220
    memset(cmd.data.message_string.content, 0, sizeof(cmd.data.message_string.content));
221
    memcpy ((char *)cmd.data.message_string.content, c.c_str(), cmd.data.message_string.length);
325 andreas 222
    gPageManager->doCommand(cmd);
223
}
326 andreas 224
 
327 andreas 225
void _TestMode::testSuccess(_TESTCMD& tc)
326 andreas 226
{
227
    ulong total = 0;
228
 
229
    while (!__done && total < TIMEOUT)
230
    {
231
        usleep(DELAY);
232
        total += DELAY;
233
    }
234
 
235
    if (total >= TIMEOUT)
236
    {
237
        MSG_WARNING("Command \"" << gLastCommand << "\" timed out!");
238
#ifdef __ANDROID__
328 andreas 239
        __android_log_print(ANDROID_LOG_INFO, "tpanel", "Command \"%s\" timed out!", gLastCommand.c_str());
326 andreas 240
#else
241
        cout << "Command \"" << gLastCommand << "\" timed out!" << endl;
242
#endif
243
    }
244
 
327 andreas 245
    if (tc.compare && tc.result == verify)
246
    {
247
        MSG_WARNING("The result \"" << verify << "\" is equal to \"" << tc.result << "\"!");
248
        __success = true;
249
    }
250
    else if (tc.compare)
251
    {
252
        MSG_WARNING("The result \"" << verify << "\" does not match the expected result of \"" << tc.result << "\"!");
253
        __success = false;
254
    }
255
 
326 andreas 256
    if (__success)
257
    {
258
        MSG_INFO("SUCCESS (" << gLastCommand << ")");
259
#ifdef __ANDROID__
328 andreas 260
        __android_log_print(ANDROID_LOG_INFO, "tpanel", "SUCCESS (%s)", gLastCommand.c_str());
326 andreas 261
#else
262
        cout << "   SUCCESS (" << gLastCommand << ")" << endl;
263
#endif
264
    }
265
    else
266
    {
267
        MSG_ERROR("FAILED (" << gLastCommand << ")");
268
#ifdef __ANDROID__
328 andreas 269
        __android_log_print(ANDROID_LOG_ERROR, "tpanel", "FAILED (%s)", gLastCommand.c_str());
326 andreas 270
#else
271
        cout << "   FAILED (" << gLastCommand << ")" << endl;
272
#endif
273
    }
274
 
275
    __success = false;
276
    __done = false;
277
}
278
 
279
void _TestMode::inform(const string& msg)
280
{
281
    MSG_INFO(msg);
282
#ifdef __ANDROID__
283
    __android_log_print(ANDROID_LOG_ERROR, "tpanel", "%s", msg.c_str());
284
#else
285
    cout << msg << endl;
286
#endif
287
}