1 #include <tests/lib/test.h>
2
3 #include <tests/lib/glib-helpers/test-conn-helper.h>
4
5 #include <tests/lib/glib/echo/chan.h>
6 #include <tests/lib/glib/echo/conn.h>
7 #include <tests/lib/glib/future/conference/chan.h>
8
9 #include <TelepathyQt/Connection>
10 #include <TelepathyQt/PendingReady>
11
12 #include <telepathy-glib/debug.h>
13
14 using namespace Tp;
15
16 class TestConferenceChan : public Test
17 {
18 Q_OBJECT
19
20 public:
TestConferenceChan(QObject * parent=0)21 TestConferenceChan(QObject *parent = 0)
22 : Test(parent),
23 mConn(0), mContactRepo(0),
24 mTextChan1Service(0), mTextChan2Service(0), mConferenceChanService(0)
25 { }
26
27 protected Q_SLOTS:
28 void onConferenceChannelMerged(const Tp::ChannelPtr &);
29 void onConferenceChannelRemoved(const Tp::ChannelPtr &channel,
30 const Tp::Channel::GroupMemberChangeDetails &details);
31
32 private Q_SLOTS:
33 void initTestCase();
34 void init();
35
36 void testConference();
37
38 void cleanup();
39 void cleanupTestCase();
40
41 private:
42 TestConnHelper *mConn;
43 TpHandleRepoIface *mContactRepo;
44
45 ChannelPtr mChan;
46 QString mTextChan1Path;
47 ExampleEchoChannel *mTextChan1Service;
48 QString mTextChan2Path;
49 ExampleEchoChannel *mTextChan2Service;
50 QString mTextChan3Path;
51 ExampleEchoChannel *mTextChan3Service;
52 QString mConferenceChanPath;
53 TpTestsConferenceChannel *mConferenceChanService;
54
55 ChannelPtr mChannelMerged;
56 ChannelPtr mChannelRemovedDetailed;
57 Channel::GroupMemberChangeDetails mChannelRemovedDetailedDetails;
58 };
59
onConferenceChannelMerged(const Tp::ChannelPtr & channel)60 void TestConferenceChan::onConferenceChannelMerged(const Tp::ChannelPtr &channel)
61 {
62 mChannelMerged = channel;
63 mLoop->exit(0);
64 }
65
onConferenceChannelRemoved(const Tp::ChannelPtr & channel,const Tp::Channel::GroupMemberChangeDetails & details)66 void TestConferenceChan::onConferenceChannelRemoved(const Tp::ChannelPtr &channel,
67 const Tp::Channel::GroupMemberChangeDetails &details)
68 {
69 mChannelRemovedDetailed = channel;
70 mChannelRemovedDetailedDetails = details;
71 mLoop->exit(0);
72 }
73
initTestCase()74 void TestConferenceChan::initTestCase()
75 {
76 initTestCaseImpl();
77
78 g_type_init();
79 g_set_prgname("chan-conference");
80 tp_debug_set_flags("all");
81 dbus_g_bus_get(DBUS_BUS_STARTER, 0);
82
83 mConn = new TestConnHelper(this,
84 EXAMPLE_TYPE_ECHO_CONNECTION,
85 "account", "me@example.com",
86 "protocol", "example",
87 NULL);
88 QCOMPARE(mConn->connect(), true);
89
90 // create a Channel by magic, rather than doing D-Bus round-trips for it
91 mContactRepo = tp_base_connection_get_handles(TP_BASE_CONNECTION(mConn->service()),
92 TP_HANDLE_TYPE_CONTACT);
93 guint handle1 = tp_handle_ensure(mContactRepo, "someone1@localhost", 0, 0);
94 guint handle2 = tp_handle_ensure(mContactRepo, "someone2@localhost", 0, 0);
95 guint handle3 = tp_handle_ensure(mContactRepo, "someone3@localhost", 0, 0);
96
97 QByteArray chanPath;
98 GPtrArray *initialChannels = g_ptr_array_new();
99
100 mTextChan1Path = mConn->objectPath() + QLatin1String("/TextChannel/1");
101 chanPath = mTextChan1Path.toLatin1();
102 mTextChan1Service = EXAMPLE_ECHO_CHANNEL(g_object_new(
103 EXAMPLE_TYPE_ECHO_CHANNEL,
104 "connection", mConn->service(),
105 "object-path", chanPath.data(),
106 "handle", handle1,
107 NULL));
108 g_ptr_array_add(initialChannels, g_strdup(chanPath.data()));
109
110 mTextChan2Path = mConn->objectPath() + QLatin1String("/TextChannel/2");
111 chanPath = mTextChan2Path.toLatin1();
112 mTextChan2Service = EXAMPLE_ECHO_CHANNEL(g_object_new(
113 EXAMPLE_TYPE_ECHO_CHANNEL,
114 "connection", mConn->service(),
115 "object-path", chanPath.data(),
116 "handle", handle2,
117 NULL));
118 g_ptr_array_add(initialChannels, g_strdup(chanPath.data()));
119
120 // let's not add this one to initial channels
121 mTextChan3Path = mConn->objectPath() + QLatin1String("/TextChannel/3");
122 chanPath = mTextChan3Path.toLatin1();
123 mTextChan3Service = EXAMPLE_ECHO_CHANNEL(g_object_new(
124 EXAMPLE_TYPE_ECHO_CHANNEL,
125 "connection", mConn->service(),
126 "object-path", chanPath.data(),
127 "handle", handle3,
128 NULL));
129
130 mConferenceChanPath = mConn->objectPath() + QLatin1String("/ConferenceChannel");
131 chanPath = mConferenceChanPath.toLatin1();
132 mConferenceChanService = TP_TESTS_CONFERENCE_CHANNEL(g_object_new(
133 TP_TESTS_TYPE_CONFERENCE_CHANNEL,
134 "connection", mConn->service(),
135 "object-path", chanPath.data(),
136 "initial-channels", initialChannels,
137 NULL));
138
139 g_ptr_array_foreach(initialChannels, (GFunc) g_free, NULL);
140 g_ptr_array_free(initialChannels, TRUE);
141 }
142
init()143 void TestConferenceChan::init()
144 {
145 initImpl();
146 }
147
testConference()148 void TestConferenceChan::testConference()
149 {
150 mChan = Channel::create(mConn->client(), mConferenceChanPath, QVariantMap());
151 QCOMPARE(mChan->isConference(), false);
152 QVERIFY(mChan->conferenceInitialInviteeContacts().isEmpty());
153 QVERIFY(mChan->conferenceChannels().isEmpty());
154 QVERIFY(mChan->conferenceInitialChannels().isEmpty());
155 QVERIFY(mChan->conferenceOriginalChannels().isEmpty());
156 QCOMPARE(mChan->supportsConferenceMerging(), false);
157 QCOMPARE(mChan->supportsConferenceSplitting(), false);
158
159 QVERIFY(connect(mChan->becomeReady(),
160 SIGNAL(finished(Tp::PendingOperation*)),
161 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
162 QCOMPARE(mLoop->exec(), 0);
163 QCOMPARE(mChan->isReady(), true);
164
165 QSet<QString> expectedObjectPaths;
166 expectedObjectPaths << mTextChan1Path << mTextChan2Path;
167
168 QSet<QString> objectPaths;
169 Q_FOREACH (const ChannelPtr &channel, mChan->conferenceInitialChannels()) {
170 objectPaths << channel->objectPath();
171 }
172 QCOMPARE(expectedObjectPaths, objectPaths);
173
174 objectPaths.clear();
175 Q_FOREACH (const ChannelPtr &channel, mChan->conferenceChannels()) {
176 objectPaths << channel->objectPath();
177 }
178 QCOMPARE(expectedObjectPaths, objectPaths);
179
180 /*
181 // TODO - Properly check for initial invitee contacts if/when a test CM supports it
182 QVERIFY(!mChan->isReady(Channel::FeatureConferenceInitialInviteeContacts));
183 QCOMPARE(mChan->conferenceInitialInviteeContacts(), Contacts());
184
185 QVERIFY(connect(mChan->becomeReady(Channel::FeatureConferenceInitialInviteeContacts),
186 SIGNAL(finished(Tp::PendingOperation*)),
187 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
188 QCOMPARE(mLoop->exec(), 0);
189 QCOMPARE(mChan->isReady(Channel::FeatureConferenceInitialInviteeContacts), true);
190
191 QCOMPARE(mChan->conferenceInitialInviteeContacts(), Contacts());
192 */
193
194 QCOMPARE(mChan->supportsConferenceMerging(), true);
195 QCOMPARE(mChan->supportsConferenceSplitting(), false);
196 QVERIFY(connect(mChan->conferenceSplitChannel(),
197 SIGNAL(finished(Tp::PendingOperation*)),
198 SLOT(expectFailure(Tp::PendingOperation*))));
199 QCOMPARE(mLoop->exec(), 0);
200 QCOMPARE(mLastError, TP_QT_ERROR_NOT_IMPLEMENTED);
201 QVERIFY(!mLastErrorMessage.isEmpty());
202
203 ChannelPtr otherChannel = Channel::create(mConn->client(), mTextChan3Path, QVariantMap());
204
205 QVERIFY(connect(mChan.data(),
206 SIGNAL(conferenceChannelMerged(const Tp::ChannelPtr &)),
207 SLOT(onConferenceChannelMerged(const Tp::ChannelPtr &))));
208 QVERIFY(connect(mChan->conferenceMergeChannel(otherChannel),
209 SIGNAL(finished(Tp::PendingOperation*)),
210 SLOT(expectSuccessfulCall(Tp::PendingOperation*))));
211 QCOMPARE(mLoop->exec(), 0);
212 QCOMPARE(mChan->isReady(), true);
213 while (!mChannelMerged) {
214 QCOMPARE(mLoop->exec(), 0);
215 }
216
217 QCOMPARE(mChannelMerged->objectPath(), otherChannel->objectPath());
218
219 expectedObjectPaths << mTextChan3Path;
220 objectPaths.clear();
221 Q_FOREACH (const ChannelPtr &channel, mChan->conferenceChannels()) {
222 objectPaths << channel->objectPath();
223 }
224 QCOMPARE(expectedObjectPaths, objectPaths);
225
226 QVERIFY(connect(mChan.data(),
227 SIGNAL(conferenceChannelRemoved(const Tp::ChannelPtr &,
228 const Tp::Channel::GroupMemberChangeDetails &)),
229 SLOT(onConferenceChannelRemoved(const Tp::ChannelPtr &,
230 const Tp::Channel::GroupMemberChangeDetails &))));
231 tp_tests_conference_channel_remove_channel (mConferenceChanService,
232 mChannelMerged->objectPath().toLatin1().data());
233 while (!mChannelRemovedDetailed) {
234 QCOMPARE(mLoop->exec(), 0);
235 }
236 QCOMPARE(mChannelRemovedDetailed, mChannelMerged);
237 QCOMPARE(mChannelRemovedDetailedDetails.allDetails().isEmpty(), false);
238 QCOMPARE(qdbus_cast<int>(mChannelRemovedDetailedDetails.allDetails().value(
239 QLatin1String("domain-specific-detail-uint"))), 3);
240 QCOMPARE(mChannelRemovedDetailedDetails.hasActor(), true);
241 QCOMPARE(mChannelRemovedDetailedDetails.actor(), mChan->groupSelfContact());
242
243 expectedObjectPaths.clear();
244 expectedObjectPaths << mTextChan1Path << mTextChan2Path;
245 objectPaths.clear();
246 Q_FOREACH (const ChannelPtr &channel, mChan->conferenceChannels()) {
247 objectPaths << channel->objectPath();
248 }
249 QCOMPARE(expectedObjectPaths, objectPaths);
250
251 mChan.reset();
252 mChannelMerged.reset();
253 }
254
cleanup()255 void TestConferenceChan::cleanup()
256 {
257 cleanupImpl();
258 }
259
cleanupTestCase()260 void TestConferenceChan::cleanupTestCase()
261 {
262 QCOMPARE(mConn->disconnect(), true);
263 delete mConn;
264
265 if (mTextChan1Service != 0) {
266 g_object_unref(mTextChan1Service);
267 mTextChan1Service = 0;
268 }
269
270 if (mTextChan2Service != 0) {
271 g_object_unref(mTextChan2Service);
272 mTextChan2Service = 0;
273 }
274
275 if (mConferenceChanService != 0) {
276 g_object_unref(mConferenceChanService);
277 mConferenceChanService = 0;
278 }
279
280 cleanupTestCaseImpl();
281 }
282
283 QTEST_MAIN(TestConferenceChan)
284 #include "_gen/chan-conference.cpp.moc.hpp"
285