Basic functionality on desktop server build. Started a test for GetServices
authorJames Aley <jamesa@symbian.org>
Mon, 07 Jun 2010 11:43:45 +0100
changeset 13 b5d63d5fc252
parent 12 5bed45b14781
child 14 a469c0e6e7fb
Basic functionality on desktop server build. Started a test for GetServices
.hgignore
smf/smfservermodule/smfclient/client/smfclient_p.cpp
smf/smfservermodule/smfclient/client/smfclientqt.cpp
smf/smfservermodule/smfclient/client/smfclientqt.h
smf/smfservermodule/smfserver/main.cpp
smf/smfservermodule/smfserver/server/server.pri
smf/smfservermodule/smfserver/server/smfserver.cpp
smf/smfservermodule/smfserver/server/smfserver.h
smf/smfservermodule/smfserver/server/smfserverqt.cpp
smf/smfservermodule/smfserver/server/smfserverqt_p.h
smf/smfservermodule/smfserver/server/smfserverqtsession.cpp
smf/smfservermodule/smfserver/server/smfserverqtsession.h
smf/smfservermodule/smfserver/smfserver.pro
smf/smfservermodule/smfservermodule.pro
smf/smfservermodule/tests/tests.pro
smf/smfservermodule/tests/testsmfgetservices/testsmfgetservices.cpp
smf/smfservermodule/tests/testsmfgetservices/testsmfgetservices.pro
--- a/.hgignore	Fri May 21 16:50:44 2010 +0100
+++ b/.hgignore	Mon Jun 07 11:43:45 2010 +0100
@@ -1,6 +1,8 @@
 syntax: regexp
 ^.*~$
+^.*\.user$
 ^.*\.o$
 ^.*moc_.*$
+^.*\.moc$
 ^.*Makefile.*$
-^bin/.*$
\ No newline at end of file
+^bin/.*$
--- a/smf/smfservermodule/smfclient/client/smfclient_p.cpp	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfclient/client/smfclient_p.cpp	Mon Jun 07 11:43:45 2010 +0100
@@ -21,6 +21,8 @@
 	//private impl for symbian
 	#ifdef Q_OS_SYMBIAN
 	m_SmfClientPrivate = CSmfClientSymbian::NewL(this);
+        #else
+        m_SmfClientPrivate = new SmfClientQt(this);
 	#endif
 
 	}
--- a/smf/smfservermodule/smfclient/client/smfclientqt.cpp	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfclient/client/smfclientqt.cpp	Mon Jun 07 11:43:45 2010 +0100
@@ -15,9 +15,23 @@
 
 #include "smfclientqt.h"
 
-SmfClientQt::SmfClientQt(QObject *parent) :
-    QObject(parent)
+SmfClientQt::SmfClientQt(QObject *parent)
+    : QObject(parent)
 {
+    m_serverConnection = new QLocalSocket();
+
+    connect(m_serverConnection, SIGNAL(connected()), this, SLOT(connectionEstablished()));
+    connect(m_serverConnection, SIGNAL(readyRead()), this, SLOT(readIncomingData()));
+    connect(m_serverConnection, SIGNAL(error(QLocalSocket::LocalSocketError)),
+            this, SLOT(handleError(QLocalSocket::LocalSocketError)));
+
+    m_serverConnection->connectToServer("SmfServerQt", QIODevice::ReadWrite);
+}
+
+SmfClientQt::~SmfClientQt()
+{
+    m_serverConnection->close();
+    delete m_serverConnection;
 }
 
 /**
@@ -26,20 +40,33 @@
  * @param aInterfaceName Interface name
  * @param requestType Opcode
  */
