sugarbot's aim is to provide testing and automation facilities for the OLPC Project's Sugar GUI. The project must first identify and evaluate possible implementation options, and then implement the best choice. Although it has a Sugar focus, sugarbot should be easily extensible to other Python-based GUI's.

Thursday, July 31, 2008

Crunchtime

The profs are really coming down hard on us at UH, as we are soon to enter the last week. Today I was writing code/debugging for UH for about 14 hours... didn't have time for Sugarbot. Yesterday was slightly more productive, but nothing pronounced. I don't expect that this weekend/next week will allow me to put in the number of hours I'd like to, but I'll be able to make up for that in the last week or so (I fly home on the 9th).

Even though there is a "pencils down" the week after that, I don't really intend to stop developing for Sugarbot anytime in the immediate future.

(Go figure, Google's whole plan of getting people involved in the FOSS community worked.)

Monday, July 28, 2008

Trying to keep it pretty...

I'm working on the sbpython.py code, trying to implement more functionality (manipulating the title explicitly, the selected entries in a ComboBox, focus, delete/backspace). Keeping the code coherent is kind of a pain, since there isn't an obvious way to keep some of the code from being duplicated.

Hmm.

Sunday, July 27, 2008

It's Alive!!!


Sugarbot/buildbot integration is complete. I only have one port opened on the box that it's running on, but you can access it here: http://129.7.243.13:22. To access that with Firefox, you need to change a setting. I'm working on getting a different port opened.


Wednesday, July 23, 2008

Mutliple Clients, Return Status

Sugarbot's XML-RPC server should now support multiple clients. Clients are identified by either an integer or string, which is supplied by an environment variable. This way, failing clients can easily be identified. Alternatively, they can be assigned a random number for the session ID.

The sugarbot-launcher script also works the part, and grabs the completion status from the XML-RPC server and returns whatever value it should (0 if there were no failures, 1 if there were). This should allow sugarbot to be used with buildbot.

Update: The code will be on SVN shortly. Looks like Google is doing maintenance.

Tuesday, July 22, 2008

Multiple Clients

Trying to get the RPC-server set up to handle multiple clients. This will allow me to request return statuses from the RPC-server to return via the sugarbot-launcher... which in turn allows the whole sugarbot/buildbot thing to work.

Yaaay!

Sunday, July 20, 2008

Big Changes

Some extremely large changes today. The old system has been completely removed (all of the manual-parsing stuff) and replaced with the native Python stuff. I have most of the stuff for buildbot reporting in place, but have not finished it yet. I need to re-do a bunch of the nose-testing stuff tonight before I get too far along.

For comparison, here is the first demo script. Much easier to use, less error-prone, and is overall actually useful.

sugarActivityName = 'Calculate'

def sugarbot_main(widgets):
one = widgets['1']
plus = widgets['+']
enter = widgets['enter']

one.click()
plus.click()
one.click()
enter.click()

widgets['TextEntry'].text = "1+5"
assert widgets['TextEntry'].text == '1+5'
enter.click()

Inheritance

Evidently, for properties to work ... properly ... the class has to inherit from the object base class.

Saturday, July 19, 2008

Somebody please tell me why the following code does not work as one would expect (that is, printing out text when setting/getting someASDF.text):

class asdf:
def click(self):
print "click"
def getText(self):
print "getText"
def setText(self, val):
print "setText"
text = property(lambda self: self.getText(), lambda self, v: self.setText(v))

Friday, July 18, 2008

So Close!

So very, very close. Just trying to get the text-setting/getting properties to work.

For comparison purposes, here is a script that uses native Python:

one = widgets['1']
plus = widgets['+']
enter = widgets['enter']

one.click()
plus.click()
one.click()
enter.click()

textEntry = widgets['TextEntry']
textEntry.text = "1+5"
assert textEntry.text.beginswith('1')

enter.click()

Missing Something

In the process of transitioning from the custom-parsed sugarbot scripts to a much simpler system using the native Python parser. A few hiccups, but I should have things sorted out soon.

Wednesday, July 16, 2008

Sugarbot Diagram

I created a small diagram that shows most of the high-level functionality of Sugarbot today for a friend, and thought it would be beneficial to share it with all interested parties.

Tuesday, July 15, 2008

Stateful XML-RPC Server

Ironed out some bugs with the instantiation of the sugarbot activity in some corner cases. Now I'm working on the XMLRPC server implementation to be able to handle sessions. Looking for a graceful way to do it so that I can just use a mix-in with the ServerProxy class and not have to do any modification beyond that.

Essentially, I want to be able to automate do the following

someObject.setValue(foo)
someObject.someMethod(bar) === someObject.someMethod(foo,bar)

It looks like the __call__ property may be able to help me out with this.

Saturday, July 12, 2008

Full automation

When launching sugar-emulator with environment variable SUGARBOT_EMULATOR set, automatically launches Sugarbot. When the Sugarbot activity closes, it is re-launched if there are other scripts that still need to be executed. Once execution of the scripts are complete, the Sugar shell is killed (SIGTERM).

SVN revision 81 has the goods. (modded-main.py is the replacement for shell/main.py)

Automated Launching: Go!

Using just about the most obscure Python code I have ever written, I have just made sugarbot fully automatable.

It requires a small patch to main.py in the main Sugar directory (/usr/share/sugar/shell/main.py), and adding a file to the same directory. It launches sugarbot by simulating a click on the sugarbot icon in the frame.

Will put the code up on SVN later, it's Pizza time now!

Important Code:
# =========================================================
# The magnitude of this hack compares favorably with the
# current national debt.
boxChildren = self.shell.get_frame()._bottom_panel._bg.get_children()
tray = [k for k in boxChildren if isinstance(k,ActivitiesTray)]
if tray:
children = tray[0]._tray.get_children()
else:
return
activities = [k for k in children if isinstance(k, ActivityButton)]
sbList = [k for k in activities if k._activity_info.name=="sugarbot"]
# ========================================================

if len(sbList) > 0: sbList[0].emit('clicked')

main.py patch:
model = ShellModel()
shell = Shell(model)
service = ShellService(shell)

if os.environ.has_key("SUGARBOT_EMULATOR"):
from sugarbotlauncher import SugarbotLauncher
sbLauncher = SugarbotLauncher(model,shell,service)

try:
gtk.main()
except KeyboardInterrupt:
print 'Ctrl+C pressed, exiting...'

Launching Activities Automatically

Haven't found a hooking point yet, but I've gound out the API call to launch the activities.

sugar.activity.activityfactory.create(...)

Friday, July 11, 2008

Mid-Summer Screencast

The screencast is up here [mp4] and here [avi].
The SVN repo has been updated to use the same code as the screencast (r77).

Accomplishments thus far:
  • Masquerading as any Activity while retaining all functionality
  • Hooks into PyGTK library to intercept GDK Events to catalog widgets
  • Intelligent identification of widgets based on widget class to give each widget a unique identifier
  • Manipulation of many types of widgets using generic commands like 'click' and 'type'
  • Multithreaded execution routine prevents hang-ups (prior versions would stall once the calls to the GTK handler stopped due to inactivity)
  • Custom scripting language with support for advanced string manipulation [will soon be replaced by native Python code]
  • XML-RPC client/server interface allows the scripts to be stored on a central machine, while sugarbot may be run on any number of slaves.
  • Per-command status reporting and graceful error handling
  • Does not rely on any libraries or modules outside those already provided by Sugar and Python
  • Automated testing provided via buildbot and python-nose.

Have fun!
Questions, comments, and rants are welcome and appreciated.

Thursday, July 10, 2008

WTFBBQ

So the problem is absolutely, 100% NOT with my code.

Running the example Activity here does NOT produce the "Hello World" output when the button is clicked. Changing the 'log.info' statement to a 'print' statement makes it work just fine. The logging module is broken or otherwise not functioning with the latest sugar packages on Ubuntu 8.04.


ScreenFlick

With the upcoming mid-summer review, it's time to throw together a screencast and show off all that sugarbot can do. I've found a piece of software, ScreenFlick, which allows me to do just that, and to do so pretty easily. It's only for Mac OS X, and keeps the interface simple (just the way I like it). It supports some nifty features, standard stuff following the mouse, variable framerate, lossless video compression, as well as some nicer options (a visual indicator for mouse-clicks, visual indicators for keyboard activity).

Some screenshots...

The software is pretty self-explanatory, and saves the videos in .MOV format, so you can easily edit things together in Quicktime Pro. Once I'm all done, I'll probably convert the files into MP4 with VisualHub, another nice utility (which I generally use to convert videos to be iPod-compatible).

Tuesday, July 8, 2008

O ya

It's my (20th) birthday.

Wierd logging issue...

When I was doing the screencast today, I went to show that the logs were cataloging all of the identifiable Widgets... but for whatever reason, the logs were mostly empty.  I reverted to r59 (my demo version), and the logs were *still* empty.  So I deleted ~/.sugar/*... *still* no logs.  Dunno what's going on, just kind of bizarre.

Woot?

sudo xhost +

Well that was pretty friggin simple. Only a few *hours* of Googling for that one. The buildbot is not yet publicly accessible, but it now runs all 70 tests just fine. My Google-fu has truly failed me :-(. In my defense, I did find the solution earlier, but the prior finds didn't mention that the "xhost +" command had to be run as root.

Zach's to-do list:
[x] Fix issue with current buildbot
[ ] Screencast
[ ] Start sugarbot automatically
[ ] Automated testing using buildbot/scripted sugarbot

Monday, July 7, 2008

Buildbot is [almost] working

So I got buildbot up-and-running last night, and have been troubleshooting a few problems with importing some of the Sugar functionality.

Here is what I get: link (don't want to clutter the blog with a huge output). Essentially, test_sugarbot, test_sbgui, and test_widgetIdentifier are totally skipped. What is unique to these files is that the files they import from rely on Sugar (for example, importing sugar.activity.Activity or sugar.graphics). The issue is the same line in each case:

File "/usr/lib/python2.5/site-packages/sugar/graphics/style.py", line 38, in _get_screen_dpi
xft_dpi = gtk.settings_get_default().get_property('gtk-xft-dpi')
AttributeError: 'NoneType' object has no attribute 'get_property'

Unfortunately, that doesn't tell me much. I can speculate that the issue is that the buildbot-user does not have an actual X display allocated, and that Sugar is choking trying to figure out the DPI of the screen. This is pretty evident when looking above the errors:

/var/lib/python-support/python2.5/gtk-2.0/gtk/__init__.py:72: GtkWarning: could not open display
warnings.warn(str(e), _gtk.Warning)

Unfortunately, my Google-fu fails me finding anything that is relevant regarding gtk-xft-dpi, and there are way too many results for "GtkWarning: could not open display".

Sunday, July 6, 2008

Buildbot Up and Running

Buildbot is up and running, although not all of the tests will run (yet they run fine when executed manually).  I believe that it has something to do with the fact that Sugar expects a display to be present, even when you just do:

from sugar.graphics import Palette

I don't have a machine that I can put the buildbot on that can be accessed remotely (yet), but I should have a shiny new Dell any day now (it was ordered ~3 weeks ago) for my work with Univ. of Houston that I can throw a buildbot on.

Thursday, July 3, 2008

Ideas???  Buildbot complains...

Following twistd.log until startup finished..
2008/07/03 20:26 CDT [-] Log opened.
2008/07/03 20:26 CDT [-] twistd 2.2.0 (/usr/bin/python 2.5.2) starting up
2008/07/03 20:26 CDT [-] reactor class: twisted.internet.selectreactor.SelectReactor
2008/07/03 20:26 CDT [-] Loading buildbot.tac...
2008/07/03 20:26 CDT [-] Loaded.
2008/07/03 20:26 CDT [-] loading configuration from /home/buildmaster/APP/master.cfg
2008/07/03 20:26 CDT [-] error while parsing config file
2008/07/03 20:26 CDT [-] error during loadConfig
2008/07/03 20:26 CDT [-] Traceback (most recent call last):
 File "/usr/lib/python2.5/site-packages/twisted/scripts/twistd.py", line 182, in startApplication
   app.startApplication(application, not config['no_save'])
 File "/usr/lib/python2.5/site-packages/twisted/application/app.py", line 298, in startApplication
   service.IService(application).startService()
 File "/usr/lib/python2.5/site-packages/twisted/application/service.py", line 196, in startService
   service.startService()
 File "/usr/lib/python2.5/site-packages/buildbot/master.py", line 407, in startService
   self.loadTheConfigFile()
--- ---
 File "/usr/lib/python2.5/site-packages/buildbot/master.py", line 462, in loadTheConfigFile
   self.loadConfig(f)
 File "/usr/lib/python2.5/site-packages/buildbot/master.py", line 480, in loadConfig
   exec f in localDict
 File "/home/buildmaster/APP/master.cfg", line 4, in
   from buildbot.process import step, factory
: cannot import name step

2008/07/03 20:26 CDT [-] The new config file is unusable, so I'll ignore it.
2008/07/03 20:26 CDT [-] I will keep using the previous config file instead.

Next Step

Looks like my next step is to automate the Sugar interface itself, so that I can automate launching of the sugarbot application. If there is a way to automatically launch a specific Activity via command-line, please let me know.

This will ultimately allow me to write example tests for the Calculate and Terminal activity, as suggested by Grig. Those will be the first real test of sugarbot.

I've also been toying with the idea of using the Python interpreter to do the bulk of the parsing work for me. It would require some restructuring, but would ultimately be the most flexible. For example, I can think of many instances where it would be very beneficial to implement complex logic into an automated GUI test. However, re-inventing the proverbial wheel (Python interpreter) seems rather non-trivial :-). [Update: Note that I don't intend to to make my own interpreter, but rather make the current code use the interpreter]

However, I still have to tackle the issue of automatically launching sugarbot in the first place.

Feels good

How well documented should tests be? It seems like they ought to be pretty self-explanatory, otherwise they are probably too complex and are prone to breakage themselves.

On another note, this is kind of nice to see...

zach@zriggle-desktop:~/Desktop/OLPC/sugarbot/trunk/sugarbot$ nosetests test*.py
......................................................................
----------------------------------------------------------------------
Ran 70 tests in 0.581s

OK


Wednesday, July 2, 2008

More difficult than it needed to be...

I don't know why I was so stuck on the idea of *actually* using the XML-RPC interface to test the functionality exposed by XML-RPC, when I can just call all of the methods directly.

Unless something in xmlrpclib or SimpleXMLRPCServer breaks (which isn't something I can do much about), you end up with the same results.  I can't believe I wasted this much time on the problem!!!