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