-int SmfClientQt::sendRequest(QByteArray& aSerializedData, QString aInterfaceName,
+int SmfClientQt::sendRequest(QByteArray& serializedData, QString interfaceName,
                              SmfRequestTypeID requestType)
 {
-
+    QDataStream out(m_serverConnection);
+    out << requestType;
+    out << interfaceName;
+    out << serializedData.size();
+    out << serializedData;
 }
 
 /**
  * This overloaded API is for ESmfGetServices, where data should be
  * fetched synchronously
  */
-QByteArray SmfClientQt::sendRequest(QString aInterfaceName,
+QByteArray SmfClientQt::sendRequest(QString interfaceName,
             SmfRequestTypeID requestType)
 {
+    QDataStream out(m_serverConnection);
+    out << requestType;
+    out << interfaceName;
 
+    // TODO: This needs to be asynchronous. Remove this wait when user API is updated.
+    m_serverConnection->waitForBytesWritten(-1);
+
+    QByteArray in;
+    out >> in;
+    return in;
 }
 
 /**
@@ -48,7 +75,9 @@
 int SmfClientQt::sendDummyRequest(QByteArray* provider,QString aInterfaceName,
             SmfRequestTypeID requestType)
 {
-
+    Q_UNUSED(provider);
+    Q_UNUSED(aInterfaceName);
+    Q_UNUSED(requestType);
 }
 
 /**
@@ -59,3 +88,25 @@
 {
 
 }
+
+void SmfClientQt::connectionEstablished()
+{
+    qDebug() << "Connected to server successfully.";
+}
+
+void SmfClientQt::readIncomingData()
+{
+}
+
+void SmfClientQt::handleError(QLocalSocket::LocalSocketError error)
+{
+    switch(error)
+    {
+    case QLocalSocket::ServerNotFoundError:
+        qDebug() << "Server not found.";
+        break;
+    default:
+        qDebug() << "Unhandled socket error";
+        break;
+    }
+}
--- a/smf/smfservermodule/smfclient/client/smfclientqt.h	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfclient/client/smfclientqt.h	Mon Jun 07 11:43:45 2010 +0100
@@ -19,6 +19,8 @@
 #include <QObject>
 #include <QByteArray>
 #include <QString>
+#include <QLocalSocket>
+
 #include "smfglobal.h"
 
 class SmfClientQt : public QObject
@@ -27,6 +29,7 @@
 
 public:
     explicit SmfClientQt(QObject *parent = 0);
+    ~SmfClientQt();
 
 public:
     /**
@@ -58,11 +61,13 @@
     */
     void CancelRequest();
 
-
-signals:
+private slots:
+    void connectionEstablished();
+    void readIncomingData();
+    void handleError(QLocalSocket::LocalSocketError error);
 
-public slots:
-
+private:
+    QLocalSocket *m_serverConnection;
 };
 
 #endif // SMFCLIENTQT_H
--- a/smf/smfservermodule/smfserver/main.cpp	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfserver/main.cpp	Mon Jun 07 11:43:45 2010 +0100
@@ -35,9 +35,14 @@
 int main(int argc, char *argv[])
 {
     QCoreApplication a(argc, argv);
-    
-	SmfServer* server = new SmfServer();
-	server->startServer();
-	
-    return a.exec();
+    SmfServer* server = new SmfServer(&a);
+    int status = -1;
+
+    if (server)
+    {
+        server->startServer();
+        status = a.exec();
+    }
+
+    return status;
 }
--- a/smf/smfservermodule/smfserver/server/server.pri	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfserver/server/server.pri	Mon Jun 07 11:43:45 2010 +0100
@@ -10,6 +10,8 @@
     PRIVATE_HEADERS += server/smfserversymbian_p.h 
     SOURCES += server/smfserversymbian.cpp
 } else {
-    PRIVATE_HEADERS += server/smfserverqt_p.h
-    SOURCES += server/smfserverqt.cpp
+    PRIVATE_HEADERS += server/smfserverqt_p.h \
+                       server/smfserverqtsession.h
+    SOURCES += server/smfserverqt.cpp \
+               server/smfserverqtsession.cpp
 }
--- a/smf/smfservermodule/smfserver/server/smfserver.cpp	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfserver/server/smfserver.cpp	Mon Jun 07 11:43:45 2010 +0100
@@ -34,11 +34,19 @@
 #include "smfserversymbian_p.h"
 #else
 #include "smfserverqt_p.h"
+#include "smfserverqtsession.h"
 #endif
 
-SmfServer::SmfServer(QObject* parent): QObject(parent)
+SmfServer::SmfServer(QObject* parent)
+    : QObject(parent)
 	{
 	}
+
+SmfServer::~SmfServer()
+{
+    delete m_SmfServerPrivate;
+}
+
 bool SmfServer::startServer()
 	{
 	bool success = false;
@@ -83,7 +91,7 @@
 			return success;
 			}
 		#else
