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

mendersoftware / mender / 1000821593

12 Sep 2023 09:08AM UTC coverage: 78.672% (-0.5%) from 79.215%
1000821593

push

gitlab-ci

lluiscampos
fix(conf): Fix private key path to be set after changing `data_store`

Amends fix 4620c8456.

Changelog: None
Ticket: None

Signed-off-by: Lluis Campos <lluis.campos@northern.tech>

1 of 1 new or added line in 1 file covered. (100.0%)

5843 of 7427 relevant lines covered (78.67%)

250.17 hits per line

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

74.24
/common/testing.cpp
1
// Copyright 2023 Northern.tech AS
2
//
3
//    Licensed under the Apache License, Version 2.0 (the "License");
4
//    you may not use this file except in compliance with the License.
5
//    You may obtain a copy of the License at
6
//
7
//        http://www.apache.org/licenses/LICENSE-2.0
8
//
9
//    Unless required by applicable law or agreed to in writing, software
10
//    distributed under the License is distributed on an "AS IS" BASIS,
11
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//    See the License for the specific language governing permissions and
13
//    limitations under the License.
14

15
#include <common/testing.hpp>
16

17
#include <cstdlib>
18
#include <filesystem>
19
#include <random>
20
#include <iostream>
21

22
#include <common/json.hpp>
23
#include <common/log.hpp>
24
#include <common/path.hpp>
25
#include <common/processes.hpp>
26

