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