• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jgomezselles / hermes / 6989477809

25 Nov 2023 01:50PM UTC coverage: 96.907% (+0.4%) from 96.514%
6989477809

push

github

jgomezselles
Bump up checkout actions

940 of 970 relevant lines covered (96.91%)

167.31 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

99.12
/src/script/script.cpp
1
#include "script.hpp"
2

3
#include <boost/algorithm/string.hpp>
4
#include <deque>
5
#include <exception>
6
#include <fstream>
7
#include <iostream>
8
#include <map>
9
#include <optional>
10
#include <set>
11
#include <vector>
12

13
#include "json_reader.hpp"
14
#include "opentelemetry/trace/semantic_conventions.h"
15
#include "script_functions.hpp"
16
#include "script_reader.hpp"
17
#include "tracer.hpp"
18

19
namespace traffic
20
{
21
script::script(const std::string& path)
4✔
22
{
23
    std::ifstream json_file(path);
4✔
24
    if (!json_file)
4✔
25
    {
26
        throw std::out_of_range("File " + path +
4✔
27
                                " not found."
28
                                "Terminating application.");
6✔
29
    }
30
    const auto json_str =
31
        std::string((std::istreambuf_iterator<char>(json_file)), std::istreambuf_iterator<char>());
2✔
32

33
    build(json_str);
2✔
34
}
38✔
35

36
script::script(const json_reader& input_json)
78✔
37
{
38
    build(input_json.as_string());
84✔
39
}
120✔
40

41
script::~script()
426✔
42
{
43
    if (span)
426✔
44
    {
45
        span->End();
68✔
46
    }
47
}
426✔
48

49
void script::validate_members() const
78✔
50
{
51
    std::set<std::string, std::less<>> unique_ids;
78✔
52
    check_repeated(unique_ids, vars);
78✔
53
    check_repeated(unique_ids, ranges);
78✔
54

55
    for (const auto& m : messages)
178✔
56
    {
57
        for (const std::string forbidden : {"content_type", "content_length"})
522✔
58
        {
59
            if (m.headers.find(forbidden) != m.headers.end())
210✔
60
            {
61
                throw std::invalid_argument(
62
                    forbidden + " is built automatically in headers. Cannot set custom values.");
4✔
63
            }
64
        }
210✔
65
    }
66
}
78✔
67

68
void script::build(const std::string& input_json)
80✔
69
{
70
    script_reader sr{input_json};
80✔
71
    ranges = sr.build_ranges();
78✔
72
    messages = sr.build_messages();
78✔
73
    server = sr.build_server_info();
78✔
74
    timeout_ms = sr.build_timeout();
78✔
75
    vars = sr.build_variables();
78✔
76
    validate_members();
78✔
77
}
78✔
78

79
std::vector<std::string> script::get_message_names() const
2✔
80
{
81
    std::vector<std::string> res;
2✔
82
    for (const auto& m : messages)
4✔
83
    {
84
        res.push_back(m.id);
2✔
85
    }
86

87
    return res;
2✔
88
}
×
89

90
bool script::save_from_answer(const answer_type& answer, const msg_modifier& sfa)
32✔
91
{
92
    try
93
    {
94
        save_headers(sfa.headers, answer.headers, vars);
32✔
95

96
        for (const auto& [id, mm] : sfa.body_fields)
48✔
97
        {
98
            json_reader ans_json{answer.body, "{}"};
48✔
99
            if (mm.value_type == "string")
24✔
100
            {
101
                saved_strs[id] = ans_json.get_value<std::string>(mm.path);
10✔
102
            }
103
            else if (mm.value_type == "int")
14✔
104
            {
105
                saved_ints[id] = ans_json.get_value<int>(mm.path);
8✔
106
            }
107
            else if (mm.value_type == "object")
6✔
108
            {
109
                saved_jsons[id] = ans_json.get_value<json_reader>(mm.path);
6✔
110
            }
111
        }
24✔
112
    }
113
    catch (const std::logic_error&)
8✔
114
    {
115
        return false;
8✔
116
    }
8✔
117
    return true;
24✔
118
}
119

120
bool script::add_to_request(const std::map<std::string, body_modifier, std::less<>>& atb,
24✔
121
                            message& m)
122
{
123
    std::string str_modif_body = m.body.empty() ? "{}" : m.body;
56✔
124
    json_reader modified_body(str_modif_body, "{}");
24✔
125

126
    try
127
    {
128
        for (const auto& [id, mm] : atb)
32✔
129
        {
130
            if (mm.value_type == "string")
10✔
131
            {
132
                modified_body.set(mm.path, saved_strs.at(id));
4✔
133
            }
134
            else if (mm.value_type == "int")
6✔
135
            {
136
                modified_body.set(mm.path, saved_ints.at(id));
4✔
137
            }
138
            else if (mm.value_type == "object")
2✔
139
            {
140
                modified_body.set(mm.path, saved_jsons.at(id));
2✔
141
            }
142
        }
143

144
        if (str_modif_body = modified_body.as_string(); str_modif_body != "{}")
22✔
145
        {
146
            m.body = str_modif_body;
8✔
147
        }
148
    }
149
    catch (const std::out_of_range&)
2✔
150
    {
151
        return false;
2✔
152
    }
2✔
153

154
    return true;
22✔
155
}
24✔
156

157
void replace_in_message(const std::string& old_str, const std::string& new_str, message& m)
30✔
158
{
159
    std::string str_to_replace = "<" + old_str + ">";
30✔
160
    boost::replace_all(m.body, str_to_replace, new_str);
30✔
161
    boost::replace_all(m.url, str_to_replace, new_str);
30✔
162

163
    traffic::msg_headers new_headers;
30✔
164
    for (std::pair<std::string, std::string> p : m.headers)
50✔
165
    {
166
        boost::replace_all(p.first, str_to_replace, new_str);
20✔
167
        boost::replace_all(p.second, str_to_replace, new_str);
20✔
168
        new_headers.insert(p);
20✔
169
    }
20✔
170
    m.headers = std::move(new_headers);
30✔
171
}
30✔
172

173
bool script::process_next(const answer_type& last_answer)
32✔
174
{
175
    // TODO: if this is an error, validation should fail. Rethink
176
    if (!save_from_answer(last_answer, messages.front().sfa))
32✔
177
    {
178
        return false;
8✔
179
    }
180

181
    messages.pop_front();
24✔
182

183
    auto& next_msg = messages.front();
24✔
184
    if (!add_to_request(next_msg.atb, next_msg))
24✔
185
    {
186
        return false;
2✔
187
    }
188

189
    for (const auto& [k, v] : vars)
30✔
190
    {
191
        replace_in_message(k, v, next_msg);
8✔
192
    }
193

194
    return true;
22✔
195
}
196

197
bool script::validate_answer(const answer_type& last_answer) const
12✔
198
{
199
    return last_answer.result_code == messages.front().pass_code;
12✔
200
}
201

202
bool script::post_process(const answer_type& last_answer)
40✔
203
{
204
    return !is_last() && process_next(last_answer);
40✔
205
}
206

207
void script::replace_in_messages(const std::string& old_str, const std::string& new_str)
16✔
208
{
209
    for (auto& m : messages)
38✔
210
    {
211
        replace_in_message(old_str, new_str, m);
22✔
212
    }
213
}
16✔
214

215
void script::parse_ranges(const std::map<std::string, int64_t, std::less<>>& current)
22✔
216
{
217
    for (const auto& [k, v] : current)
30✔
218
    {
219
        replace_in_messages(k, std::to_string(v));
8✔
220
    }
221
}
22✔
222

223
void script::parse_variables()
22✔
224
{
225
    for (const auto& [k, v] : vars)
30✔
226
    {
227
        replace_in_messages(k, v);
8✔
228
    }
229
}
22✔
230

231
void script::start_span()
20✔
232
{
233
    span = o11y::create_span("script");
20✔
234
}
20✔
235

236
}  // namespace traffic
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc