-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathExecutorModule.hpp
More file actions
238 lines (221 loc) · 8.56 KB
/
Copy pathExecutorModule.hpp
File metadata and controls
238 lines (221 loc) · 8.56 KB
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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/* =============================================================================
* Vader Modular Fuzzer (VMF)
* Copyright (c) 2021-2025 The Charles Stark Draper Laboratory, Inc.
* <vmf@draper.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 (only) as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @license GPL-2.0-only <https://spdx.org/licenses/GPL-2.0-only.html>
* ===========================================================================*/
#pragma once
#include "StorageUserModule.hpp"
#include "RuntimeException.hpp"
#include "Logging.hpp"
#include <memory>
namespace vmf
{
/**
* @brief The base class for all VMF Executors
*
* Executore modules run the SUT using each test case as an input and capture the
* results of that execution in storage. This includes evaluating the bug oracle.
*
*/
class ExecutorModule : public StorageUserModule
{
public:
/**
* @brief Method that runs the provided test case on the SUT
*
* Any test results must be written to the storage entry.
* The specific data collected will depend on the executor, but in general
* includes information like whether the test case crashed or not and how
* long it took to execute.
*
* @param storage
* @param entry the entry to execute
*/
virtual void runTestCase(StorageModule& storage, StorageEntry* entry) = 0;
/**
* @brief Method that runs the provided list of test cases on the SUT
*
* This is an optional method. The default implementation of this method
* will simply call runTestCase() for every new entry in storage. Executors
* need only override this method if they do something other than run each of the
* entries individually (for example, a batch execution capability would
* likely require overriding this method).
*
* @param storage
* @param iterator
*/
virtual void runTestCases(StorageModule& storage, std::unique_ptr<Iterator>& iterator)
{
while(iterator->hasNext())
{
StorageEntry* entry = iterator->getNext();
runTestCase(storage, entry);
}
}
/**
* @brief Method that runs the provided test case in callibration mode
* This method is optional. But it will be called once with the initial
* seed test cases, and should be used for any callibration that requires
* sample test cases (such as determining a reasonable execution time for a test case).
*
* @param storage the reference to storage
* @param iterator an iterator that contains the initial seed test cases
*/
virtual void runCalibrationCases(StorageModule& storage, std::unique_ptr<Iterator>& iterator) {};
/**
* @brief Destroy the Executor Module object
*/
virtual ~ExecutorModule() {};
/**
* @brief Helper method to return a single Executor submodule from config
* This method will retrieve a single Executor submodules for the specified parent modules.
* If there are no Executor submodules, then an nullptr will be returned. If there are more
* than one Executor submodules specified, than an exception will be thrown. Use the list form
* of this method getExecutorSubmodules(), if more than one Executor module can be specified.
*
* @param config the ConfigInterface object
* @param parentName the name of the parent module
* @return ExecutorModule* the submodule, or nullptr if none is specified
*/
static ExecutorModule* getExecutorSubmodule(ConfigInterface& config, std::string parentName)
{
ExecutorModule* theModule = nullptr;
std::vector<Module*> modules = config.getSubModules(parentName);
for(Module* m: modules)
{
if(isAnInstance(m))
{
if(nullptr == theModule)
{
theModule = castTo(m);
}
else
{
throw RuntimeException(
"Configuration file contained more than one Executor module, but only one is supported",
RuntimeException::CONFIGURATION_ERROR);
}
}
}
return theModule;
}
/**
* @brief Helper method to return a single Executor submodule from config by name
* This method will retrieve a single Executor submodule by name for the specified parent modules.
* If there are no Executor submodules with the specified name, then an nullptr will be returned.
*
* @param config the ConfigInterface object
* @param parentName the name of the parent module
* @param childName the name of the child module to finde
* @return ExecutorModule* the submodule, or nullptr if none is found
*/
static ExecutorModule* getExecutorSubmoduleByName(ConfigInterface& config, std::string parentName, std::string childName)
{
ExecutorModule* theModule = nullptr;
std::vector<Module*> modules = config.getSubModules(parentName);
for(Module* m: modules)
{
if(childName == m->getModuleName())
{
if(isAnInstance(m))
{
theModule = castTo(m);
break;
}
else
{
LOG_ERROR << parentName << " requested an Executor submodule named " << childName
<< ", but that submodules is not of type Executor.";
throw RuntimeException(
"Configuration file contained a module with this name, but it was not an executor module",
RuntimeException::CONFIGURATION_ERROR);
}
}
}
return theModule;
}
/**
* @brief Helper method to get the Executor Submodules from config
* This method will retrieve all of the Executor submodules for the specified parent modules.
* If there are no Executor submodules, then an empty list will be returned.
*
* @param config the ConfigInterface object
* @param parentName the name of the parent module
* @return std::vector<ExecutorModule*> the list of submodules
*/
static std::vector<ExecutorModule*> getExecutorSubmodules(ConfigInterface& config, std::string parentName)
{
std::vector<ExecutorModule*> list;
std::vector<Module*> modules = config.getSubModules(parentName);
for(Module* m: modules)
{
if(isAnInstance(m))
{
list.push_back(castTo(m));
}
}
return list;
}
/**
* @brief Convenience method to determine if a module is actually an executor
*
* @param module
* @return true if this module has a module type=EXECUTOR
* @return false
*/
static bool isAnInstance(Module* module)
{
ModuleTypeEnum type = module->getModuleType();
return (ModuleTypeEnum::EXECUTOR == type);
}
/**
* @brief Convenience method to cast Module* to ExecutorModule*
*
* Call isAnInstance first to check the type in order to avoid an exception.
*
* @param module
* @return ExecutorModule*
* @throws RuntimeException if the underlying Module* is not a decendant of ExecutorModule
*/
static ExecutorModule* castTo(Module* module)
{
ExecutorModule* exec;
if(nullptr != module)
{
exec = dynamic_cast<ExecutorModule*>(module);
if(nullptr == exec)
{
throw RuntimeException("Failed attempt to cast module to Executor",
RuntimeException::USAGE_ERROR);
}
}
else
{
throw RuntimeException("Attempt to cast nullptr to Executor",
RuntimeException::UNEXPECTED_ERROR);
}
return exec;
}
protected:
/**
* @brief Construct a new Executor Module object
*
* @param name the module name
*/
ExecutorModule(std::string name) : StorageUserModule(name, ModuleTypeEnum::EXECUTOR) {};
};
}