1 //
2 // Copyright (C) 2012 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "shill/cellular/modem_manager.h"
18
19 #include <base/stl_util.h>
20 #include <ModemManager/ModemManager.h>
21
22 #include "shill/cellular/mock_dbus_objectmanager_proxy.h"
23 #include "shill/cellular/mock_modem.h"
24 #include "shill/cellular/mock_modem_info.h"
25 #include "shill/cellular/mock_modem_manager_proxy.h"
26 #include "shill/manager.h"
27 #include "shill/mock_control.h"
28 #include "shill/mock_manager.h"
29 #include "shill/test_event_dispatcher.h"
30 #include "shill/testing.h"
31
32 using std::string;
33 using std::shared_ptr;
34 using std::vector;
35 using testing::_;
36 using testing::Invoke;
37 using testing::Pointee;
38 using testing::Return;
39 using testing::SaveArg;
40 using testing::StrEq;
41 using testing::Test;
42
43 namespace shill {
44
45 class ModemManagerTest : public Test {
46 public:
ModemManagerTest()47 ModemManagerTest()
48 : manager_(&control_, &dispatcher_, nullptr),
49 modem_info_(&control_, &dispatcher_, nullptr, &manager_) {}
50
SetUp()51 virtual void SetUp() {
52 modem_.reset(
53 new StrictModem(kService, kModemPath, &modem_info_, &control_));
54 }
55
56 protected:
57 static const char kService[];
58 static const char kPath[];
59 static const char kModemPath[];
60
61 shared_ptr<StrictModem> modem_;
62
63 EventDispatcherForTest dispatcher_;
64 MockControl control_;
65 MockManager manager_;
66 MockModemInfo modem_info_;
67 };
68
69 const char ModemManagerTest::kService[] = "org.chromium.ModemManager";
70 const char ModemManagerTest::kPath[] = "/org/chromium/ModemManager";
71 const char ModemManagerTest::kModemPath[] = "/org/blah/Modem/blah/0";
72
73 class ModemManagerForTest : public ModemManager {
74 public:
ModemManagerForTest(ControlInterface * control_interface,const string & service,const string & path,ModemInfo * modem_info)75 ModemManagerForTest(ControlInterface* control_interface,
76 const string& service,
77 const string& path,
78 ModemInfo* modem_info)
79 : ModemManager(control_interface, service, path, modem_info) {}
80
81 MOCK_METHOD0(Start, void());
82 MOCK_METHOD0(Stop, void());
83 };
84
85 class ModemManagerCoreTest : public ModemManagerTest {
86 public:
ModemManagerCoreTest()87 ModemManagerCoreTest()
88 : ModemManagerTest(),
89 modem_manager_(&control_, kService, kPath, &modem_info_) {}
90
91 protected:
92 ModemManagerForTest modem_manager_;
93 };
94
TEST_F(ModemManagerCoreTest,ConnectDisconnect)95 TEST_F(ModemManagerCoreTest, ConnectDisconnect) {
96 EXPECT_FALSE(modem_manager_.service_connected_);
97 modem_manager_.Connect();
98 EXPECT_TRUE(modem_manager_.service_connected_);
99
100 modem_manager_.RecordAddedModem(modem_);
101 EXPECT_EQ(1, modem_manager_.modems_.size());
102
103 modem_manager_.ModemManager::Disconnect();
104 EXPECT_EQ(0, modem_manager_.modems_.size());
105 EXPECT_FALSE(modem_manager_.service_connected_);
106 }
107
TEST_F(ModemManagerCoreTest,AddRemoveModem)108 TEST_F(ModemManagerCoreTest, AddRemoveModem) {
109 modem_manager_.Connect();
110 EXPECT_FALSE(modem_manager_.ModemExists(kModemPath));
111
112 // Remove non-existent modem path.
113 modem_manager_.RemoveModem(kModemPath);
114 EXPECT_FALSE(modem_manager_.ModemExists(kModemPath));
115
116 modem_manager_.RecordAddedModem(modem_);
117 EXPECT_TRUE(modem_manager_.ModemExists(kModemPath));
118
119 // Add an already added modem.
120 modem_manager_.RecordAddedModem(modem_);
121 EXPECT_TRUE(modem_manager_.ModemExists(kModemPath));
122
123 modem_manager_.RemoveModem(kModemPath);
124 EXPECT_FALSE(modem_manager_.ModemExists(kModemPath));
125
126 // Remove an already removed modem path.
127 modem_manager_.RemoveModem(kModemPath);
128 EXPECT_FALSE(modem_manager_.ModemExists(kModemPath));
129 }
130
131 class ModemManagerClassicMockInit : public ModemManagerClassic {
132 public:
ModemManagerClassicMockInit(ControlInterface * control_interface,const string & service,const string & path,ModemInfo * modem_info_)133 ModemManagerClassicMockInit(ControlInterface* control_interface,
134 const string& service,
135 const string& path,
136 ModemInfo* modem_info_) :
137 ModemManagerClassic(control_interface, service, path, modem_info_) {}
138
139 MOCK_METHOD1(InitModemClassic, void(shared_ptr<ModemClassic>));
140 };
141
142 class ModemManagerClassicTest : public ModemManagerTest {
143 public:
ModemManagerClassicTest()144 ModemManagerClassicTest()
145 : ModemManagerTest(),
146 modem_manager_(&control_, kService, kPath, &modem_info_),
147 proxy_(new MockModemManagerProxy()) {}
148
149 protected:
150 ModemManagerClassicMockInit modem_manager_;
151 MockModemManagerProxy* proxy_;
152 };
153
TEST_F(ModemManagerClassicTest,StartStop)154 TEST_F(ModemManagerClassicTest, StartStop) {
155 EXPECT_EQ(nullptr, modem_manager_.proxy_.get());
156
157 EXPECT_CALL(control_, CreateModemManagerProxy(_, kPath, kService, _, _))
158 .WillOnce(Return(proxy_));
159 modem_manager_.Start();
160 EXPECT_NE(nullptr, modem_manager_.proxy_.get());
161
162 modem_manager_.Stop();
163 EXPECT_EQ(nullptr, modem_manager_.proxy_.get());
164 }
165
TEST_F(ModemManagerClassicTest,Connect)166 TEST_F(ModemManagerClassicTest, Connect) {
167 // Setup proxy.
168 modem_manager_.proxy_.reset(proxy_);
169
170 EXPECT_CALL(*proxy_, EnumerateDevices())
171 .WillOnce(Return(vector<string>(1, kModemPath)));
172 EXPECT_CALL(modem_manager_,
173 InitModemClassic(
174 Pointee(Field(&Modem::path_, StrEq(kModemPath)))));
175 modem_manager_.Connect();
176 EXPECT_EQ(1, modem_manager_.modems_.size());
177 ASSERT_TRUE(ContainsKey(modem_manager_.modems_, kModemPath));
178 }
179
180 class ModemManager1MockInit : public ModemManager1 {
181 public:
ModemManager1MockInit(ControlInterface * control_interface,const string & service,const string & path,ModemInfo * modem_info_)182 ModemManager1MockInit(ControlInterface* control_interface,
183 const string& service,
184 const string& path,
185 ModemInfo* modem_info_) :
186 ModemManager1(control_interface, service, path, modem_info_) {}
187 MOCK_METHOD2(InitModem1, void(shared_ptr<Modem1>,
188 const InterfaceToProperties&));
189 };
190
191
192 class ModemManager1Test : public ModemManagerTest {
193 public:
ModemManager1Test()194 ModemManager1Test()
195 : ModemManagerTest(),
196 modem_manager_(&control_, kService, kPath, &modem_info_),
197 proxy_(new MockDBusObjectManagerProxy()) {}
198
199 protected:
SetUp()200 virtual void SetUp() {
201 proxy_->IgnoreSetCallbacks();
202 }
203
Connect(const ObjectsWithProperties & expected_objects)204 void Connect(const ObjectsWithProperties& expected_objects) {
205 ManagedObjectsCallback get_managed_objects_callback;
206 EXPECT_CALL(*proxy_, GetManagedObjects(_, _, _))
207 .WillOnce(SaveArg<1>(&get_managed_objects_callback));
208 modem_manager_.Connect();
209 get_managed_objects_callback.Run(expected_objects, Error());
210 }
211
GetModemWithProperties()212 static ObjectsWithProperties GetModemWithProperties() {
213 KeyValueStore o_fd_mm1_modem;
214
215 InterfaceToProperties properties;
216 properties[MM_DBUS_INTERFACE_MODEM] = o_fd_mm1_modem;
217
218 ObjectsWithProperties objects_with_properties;
219 objects_with_properties[kModemPath] = properties;
220
221 return objects_with_properties;
222 }
223
224 ModemManager1MockInit modem_manager_;
225 MockDBusObjectManagerProxy* proxy_;
226 MockControl control_;
227 };
228
TEST_F(ModemManager1Test,StartStop)229 TEST_F(ModemManager1Test, StartStop) {
230 EXPECT_EQ(nullptr, modem_manager_.proxy_.get());
231
232 EXPECT_CALL(control_, CreateDBusObjectManagerProxy(kPath, kService, _, _))
233 .WillOnce(Return(proxy_));
234 EXPECT_CALL(*proxy_, set_interfaces_added_callback(_));
235 EXPECT_CALL(*proxy_, set_interfaces_removed_callback(_));
236 modem_manager_.Start();
237 EXPECT_NE(nullptr, modem_manager_.proxy_.get());
238
239 modem_manager_.Stop();
240 EXPECT_EQ(nullptr, modem_manager_.proxy_.get());
241 }
242
TEST_F(ModemManager1Test,Connect)243 TEST_F(ModemManager1Test, Connect) {
244 // Setup proxy.
245 modem_manager_.proxy_.reset(proxy_);
246
247 Connect(GetModemWithProperties());
248 EXPECT_EQ(1, modem_manager_.modems_.size());
249 EXPECT_TRUE(ContainsKey(modem_manager_.modems_, kModemPath));
250 }
251
TEST_F(ModemManager1Test,AddRemoveInterfaces)252 TEST_F(ModemManager1Test, AddRemoveInterfaces) {
253 // Setup proxy.
254 modem_manager_.proxy_.reset(proxy_);
255
256 // Have nothing come back from GetManagedObjects
257 Connect(ObjectsWithProperties());
258 EXPECT_EQ(0, modem_manager_.modems_.size());
259
260 // Add an object that doesn't have a modem interface. Nothing should be added
261 EXPECT_CALL(modem_manager_, InitModem1(_, _)).Times(0);
262 modem_manager_.OnInterfacesAddedSignal(kModemPath,
263 InterfaceToProperties());
264 EXPECT_EQ(0, modem_manager_.modems_.size());
265
266 // Actually add a modem
267 EXPECT_CALL(modem_manager_, InitModem1(_, _)).Times(1);
268 modem_manager_.OnInterfacesAddedSignal(kModemPath,
269 GetModemWithProperties()[kModemPath]);
270 EXPECT_EQ(1, modem_manager_.modems_.size());
271
272 // Remove an irrelevant interface
273 vector<string> not_including_modem_interface;
274 not_including_modem_interface.push_back("not.a.modem.interface");
275 modem_manager_.OnInterfacesRemovedSignal(kModemPath,
276 not_including_modem_interface);
277 EXPECT_EQ(1, modem_manager_.modems_.size());
278
279 // Remove the modem
280 vector<string> with_modem_interface;
281 with_modem_interface.push_back(MM_DBUS_INTERFACE_MODEM);
282 modem_manager_.OnInterfacesRemovedSignal(kModemPath, with_modem_interface);
283 EXPECT_EQ(0, modem_manager_.modems_.size());
284 }
285
286 } // namespace shill
287