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

mendersoftware / mender / 1018307341

27 Sep 2023 12:04PM UTC coverage: 77.682% (-0.4%) from 78.076%
1018307341

push

gitlab-ci

vpodzime
fix: Wait repeatedly for I/O events on DBus file descriptors

ASIO's `stream_descriptor::async_read/wait/error()` all register
one-off handlers. We actually need to watch the given file
descriptors for all events until we cancel the watch.

We can do that by using functors re-registering themselves
whenever called.

Also, add a tip and commented code to DBus tests helping debug
DBus issues.

Ticket: MEN-6655
Changelog: none
Signed-off-by: Vratislav Podzimek <v.podzimek@mykolab.com>

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

6474 of 8334 relevant lines covered (77.68%)

11035.56 hits per line

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

72.22
/mender-update/cli/cli.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 <mender-update/cli/cli.hpp>
16

17
#include <iostream>
18

19
#include <common/conf.hpp>
20

21
namespace mender {
22
namespace update {
23
namespace cli {
24

25
namespace conf = mender::common::conf;
26

27
const int NoUpdateInProgressExitStatus = 2;
28
const int RebootExitStatus = 4;
29

30
ExpectedActionPtr ParseUpdateArguments(
96✔
31
        vector<string>::const_iterator start, vector<string>::const_iterator end) {
32
        if (start == end) {
96✔
33
                return expected::unexpected(conf::MakeError(conf::InvalidOptionsError, "Need an action"));
2✔
34
        }
35

36
        if (start[0] == "show-artifact") {
95✔
37
                unordered_set<string> options {};
8✔
38
                conf::CmdlineOptionsIterator iter(start + 1, end, options, options);
8✔
39
                auto arg = iter.Next();
8✔
40
                if (!arg) {
4✔
41
                        return expected::unexpected(arg.error());
4✔
42
                }
43

44
                return make_shared<ShowArtifactAction>();
4✔
45
        } else if (start[0] == "show-provides") {
91✔
46
                unordered_set<string> options {};
68✔
47
                conf::CmdlineOptionsIterator iter(start + 1, end, options, options);
68✔
48
                auto arg = iter.Next();
68✔
49
                if (!arg) {
34✔
50
                        return expected::unexpected(arg.error());
4✔
51
                }
52

53
                return make_shared<ShowProvidesAction>();
64✔
54
        } else if (start[0] == "install") {
57✔
55
                unordered_set<string> options {};
94✔
56
                conf::CmdlineOptionsIterator iter(start + 1, end, options, {"--reboot-exit-code"});
235✔
57
                iter.SetArgumentsMode(conf::ArgumentsMode::AcceptBareArguments);
47✔
58

59
                string filename;
94✔
60
                bool reboot_exit_code = false;
47✔
61
                while (true) {
62
                        auto arg = iter.Next();
93✔
63
                        if (!arg) {
93✔
64
                                return expected::unexpected(arg.error());
2✔
65
                        }
66

67
                        auto value = arg.value();
92✔
68
                        if (value.option == "--reboot-exit-code") {
92✔
69
                                reboot_exit_code = true;
1✔
70
                                continue;
1✔
71
                        } else if (value.option != "") {
91✔
72
                                return expected::unexpected(
×
73
                                        conf::MakeError(conf::InvalidOptionsError, "No such option: " + value.option));
×
74
                        }
75

76
                        if (value.value != "") {
91✔
77
                                if (filename != "") {
46✔
78
                                        return expected::unexpected(conf::MakeError(
1✔
79
                                                conf::InvalidOptionsError, "Too many arguments: " + value.value));
2✔
80
                                } else {
81
                                        filename = value.value;
45✔
82
                                }
83
                        } else {
84
                                if (filename == "") {
45✔
85
                                        return expected::unexpected(
1✔
86
                                                conf::MakeError(conf::InvalidOptionsError, "Need a path to an artifact"));
2✔
87
                                } else {
88
                                        break;
44✔
89
                                }
90
                        }
91
                }
46✔
92

93
                return make_shared<InstallAction>(filename, reboot_exit_code);
88✔
94
        } else if (start[0] == "commit") {
10✔
95
                unordered_set<string> options {};
8✔
96
                conf::CmdlineOptionsIterator iter(start + 1, end, options, options);
8✔
97
                auto arg = iter.Next();
8✔
98
                if (!arg) {
4✔
99
                        return expected::unexpected(arg.error());
×
100
                }
101

102
                return make_shared<CommitAction>();
8✔
103
        } else if (start[0] == "rollback") {
6✔
104
                unordered_set<string> options {};
12✔
105
                conf::CmdlineOptionsIterator iter(start + 1, end, options, options);
12✔
106
                auto arg = iter.Next();
12✔
107
                if (!arg) {
6✔
108
                        return expected::unexpected(arg.error());
×
109
                }
110

111
                return make_shared<RollbackAction>();
12✔
112
        } else if (start[0] == "daemon") {
×
113
                unordered_set<string> options {};
×
114
                conf::CmdlineOptionsIterator iter(start + 1, end, options, options);
×
115
                auto arg = iter.Next();
×
116
                if (!arg) {
×
117
                        return expected::unexpected(arg.error());
×
118
                }
119

120
                return make_shared<DaemonAction>();
×
121
        } else if (start[0] == "show-inventory") {
×
122
                unordered_set<string> options {};
×
123
                conf::CmdlineOptionsIterator iter(start + 1, end, options, options);
×
124
                auto arg = iter.Next();
×
125
                if (!arg) {
×
126
                        return expected::unexpected(arg.error());
×
127
                }
128

129
                return make_shared<ShowInventoryAction>();
×
130
        } else if (start[0] == "check-update") {
×
131
                unordered_set<string> options {};
×
132
                conf::CmdlineOptionsIterator iter(start + 1, end, options, options);
×
133
                auto arg = iter.Next();
×
134
                if (!arg) {
×
135
                        return expected::unexpected(arg.error());
×
136
                }
137

138
                return make_shared<CheckUpdateAction>();
×
139
        } else {
140
                return expected::unexpected(
×
141
                        conf::MakeError(conf::InvalidOptionsError, "No such action: " + start[0]));
×
142
        }
143
}
144

145
static error::Error DoMain(
96✔
146
        const vector<string> &args,
147
        function<void(mender::update::context::MenderContext &ctx)> test_hook) {
148
        mender::common::conf::MenderConfig config;
192✔
149

150
        auto args_pos = config.ProcessCmdlineArgs(args.begin(), args.end());
192✔
151
        if (!args_pos) {
96✔
152
                return args_pos.error();
×
153
        }
154

155
        auto action = ParseUpdateArguments(args.begin() + args_pos.value(), args.end());
192✔
156
        if (!action) {
96✔
157
                return action.error();
8✔
158
        }
159

160
        mender::update::context::MenderContext main_context(config);
176✔
161

162
        test_hook(main_context);
88✔
163

164
        auto err = main_context.Initialize();
176✔
165
        if (error::NoError != err) {
88✔
166
                return err;
×
167
        }
168

169
        return action.value()->Execute(main_context);
88✔
170
}
171

172
int Main(
96✔
173
        const vector<string> &args,
174
        function<void(mender::update::context::MenderContext &ctx)> test_hook) {
175
        auto err = DoMain(args, test_hook);
192✔
176

177
        if (err.code == context::MakeError(context::NoUpdateInProgressError, "").code) {
96✔
178
                return NoUpdateInProgressExitStatus;
2✔
179
        } else if (err.code == context::MakeError(context::RebootRequiredError, "").code) {
94✔
180
                return RebootExitStatus;
1✔
181
        } else if (err != error::NoError) {
93✔
182
                if (err.code == error::MakeError(error::ExitWithSuccessError, "").code) {
26✔
183
                        return 0;
×
184
                } else if (err.code != error::MakeError(error::ExitWithFailureError, "").code) {
26✔
185
                        cerr << "Could not fulfill request: " + err.String() << endl;
20✔
186
                }
187
                return 1;
26✔
188
        }
189

190
        return 0;
67✔
191
}
192

193
} // namespace cli
194
} // namespace update
195
} // 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