27
namespace mender {
28
namespace common {
29
namespace testing {
30

31
namespace fs = std::filesystem;
32

33
namespace log = mender::common::log;
34
namespace path = mender::common::path;
35

36
shared_ptr<ostream> AssertInDeathTestHelper(const char *func, const char *file, int line) {
×
37
        // Unsuccessful assert. Return a stream which prints to stderr, and which aborts when it is
38
        // destroyed (at the end of the statement evaluation).
39
        cerr << "Assert at " << func << " in " << file << ":" << line << endl;
×
40
        return shared_ptr<ostream>(new ostream(cerr.rdbuf()), [](ostream *) { std::abort(); });
×
41
}
42

43
TemporaryDirectory::TemporaryDirectory() {
376✔
44
        fs::path path = fs::temp_directory_path();
376✔
45
        path.append("mender-test-" + std::to_string(std::random_device()()));
376✔
46
        if (!fs::create_directories(path)) {
376✔
47
                throw runtime_error("Failed to create the temporary directory: " + string(path));
×
48
        }
49
        path_ = path;
376✔
50
}
376✔
51

52
TemporaryDirectory::~TemporaryDirectory() {
1,128✔
53
        fs::remove_all(path_);
376✔
54
}
376✔
55

56
std::string TemporaryDirectory::Path() const {
1,228✔
57
        return path_;
1,228✔
58
}
59

60
void TemporaryDirectory::CreateSubDirectory(const string &dirname) {
20✔
61
        fs::path sub_path {path_};
20✔
62
        sub_path.append(dirname);
20✔
63
        ASSERT_TRUE(fs::create_directory(sub_path));
20✔
64
}
65

66
::testing::AssertionResult FileContains(const string &filename, const string &expected_content) {
14✔
67
        ifstream is {filename};
28✔
68
        if (!is) {
14✔
69
                auto errnum {errno};
1✔
70
                return ::testing::AssertionFailure()
2✔
71
                           << "Cannot open `" << filename
1✔
72
                           << "`: " << generic_category().default_error_condition(errnum).message();
2✔
73
        }
74
        ostringstream contents_s;
26✔
75
        contents_s << is.rdbuf();
13✔
76
        string contents {contents_s.str()};
26✔
77
        if (contents.find(expected_content) != contents.npos) {
13✔
78
                return ::testing::AssertionSuccess();
12✔
79
        }
80
        return ::testing::AssertionFailure()
2✔
81
                   << "'" << contents << "' does not contain '" << expected_content << "'";
1✔
82
}
83

84
::testing::AssertionResult FileContainsExactly(
135✔
85
        const string &filename, const string &expected_content) {
86
        ifstream is {filename};
270✔
87
        if (!is) {
135✔
88
                auto errnum {errno};
×
89
                return ::testing::AssertionFailure()
×
90
                           << "Cannot open `" << filename
×
91
                           << "`: " << generic_category().default_error_condition(errnum).message();
×
92
        }
93
        ostringstream contents_s;
270✔
94
        contents_s << is.rdbuf();
135✔
95
        string contents {contents_s.str()};
270✔
96
        if (contents == expected_content) {
135✔
97
                return ::testing::AssertionSuccess();
135✔
98
        }
99
        return ::testing::AssertionFailure()
×
100
                   << "Expected: '" << expected_content << "' Got: '" << contents << "'";
×
101
}
102

103

104
::testing::AssertionResult FileJsonEquals(const string &filename, const string &expected_content) {
2✔
105
        ifstream is {filename};
4✔
106
        json::Json contents = json::Load(is).value();
4✔
107
        json::Json expected_contents = json::Load(expected_content).value();
6✔
108
        if (contents.Dump() == expected_contents.Dump()) {
2✔
109
                return ::testing::AssertionSuccess();
2✔
110
        }
111
        return ::testing::AssertionFailure()
×
112
                   << "Expected: '" << contents.Dump() << "' Got: '" << expected_contents.Dump() << "'";
×
113
}
114

115
::testing::AssertionResult FilesEqual(const string &filename1, const string &filename2) {
8✔
116
        processes::Process proc({"diff", "-u", filename1, filename2});
64✔
117
        auto err = proc.Run();
16✔
118
        if (err == error::NoError) {
8✔
119
                return ::testing::AssertionSuccess();
8✔
120
        }
121
        // Some extra information in case of failure.
122
        cout << "ls -l " << filename1 << " " << filename2 << endl;
×
123
        processes::Process listdir({"ls", "-l", filename1, filename2});
×
124
        listdir.Run();
×
125
        return ::testing::AssertionFailure() << filename1 << " and " << filename2 << " differ";
×
126
}
127

128
::testing::AssertionResult FilesNotEqual(const string &filename1, const string &filename2) {
1✔
129
        processes::Process proc({"cmp", "-s", filename1, filename2});
8✔
130
        auto err = proc.Run();
2✔
131
        // We need to explicitly check for 1 exit code - 0 means no differences and 2 means trouble.
132
        if (err != error::NoError && err.message.back() == '1') {
1✔
133
                return ::testing::AssertionSuccess();
1✔
134
        }
135
        return ::testing::AssertionFailure() << filename1 << " and " << filename2 << " are equal";
×
136
}
137

138
const string HttpFileServer::serve_address_ {"http://127.0.0.1:53272"};
139

140
HttpFileServer::HttpFileServer(const string &dir) :
46✔
141
        dir_ {dir},
142
        server_(http::ServerConfig {}, loop_) {
46✔
143
        // The reason we need this synchronization is because of the thread sanitizer and
144
        // logging. AsyncServeUrl uses the logger internally, and the log level is also set by
145
        // certain tests. Since these things happen in two separate threads, we need to make sure
146
        // that AsyncServeUrl has returned before we leave this function.
147
        promise<bool> running;
92✔
148
        auto maybe_running = running.get_future();
92✔
149

150
        thread_ = thread([this, &running]() {
46✔
151
                auto err = server_.AsyncServeUrl(
152
                        serve_address_,
153
                        [](http::ExpectedIncomingRequestPtr exp_req) {
31✔
154
                                if (!exp_req) {
31✔
155
                                        log::Warning("HttpFileServer: " + exp_req.error().String());
×
156
                                }
157
                        },
31✔
158
                        [this](http::ExpectedIncomingRequestPtr exp_req) { Serve(exp_req); });
123✔
159
                if (err != error::NoError) {
46✔
160
                        log::Error("HttpFileServer: " + err.String());
×
161
                        return;
×
162
                }
163

164
                running.set_value(true);
46✔
165
                loop_.Run();
46✔
166
        });
46✔
167

168
        maybe_running.wait();
46✔
169
}
46✔
170

171
HttpFileServer::~HttpFileServer() {
46✔
172
        loop_.Stop();
46✔
173
        thread_.join();
46✔
174
}
46✔
175

176
void HttpFileServer::Serve(http::ExpectedIncomingRequestPtr exp_req) {
31✔
177
        if (!exp_req) {
31✔
178
                log::Warning("HttpFileServer: " + exp_req.error().String());
×
179
                return;
×
180
        }
181

182
        auto req = exp_req.value();
31✔
183

184
        if (req->GetMethod() != http::Method::GET) {
31✔
185
                log::Warning(
×
186
                        "HttpFileServer: Expected HTTP GET method, but got "
187
                        + http::MethodToString(req->GetMethod()));
×
188
                return;
×
189
        }
190

191
        auto exp_resp = req->MakeResponse();
31✔
192
        if (!exp_resp) {
31✔
193
                log::Warning("HttpFileServer: " + exp_resp.error().String());
×
194
                return;
×
195
        }
196
        auto resp = exp_resp.value();
31✔
197

198
        auto path = req->GetPath();
31✔
199
        while (path.size() > 0 && path[0] == '/') {
62✔
200
                path = string {path.begin() + 1, path.end()};
31✔
201
        }
202

203
        string file_path = path::Join(dir_, path);
31✔
204

205
        auto exp_stream = io::OpenIfstream(file_path);
31✔
206
        if (!exp_stream) {
31✔
207
                resp->SetStatusCodeAndMessage(http::StatusNotFound, exp_stream.error().String());
1✔
208
                resp->SetHeader("Content-Length", "0");
1✔
209
                resp->SetBodyReader(make_shared<io::StringReader>(""));
1✔
210
        } else {
211
                auto exp_size = io::FileSize(file_path);
30✔
212
                if (!exp_size) {
30✔
213
                        log::Warning("HttpFileServer: " + exp_size.error().String());
×
214
                        resp->SetStatusCodeAndMessage(
×
215
                                http::StatusInternalServerError, exp_size.error().String());
×
216
                        resp->SetHeader("Content-Length", "0");
×
217
                        return;
×
218
                }
219

220
                resp->SetStatusCodeAndMessage(http::StatusOK, "");
30✔
221
                resp->SetBodyReader(
60✔
222
                        make_shared<io::StreamReader>((make_shared<ifstream>(std::move(exp_stream.value())))));
60✔
223

224
                resp->SetHeader("Content-Length", to_string(exp_size.value()));
30✔
225
        }
226

227
        auto err = resp->AsyncReply([](error::Error err) {
31✔
228
                if (err != error::NoError) {
31✔
229
                        log::Warning("HttpFileServer: " + err.String());
×
230
                }
231
        });
93✔
232
        if (err != error::NoError) {
31✔
233
                log::Warning("HttpFileServer: " + err.String());
×
234
        }
235
}
236

237
} // namespace testing
238
} // namespace common
239
} // namespace mender
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

© 2025 Coveralls, Inc