blob: 24ec2d9625b9e9f03b536730fcc26e5d20ecad6e [file] [log] [blame]
#!/usr/bin/python -u
#
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# DESCRIPTION :
#
# A library for factory tests with sub-tasks.
import logging
import collections
# GTK modules
import gobject
import gtk
import factory_common
from autotest_lib.client.cros import factory
from autotest_lib.client.cros.factory import ui
def schedule(task, *args, **kargs):
"""Schedules a task function to be executed one time in GTK context."""
def idle_callback():
task(*args, **kargs)
return False
gobject.idle_add(idle_callback)
class FactoryTask(object):
"""Base class for factory tasks."""
TaskSession = collections.namedtuple(
'TaskSession',
'remover, on_stop, widgets, window_connects, timeout_callbacks')
def _attach_to_task_manager(self, window, container, remover):
"""Attaches to a task manager.
@param window: The window provided by task manager.
@param container: Container widget inside window.
@param remover: Callback to remove task.
"""
assert not hasattr(self, "_task_session"), "Already attached before."
self.window = window
self.container = container
self._task_session = self.TaskSession(remover, self.stop, [], [], [])
# Hook self.stop
self.stop = self._detach_from_task_manager
def _detach_from_task_manager(self):
assert hasattr(self, "_task_session"), "Not attached yet."
self._task_session.on_stop()
for callback in self._task_session.timeout_callbacks:
gobject.source_remove(callback)
for callback in self._task_session.window_connects:
self.window.disconnect(callback)
for widget in self._task_session.widgets:
widget.hide()
self.container.remove(widget)
# Restore self.stop
self.stop = self._task_session.on_stop
remover = self._task_session.remover
del self._task_session
remover(self)
def add_widget(self, widget):
"""Adds a widget to container (automatically removed on stop)."""
self._task_session.widgets.append(widget)
self.container.add(widget)
# For widgets created by ui.make_input_window.
if hasattr(widget, 'entry'):
widget.entry.grab_focus()
def connect_window(self, *args, **kargs):
"""Connects a window event (automatically cleared on stop)."""
self._task_session.window_connects.append(
self.window.connect(*args, **kargs))
def add_timeout(self, *args, **kargs):
"""Adds a timeout callback (automatically deleted on stop)."""
self._task_session.timeout_callbacks.append(
gobject.timeout_add(*args, **kargs))
def start(self):
"""The procedure for preparing widgets and threads."""
logging.debug("%s: started.", self.__class__.__name__)
def stop(self):
"""The procedure to notify task manager to terminate current task."""
logging.debug("%s: stopped.", self.__class__.__name__)
def run_factory_tasks(job, tasklist, on_complete=gtk.main_quit):
"""Runs a list of factory tasks.
@param job: The job object from autotest "test.job".
@param tasklist: A list of FactoryTask objects to run.
@param on_complete: Callback when no more tasks to run.
"""
session = {}
def find_next_task():
if tasklist:
task = tasklist[0]
logging.info("Starting task: %s", task.__class__.__name__)
task._attach_to_task_manager(session['window'], container,
remove_task)
task.start()
container.show_all()
else:
# No more tasks - try to complete.
logging.info("All tasks completed.")
schedule(on_complete)
return False
def remove_task(task):
factory.log("Stopping task: %s" % task.__class__.__name__)
tasklist.remove(task)
schedule(find_next_task)
def register_window(window):
session['window'] = window
schedule(find_next_task)
container = gtk.VBox()
ui.run_test_widget(job, container,
window_registration_callback=register_window)