qt

making hooq work with pyQt and Qt4.7

GUI automation test for desktop apps with Qt could be a PIA, not only because GUI automation is simply a PIA in general,
but there are just not that much free open source tools you can make use of for Qt. Or I should say at least for me it is not easy to find any.
Almost all tools I found online are heavy weight commercial software
that have this long and fancy feature set that I have to buy as a whole, out of which most I may never touch.

Luckily I found hooq, a free, open source tool to help recording qt events
and replay them (which is exactly what I need, for now). Like all other free lunches it does take me some effort to make it useful for me. And kudos to my genius coworker Leaf
who figured out how to build all the packages hooq requires to make this happen. It seems most people got stuck on this very first step.

But then I got stuck on another problem:
although hooq can be executed fine and it can launch my app correctly, it won’t record any of my actions.
All I got was requireHooqScriptVersion(2);
I spent a whole day digging into this and it seems to be a timing issue.
fundamentally hooq uses gdb to track all the qt events by inserting breaks on all QCoreApplication::exec
and sometimes (I’m not sure if this is a system thing) the timing of loading the shared libraries could be different
and that will cause the breaks failed to be set, thus the recording won’t take effect

after trying different combinations, I modify void GdbInjector::startProcess() in GdbInjecter.cpp into the following
and this seem to work for me:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
void GdbInjector::startProcess()
{
        QString argumentsString;
        Q_FOREACH(QString argument, m_applicationArguments)
        {
         	argument.replace('"', "\\\"");
                argumentsString.append(QString(" \"%1\"").arg(argument));
	}
 
        Q_ASSERT(m_gdb->state() == QProcess::Running);
	Q_ASSERT(m_gdb->isWritable());
        m_gdbStream.setDevice(m_gdb);
        m_gdbStream << "set breakpoint pending on" << endl;
        m_gdbStream << "set auto-solib-add off" << endl; // avoid loading symbols for shared libraries                                                                                                         
                                                         // that we do not need to interact with from GDB                                                                                                      
        m_gdbStream << "break _start" << endl; // C entry point - after main libraries have been loaded                                                                                                        
	m_gdbStream << "set args" << argumentsString << endl;
        m_gdbStream << "run" << endl; // run until we hit it, and therefore Qt shared libraries are loaded                                                                                                     
 
        m_gdbStream << "sharedlibrary libdl" << endl; // load the libdl library so that we can call __dlopen()                                                                                                 
	m_gdbStream << "sharedlibrary libc" << endl;  // load the libc library so that we can call __dlopen()                                                                                                  
        //m_gdbStream << QString("call dlopen(\"/usr/lib64/libQtCore.so.4\",%1)").arg(QString::number(RTLD_NOW)) << endl;                                                                                      
        // Newer systems                                                                                                                                                                                       
        m_gdbStream << QString("call dlopen(\"%1\", %2)").arg(libraryPath()).arg(QString::number(RTLD_NOW)) << endl; // load our library                                                                       
	// Older systems                                                                                                                                                                                       
        m_gdbStream << QString("call __dlopen(\"%1\", %2)").arg(libraryPath()).arg(QString::number(RTLD_NOW)) << endl; // load our library                                                                     
        m_gdbStream << "sharedlibrary libQtCore" << endl; // load QtCore for breaking on QCoreApplication::exec()                                                                                              
        m_gdbStream << "sharedlibrary libQtGui" << endl; // load QtCore for breaking on QCoreApplication::exec()                                                                                               
        m_gdbStream << "break QCoreApplication::exec" << endl; // now, we can set this breakpoint...                                                                                                           
        m_gdbStream << "continue" << endl;
 
        m_gdbStream << "sharedlibrary injectedHooq" << endl; // load the hooq injector library so that we can call startHooq()                                                                                 
 
        m_gdbStream << "call startHooq()" << endl; // install our plugin (which required QCoreApplication setup)                                                                                               
	m_gdbStream << "continue" << endl; // run the app                                                                                                                                                      
        m_gdbStream << "backtrace" << endl; // just in case (use with --spam)                                                                                                                                  
        m_gdbStream << "quit" << endl; // after the application has exited, quit gdb                                                                                                                           
}
EmailDiggFacebookDeliciousStumbleUponTwitterTumblrGoogle GmailBlogger PostGoogle ReaderSina WeiboBox.netEvernoteFriendFeedGoogle BookmarksHotmailLiveJournalLinkedInPrintPrintFriendlyRedditSlashdotWordPressShare

Tags: , , , ,

Thursday, June 2nd, 2011 python, qt, tech 3 Comments