2
* Copyright © 2012-2013 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License version 3,
6
* as published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful,
9
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
* GNU Lesser General Public License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Authored by: Thomas Voß <thomas.voss@canonical.com>
19
#include <com/ubuntu/location/service/ichnaea_reporter.h>
21
#include "web_server.h"
23
#include <core/posix/fork.h>
24
#include <core/posix/signal.h>
25
#include <core/posix/wait.h>
26
#include <core/testing/cross_process_sync.h>
27
#include <core/testing/fork_and_run.h>
29
#include <json/json.h>
31
#include <gtest/gtest.h>
32
#include <gmock/gmock.h>
34
#include <condition_variable>
36
namespace json = Json;
37
namespace location = com::ubuntu::location;
41
struct MockWirelessNetwork : public location::connectivity::WirelessNetwork
43
/** @brief Timestamp when the network became visible. */
44
MOCK_CONST_METHOD0(last_seen, const core::Property<std::chrono::system_clock::time_point>&());
46
/** @brief Returns the BSSID of the network */
47
MOCK_CONST_METHOD0(bssid, const core::Property<std::string>&());
49
/** @brief Returns the SSID of the network. */
50
MOCK_CONST_METHOD0(ssid, const core::Property<std::string>&());
52
/** @brief Returns the mode of the network. */
53
MOCK_CONST_METHOD0(mode, const core::Property<Mode>&());
55
/** @brief Returns the frequency that the network/AP operates upon. */
56
MOCK_CONST_METHOD0(frequency, const core::Property<Frequency>&());
58
/** @brief Returns the signal quality of the network/AP in percent. */
59
MOCK_CONST_METHOD0(signal_strength, const core::Property<SignalStrength>&());
62
struct MockRadioCell : public location::connectivity::RadioCell
64
typedef std::shared_ptr<MockRadioCell> Ptr;
66
/** @brief Returns the type of the radio cell. */
67
MOCK_CONST_METHOD0(changed, const core::Signal<>&());
69
/** @brief Returns the type of the radio cell. */
70
MOCK_CONST_METHOD0(type, Type());
72
/** @brief Returns GSM-specific details or throws std::runtime_error if this is not a GSM radiocell. */
73
MOCK_CONST_METHOD0(gsm, const Gsm&());
75
/** @brief Returns UMTS-specific details or throws std::runtime_error if this is not a UMTS radiocell. */
76
MOCK_CONST_METHOD0(umts, const Umts&());
78
/** @brief Returns LTE-specific details or throws std::runtime_error if this is not an LTE radiocell. */
79
MOCK_CONST_METHOD0(lte, const Lte&());
82
location::Update<location::Position> reference_position_update
85
location::wgs84::Latitude{9. * location::units::Degrees},
86
location::wgs84::Longitude{53. * location::units::Degrees},
87
location::wgs84::Altitude{-2. * location::units::Meters}
89
location::Clock::now()
94
TEST(IchnaeaReporter, issues_correct_posts_requests)
96
using namespace ::testing;
98
static const location::connectivity::RadioCell::Gsm gsm
100
location::connectivity::RadioCell::Gsm::MCC{42},
101
location::connectivity::RadioCell::Gsm::MNC{42},
102
location::connectivity::RadioCell::Gsm::LAC{42},
103
location::connectivity::RadioCell::Gsm::ID{42},
104
location::connectivity::RadioCell::Gsm::SignalStrength{21}
107
static const MockRadioCell::Ptr ref_cell
109
new NiceMock<MockRadioCell>()
112
ON_CALL(*ref_cell, type()).WillByDefault(Return(location::connectivity::RadioCell::Type::gsm));
113
ON_CALL(*ref_cell, gsm()).WillByDefault(ReturnRef(gsm));
115
static const core::Property<std::chrono::system_clock::time_point> ref_timestamp
117
std::chrono::system_clock::now()
120
static const core::Property<std::string> ref_bssid
125
static const core::Property<std::string> ref_ssid
130
static const core::Property<location::connectivity::WirelessNetwork::Mode> ref_mode
132
location::connectivity::WirelessNetwork::Mode::infrastructure
135
static const core::Property<location::connectivity::WirelessNetwork::Frequency> ref_frequency
137
location::connectivity::WirelessNetwork::Frequency{4242}
140
static const core::Property<location::connectivity::WirelessNetwork::SignalStrength> ref_strength
142
location::connectivity::WirelessNetwork::SignalStrength{80}
145
static const std::string api_key
150
static const std::string nick_name
155
core::testing::CrossProcessSync cps; // server - ready -> client
157
testing::web::server::Configuration web_server_configuration
160
[](mg_connection* conn)
162
core::net::http::Header header;
164
for (int i = 0; i < conn->num_headers; i++)
166
header.add(conn->http_headers[i].name, conn->http_headers[i].value);
169
EXPECT_TRUE(header.has(location::service::ichnaea::Reporter::nick_name_header));
170
EXPECT_STREQ("/v1/submit", conn->uri);
171
EXPECT_STREQ("POST", conn->request_method);
172
EXPECT_EQ("key=" + api_key, conn->query_string);
173
EXPECT_NE(nullptr, conn->content);
174
EXPECT_GT(conn->content_len, 0);
176
using namespace location::service::ichnaea;
181
EXPECT_TRUE(reader.parse(conn->content, result));
183
auto items = result[Reporter::Json::items];
184
EXPECT_EQ(1u, items.size());
186
auto item = items[0];
187
EXPECT_EQ("gsm", item[Reporter::Json::radio].asString());
190
reference_position_update.value.latitude.value.value(),
191
item[Reporter::Json::lat].asDouble());
193
reference_position_update.value.longitude.value.value(),
194
item[Reporter::Json::lon].asDouble());
196
auto wifis = item[Reporter::Json::wifi];
197
EXPECT_EQ(1u, wifis.size());
199
auto wifi = wifis[0];
200
EXPECT_EQ(ref_bssid.get(), wifi[Reporter::Json::Wifi::key].asString());
201
EXPECT_EQ(ref_frequency->get(), wifi[Reporter::Json::Wifi::frequency].asInt());
203
auto cells = item[Reporter::Json::cell];
204
EXPECT_EQ(1u, cells.size());
206
auto cell = cells[0];
207
EXPECT_EQ(ref_cell->gsm().mobile_country_code.get(), cell[Reporter::Json::Cell::mcc].asInt());
208
EXPECT_EQ(ref_cell->gsm().mobile_network_code.get(), cell[Reporter::Json::Cell::mnc].asInt());
209
EXPECT_EQ(ref_cell->gsm().location_area_code.get(), cell[Reporter::Json::Cell::lac].asInt());
210
EXPECT_EQ(ref_cell->gsm().id.get(), cell[Reporter::Json::Cell::cid].asInt());
211
EXPECT_EQ(ref_cell->gsm().strength.get(), cell[Reporter::Json::Cell::asu].asInt());
213
mg_send_status(conn, static_cast<int>(submit::success));
218
core::posix::ChildProcess server = core::posix::fork(
219
std::bind(testing::a_web_server(web_server_configuration), cps),
220
core::posix::StandardStream::empty);
222
using namespace ::testing;
224
auto wireless_network = std::make_shared<NiceMock<MockWirelessNetwork> >();
225
ON_CALL(*wireless_network, last_seen()).WillByDefault(ReturnRef(ref_timestamp));
226
ON_CALL(*wireless_network, bssid()).WillByDefault(ReturnRef(ref_bssid));
227
ON_CALL(*wireless_network, ssid()).WillByDefault(ReturnRef(ref_ssid));
228
ON_CALL(*wireless_network, mode()).WillByDefault(ReturnRef(ref_mode));
229
ON_CALL(*wireless_network, frequency()).WillByDefault(ReturnRef(ref_frequency));
230
ON_CALL(*wireless_network, signal_strength()).WillByDefault(ReturnRef(ref_strength));
232
location::service::ichnaea::Reporter::Configuration config
234
"http://127.0.0.1:5000",
239
location::service::ichnaea::Reporter reporter{config};
242
reporter.report(reference_position_update, {wireless_network}, {ref_cell});
244
cps.wait_for_signal_ready_for(std::chrono::seconds{2});
246
server.send_signal_or_throw(core::posix::Signal::sig_term);
247
auto result = server.wait_for(core::posix::wait::Flags::untraced);
249
EXPECT_EQ(core::posix::wait::Result::Status::exited, result.status);
250
EXPECT_EQ(core::posix::exit::Status::success, result.detail.if_exited.status);