-		m_SmfServerPrivate = new SmfServerQt();
+                m_SmfServerPrivate = new SmfServerQt(this);
 		success = m_SmfServerPrivate->start();
 		if (!success) 
 			{
@@ -104,7 +112,7 @@
  * @param clientID some unique client process ID, SID for symbian platform
  * TODO:-How to get the pid for rest of the platforms?
  * @return true if client is already athorized, else false
- * 
+ * 
  */
 bool SmfServer::isClientAuthorized(SmfClientAuthID clientID)
 	{
@@ -115,7 +123,7 @@
 /**
  * This API is called by the private impl when isClientAuthorized returns false
  * @param clientID client Id (SID for symbian platform), provided by the private impl
- * Note:- The session(and in turn the client) will be blocked untill authorization completes.
+ * Note:- The session(and in turn the client) will be blocked untill authorization completes.
  */
 void SmfServer::authorizeClient(SmfClientAuthID clientID)
 	{
@@ -130,7 +138,7 @@
  * @param pluginIDMap Map of plugins who implement this interface and corresponding provider,
  * this is returned to the private impl
  * It calls PM to get the list. Note:- PM may return SmfProviderBase which is superset of SmfProvider.
- * TODO:- session should store this map for future ref?
+ * TODO:- session should store this map for future ref?
  */
 void SmfServer::getPlugins(SmfInterfaceID interfaceID, QMap<SmfPluginID,SmfProvider>& pluginIDMap)
 	{
@@ -173,7 +181,7 @@
  * @param requestID Request id (corresponds to the key of the mapmaintained by SmfServerSymbian).
  * @param pluginID PluginID, provided by the session
  * @param interfaceID InterfaceID provided by session
- * @requestTypeID Request Opcode, provided by session
+ * @requestTypeID Request Opcode, provided by session
  */
 void SmfServer::getRequestedData(int requestID,SmfPluginID pluginID,SmfInterfaceID interfaceID, SmfRequestTypeID requestTypeID,QByteArray dataForPlugin)
 	{
@@ -303,7 +311,7 @@
 	}
 /**
  * This slot is invoked when CM finishes the authorization of the client.
- * @param authID As it contains the session ptr, sever directly invokes the session's API to notify success
+ * @param authID As it contains the session ptr, sever directly invokes the session's API to notify success
  */
 void SmfServer::clientAuthorizationFinished(bool success,SmfClientAuthID authID )
 	{
@@ -317,7 +325,7 @@
  * @param requestID The request id which is completed
  * @param parsedData Serialized data(as per request type) filled by PM
  * @param error Error occured
- * TODO:- should use smf wide global errors instead
+ * TODO:- should use smf wide global errors instead
  */
 void SmfServer::resultsAvailable(int requestID,QByteArray* parsedData,SmfError error)
 	{
@@ -345,7 +353,7 @@
 	}
 /**
  * Used by PM to get a list of tokens
- * TODO:- cross check the params
+ * TODO:- cross check the params
  */
 void SmfServer::getAuthenticationKeys(int pluginID,QStringList& keys,QStringList& urls)
 	{
@@ -360,7 +368,7 @@
 /**
  * This is called when CMclient notifies client expiry.
  * @param type notification type, set of enums for future expansion
- * @param id Plugin Id for which the authentication has expired
+ * @param id Plugin Id for which the authentication has expired
  */
 void SmfServer::authenticationKeysExpired(NotificationType type,SmfPluginID id)
 	{
--- a/smf/smfservermodule/smfserver/server/smfserver.h	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfserver/server/smfserver.h	Mon Jun 07 11:43:45 2010 +0100
@@ -76,7 +76,7 @@
    */
   bool startServer();
   
-  ~SmfServer(){}
+  ~SmfServer();
 
 public:
   /*
--- a/smf/smfservermodule/smfserver/server/smfserverqt.cpp	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfserver/server/smfserverqt.cpp	Mon Jun 07 11:43:45 2010 +0100
@@ -11,42 +11,62 @@
  *
  * Contributors:
  * Manasij Roy, Nalina Hariharan
-* Description:
-* SMF Server implementation for platforms other than Symbian.
-* Uses  QLocalServer-QLocalSocket classes
-*
-*/
+ * Description:
+ * SMF Server implementation for platforms other than Symbian.
+ * Uses  QLocalServer-QLocalSocket classes
+ *
+ */
 
 #include "smfserverqt_p.h"
+#include "smfserverqtsession.h"
+#include "smfserver.h"
 
 #include <QLocalServer>
 #include <QLocalSocket>
 
-//
-// SmfServerQt
-//
 
-SmfServerQt::SmfServerQt()
+SmfServerQt::SmfServerQt(SmfServer *wrapper)
+    : m_generic(wrapper)
 {
+    m_server = new QLocalServer(this);
+    connect(m_server, SIGNAL(newConnection()), this, SLOT(newClientConnected()));
 }
 
 SmfServerQt::~SmfServerQt()
 {
+    m_server->close();
 }
 
+/**
+  * Start the server listening for connections.
+  */
 bool SmfServerQt::start()
 {
-    return false;
+    const QString KServerName("SmfServerQt");
+    if (m_server->listen(KServerName))
+    {
+        writeLog(QString(m_server->serverName() + ": listening for connections."));
+        return true;
+    }
+    else
+    {
+        writeLog(QString(KServerName + ": failed to start"));
+        writeLog(QString(m_server->errorString()));
+        return false;
+    }
 }
 
+/**
+ * Return the number of open sessions
+ */
 int SmfServerQt::sessionListCount() const
 {
-    return 0;
+    return m_sessions.count();
 }
 
 void SmfServerQt::writeLog(QString log) const
 {
-    Q_UNUSED(log);
+    qDebug() << log.toAscii().constData();
 }
 
 /**
@@ -58,8 +78,22 @@
     Q_UNUSED(success);
 }
 
+/**
+  * Slot to receive incoming connections
+  */
 void SmfServerQt::newClientConnected()
 {
+    QLocalSocket *client(m_server->nextPendingConnection());
+    if (!client)
+    {
+        writeLog("SmfServerQt::newClientConnected(): no socket - client may have dropped.");
+        return;
+    }
+
+    // Create a new session for this client.
+    writeLog("Client connected.");
+
+    m_sessions.append(new SmfServerQtSession(client, this));
 }
 
 void  SmfServerQt::removeFromList()
@@ -74,25 +108,3 @@
     return 0;
 }
 
-//
-// SmfServerQtSession
-//
-
-SmfServerQtSession::SmfServerQtSession(QLocalSocket *clientConnection, SmfServerQt *server)
-{
-    Q_UNUSED(server);
-    Q_UNUSED(clientConnection);
-}
-
-SmfServerQtSession::~SmfServerQtSession()
-{
-}
-
-void SmfServerQtSession::readDataFromClient()
-{
-}
-
-void SmfServerQtSession::clientAuthorizationFinished(bool success)
-{
-    Q_UNUSED(success);
-}
--- a/smf/smfservermodule/smfserver/server/smfserverqt_p.h	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfserver/server/smfserverqt_p.h	Mon Jun 07 11:43:45 2010 +0100
@@ -23,6 +23,7 @@
 #include "smfglobal.h"
 
 #include <QObject>
+class SmfServer;
 class QLocalServer;
 class QLocalSocket;
 
@@ -31,9 +32,11 @@
     Q_OBJECT
 
 public:
-    SmfServerQt();
+    SmfServerQt(SmfServer* wrapper);
     ~SmfServerQt();
 
+    inline SmfServer *wrapper() const;
+
     bool start();
     int sessionListCount() const;
     void writeLog(QString log) const;
@@ -45,27 +48,15 @@
     void removeFromList();
 
 private:
+    SmfServer *m_generic;
     QLocalServer *m_server;
-    QLocalSocket *m_client;
+    QList<SmfServerQtSession*> m_sessions;
 };
 
-class SmfServerQtSession : public QObject
+inline SmfServer *SmfServerQt::wrapper() const
 {
-    Q_OBJECT
-
-public:
-    SmfServerQtSession(QLocalSocket *clientConnection, SmfServerQt *server);
-    ~SmfServerQtSession();
+    return m_generic;
+}
 
-    void clientAuthorizationFinished(bool success);
-
-public slots:
-    void readDataFromClient();
-    
-private:
-    SmfServerQt *m_server;
-    QLocalSocket *m_clientConnection;
-
-};
 
 #endif // SMFSERVERQT_P_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smf/smfservermodule/smfserver/server/smfserverqtsession.cpp	Mon Jun 07 11:43:45 2010 +0100
@@ -0,0 +1,116 @@
+/**
+ * Copyright (c) 2010 Sasken Communication Technologies Ltd.
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of the "Eclipse Public License v1.0"
+ * which accompanies  this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html"
+ *
+ * Initial Contributors:
+ * Chandradeep Gandhi, Sasken Communication Technologies Ltd - Initial contribution
+ *
+ * Contributors:
+ * Manasij Roy, Nalina Hariharan
+ *
+ *
+ * Description: Session implementation for Qt desktop builds
+ *
+ */
+
+#include "smfserverqtsession.h"
+#include "smfserverqt_p.h"
+#include "smfserver.h"
+
+SmfServerQtSession::SmfServerQtSession(QLocalSocket *clientConnection, SmfServerQt *server)
+    : m_opCode(-1), m_clientConnection(clientConnection), m_server(server)
+{
+    connect(m_clientConnection, SIGNAL(readyRead()), this, SLOT(readDataFromClient()));
+    connect(m_clientConnection, SIGNAL(error(QLocalSocket::LocalSocketError)),
+            this, SLOT(socketError(QLocalSocket::LocalSocketError)));
+}
+
+SmfServerQtSession::~SmfServerQtSession()
+{
+    // The socket has the QLocalServer as a parent, but it should be deleted to
+    // save unnecessary accumulation of these objects in memory. It won't be double deleted.
+    delete m_clientConnection;
+}
+
+void SmfServerQtSession::readDataFromClient()
+{
+    // TODO: This needs to be much safer.
+    if(m_clientConnection->bytesAvailable() < sizeof(typeof(SmfRequestTypeID)))
+    {
+        // Don't read yet, haven't received opcode
+        return;
+    }
+
+    if (m_opCode == -1)
+    {
+        QDataStream in(m_clientConnection);
+        in >> m_opCode;
+    }
+
+    // m_opCode set, so handle request
+    handleRequest();
+}
+
+/**
+ * Call the appropriate handler function
+ */
+void SmfServerQtSession::handleRequest()
+{
+    switch (m_opCode)
+    {
+    case SmfGetService:
+        handleGetService();
+        break;
+    default:
+        m_server->writeLog(QString("Bad Request received: ") + m_opCode);
+    }
+}
+
+/**
+ * Find available services for specified interface and return list to client.
+ */
+void SmfServerQtSession::handleGetService()
+{
+    m_server->writeLog("SmfServerQtSession::handleGetService()");
+
+    QDataStream in(m_clientConnection);
+
+    // Get interface type requested
+    SmfInterfaceID ifName;
+    in >> ifName;
+    m_server->writeLog("Requested: " + ifName);
+
+    // Get the available services for this interface
+    QMap<SmfPluginID, SmfProvider> services;
+    m_server->wrapper()->getPlugins(ifName, services);
+
+    // write back the results
+    QDataStream out(m_clientConnection);
+    out << services;
+}
+
+void SmfServerQtSession::clientAuthorizationFinished(bool success)
+{
+    Q_UNUSED(success);
+}
+
+void SmfServerQtSession::socketError(QLocalSocket::LocalSocketError error)
+{
+    switch (error)
+    {
+    case QLocalSocket::PeerClosedError:
+        m_server->writeLog("Peer closed connection.");
+        break;
+    case QLocalSocket::SocketTimeoutError:
+        m_server->writeLog("error: connection timed out.");
+        break;
+    default:
+        m_server->writeLog("error: unkown socket error: " + error);
+        break;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smf/smfservermodule/smfserver/server/smfserverqtsession.h	Mon Jun 07 11:43:45 2010 +0100
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2010 Sasken Communication Technologies Ltd.
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of the "Eclipse Public License v1.0"
+ * which accompanies  this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html"
+ *
+ * Initial Contributors:
+ * Chandradeep Gandhi, Sasken Communication Technologies Ltd - Initial contribution
+ *
+ * Contributors:
+ * Manasij Roy, Nalina Hariharan
+ *
+ *
+ * Description: Session implementation for Qt desktop builds
+ *
+ */
+
+#ifndef SMFSERVERQTSESSION_H
+#define SMFSERVERQTSESSION_H
+
+#include <QObject>
+#include <QLocalSocket>
+
+class SmfServerQt;
+
+class SmfServerQtSession : public QObject
+{
+    Q_OBJECT
+
+public:
+    SmfServerQtSession(QLocalSocket *clientConnection, SmfServerQt *server);
+    ~SmfServerQtSession();
+
+    void clientAuthorizationFinished(bool success);
+
+private:
+    void handleRequest();
+    void handleGetService();
+
+public slots:
+    void readDataFromClient();
+    void socketError(QLocalSocket::LocalSocketError error);
+
+private:
+    int m_opCode;
+    QLocalSocket *m_clientConnection;
+    SmfServerQt *m_server;
+};
+
+#endif // SMFSERVERQTSESSION_H
--- a/smf/smfservermodule/smfserver/smfserver.pro	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfserver/smfserver.pro	Mon Jun 07 11:43:45 2010 +0100
@@ -38,9 +38,6 @@
 SOURCES += \
 	main.cpp
 
-FORMS	  +=
-RESOURCES +=
-
 symbian: { 
     TARGET.UID3 = 0xE5027327
 
--- a/smf/smfservermodule/smfservermodule.pro	Fri May 21 16:50:44 2010 +0100
+++ b/smf/smfservermodule/smfservermodule.pro	Mon Jun 07 11:43:45 2010 +0100
@@ -2,4 +2,5 @@
 
 SUBDIRS   =	util \
                 smfserver \
-                smfclient
+                smfclient \
+                tests
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smf/smfservermodule/tests/tests.pro	Mon Jun 07 11:43:45 2010 +0100
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+
+SUBDIRS = testsmfgetservices
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smf/smfservermodule/tests/testsmfgetservices/testsmfgetservices.cpp	Mon Jun 07 11:43:45 2010 +0100
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2010 Sasken Communication Technologies Ltd.
+ * All rights reserved.
+ * This component and the accompanying materials are made available
+ * under the terms of the "Eclipse Public License v1.0"
+ * which accompanies  this distribution, and is available
+ * at the URL "http://www.eclipse.org/legal/epl-v10.html"
+ *
+ * Initial Contributors:
+ * Chandradeep Gandhi, Sasken Communication Technologies Ltd - Initial contribution
+ *
+ * Contributors:
+ * Manasij Roy, Nalina Hariharan
+ *
+ *
+ * Description: Testing the GetServices API of Social Mobile Framework, expected to
+ * return a list of installed service providers for a given interface.
+ */
+
+#include <QtTest>
+
+#include "smfclient.h"
+
+class TestSmfGetServices : public QObject
+{
+    Q_OBJECT
+
+private slots:
+    void initTestCase();
+    void testConnectToServer();
+    void cleanupTestCase();
+
+private:
+    SmfClient* m_smf;
+};
+
+void TestSmfGetServices::initTestCase()
+{
+    m_smf = new SmfClient();
+}
+
+void TestSmfGetServices::testConnectToServer()
+{
+    QList<SmfProvider> *services = m_smf->GetServices("org.symbian.smf.contacts.fetcher");
+    qDebug() << "SmfClient::GetServices returned " << services->length() << " services.";
+}
+
+void TestSmfGetServices::cleanupTestCase()
+{
+    delete m_smf;
+}
+
+QTEST_MAIN(TestSmfGetServices)
+#include "testsmfgetservices.moc"
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smf/smfservermodule/tests/testsmfgetservices/testsmfgetservices.pro	Mon Jun 07 11:43:45 2010 +0100
@@ -0,0 +1,18 @@
+# TestSmfGetServices
+
+TEMPLATE = app
+
+TARGET = testsmfgetservices
+
+QT += core \
+      testlib
+
+SOURCES += ./testsmfgetservices.cpp
+
+LIBS += -lsmfclient
+
+!symbian {
+    include(../../../desktop.pri)
+    INCLUDEPATH += $$PWD/../../smfclient/client \
+                   $$PWD/../../smfclient/common \
+}