summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--testing/legion/common_lib.py2
-rw-r--r--testing/legion/examples/hello_world/host_test.isolate22
-rwxr-xr-xtesting/legion/examples/hello_world/host_test.py77
-rw-r--r--testing/legion/examples/hello_world/task_test.isolate (renamed from testing/legion/examples/hello_world/client_test.isolate)6
-rwxr-xr-xtesting/legion/examples/hello_world/task_test.py (renamed from testing/legion/examples/hello_world/client_test.py)0
-rw-r--r--testing/legion/examples/subprocess/subprocess_test.isolate2
-rwxr-xr-xtesting/legion/examples/subprocess/subprocess_test.py52
-rw-r--r--testing/legion/examples/subprocess/task.isolate (renamed from testing/legion/examples/subprocess/client.isolate)4
-rw-r--r--testing/legion/host_controller.py70
-rw-r--r--testing/legion/legion.isolate12
-rw-r--r--testing/legion/rpc_methods.py (renamed from testing/legion/client_rpc_methods.py)2
-rw-r--r--testing/legion/rpc_server.py (renamed from testing/legion/client_rpc_server.py)12
-rwxr-xr-xtesting/legion/run_task.py (renamed from testing/legion/client_controller.py)22
-rw-r--r--testing/legion/task_controller.py (renamed from testing/legion/client_lib.py)57
-rw-r--r--testing/legion/task_registration_server.py (renamed from testing/legion/discovery_server.py)32
-rw-r--r--testing/legion/test_controller.py69
16 files changed, 175 insertions, 266 deletions
diff --git a/testing/legion/common_lib.py b/testing/legion/common_lib.py
index 2f527ea..c752e0f 100644
--- a/testing/legion/common_lib.py
+++ b/testing/legion/common_lib.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Common library methods used by both host and client controllers."""
+"""Common library methods used by both coordinator and task machines."""
import argparse
import logging
diff --git a/testing/legion/examples/hello_world/host_test.isolate b/testing/legion/examples/hello_world/host_test.isolate
deleted file mode 100644
index da4ee4e..0000000
--- a/testing/legion/examples/hello_world/host_test.isolate
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'includes': [
- '../../legion.isolate',
- 'client_test.isolate'
- ],
- 'conditions': [
- ['multi_machine == 1', {
- 'variables': {
- 'command': [
- 'host_test.py',
- ],
- 'files': [
- 'host_test.py',
- ],
- },
- }],
- ]
-}
diff --git a/testing/legion/examples/hello_world/host_test.py b/testing/legion/examples/hello_world/host_test.py
deleted file mode 100755
index 7a7875b..0000000
--- a/testing/legion/examples/hello_world/host_test.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A simple host test module.
-
-This module runs on the host machine and is responsible for creating 2
-client machines, waiting for them, and running RPC calls on them.
-"""
-
-# Map the legion directory so we can import the host controller.
-import sys
-sys.path.append('../../')
-
-import logging
-import time
-
-import host_controller
-
-
-class ExampleController(host_controller.HostController):
- """A simple example controller for a test."""
-
- def __init__(self):
- super(ExampleController, self).__init__()
- self.client1 = None
- self.client2 = None
-
- def CreateClient(self):
- """Create a client object and set the proper values."""
- client = self.NewClient(
- isolate_file='client_test.isolate',
- config_vars={'multi_machine': '1'},
- dimensions={'os': 'legion-linux'}, priority=200,
- idle_timeout_secs=90, connection_timeout_secs=90,
- verbosity=logging.INFO)
- client.Create()
- return client
-
- def SetUp(self):
- """Create the client machines and wait until they connect.
-
- In this call the actual creation of the client machines is done in parallel
- by the system. The WaitForConnect calls are performed in series but will
- return as soon as the clients connect.
- """
- self.client1 = self.CreateClient()
- self.client2 = self.CreateClient()
- self.client1.WaitForConnection()
- self.client2.WaitForConnection()
-
- def Task(self):
- """Main method to run the task code."""
- self.CallEcho(self.client1)
- self.CallEcho(self.client2)
- self.CallClientTest(self.client1)
- self.CallClientTest(self.client2)
-
- def CallEcho(self, client):
- """Call rpc.Echo on a client."""
- logging.info('Calling Echo on %s', client.name)
- logging.info(client.rpc.Echo(client.name))
-
- def CallClientTest(self, client):
- """Call client_test.py name on a client."""
- logging.info('Calling Subprocess to run "./client_test.py %s"', client.name)
- proc = client.rpc.subprocess.Popen(['./client_test.py', client.name])
- client.rpc.subprocess.Wait(proc)
- retcode = client.rpc.subprocess.GetReturncode(proc)
- stdout = client.rpc.subprocess.ReadStdout(proc)
- stderr = client.rpc.subprocess.ReadStderr(proc)
- logging.info('retcode: %s, stdout: %s, stderr: %s', retcode, stdout, stderr)
-
-
-if __name__ == '__main__':
- ExampleController().RunController()
diff --git a/testing/legion/examples/hello_world/client_test.isolate b/testing/legion/examples/hello_world/task_test.isolate
index 7135ef2..1322f31 100644
--- a/testing/legion/examples/hello_world/client_test.isolate
+++ b/testing/legion/examples/hello_world/task_test.isolate
@@ -11,11 +11,11 @@
'variables': {
'command': [
'python',
- '../../client_controller.py',
+ '../../run_task.py',
],
'files': [
- 'client_test.py',
- 'client_test.isolate'
+ 'task_test.isolate',
+ 'task_test.py',
],
},
}],
diff --git a/testing/legion/examples/hello_world/client_test.py b/testing/legion/examples/hello_world/task_test.py
index 0333f7b..0333f7b 100755
--- a/testing/legion/examples/hello_world/client_test.py
+++ b/testing/legion/examples/hello_world/task_test.py
diff --git a/testing/legion/examples/subprocess/subprocess_test.isolate b/testing/legion/examples/subprocess/subprocess_test.isolate
index 5b20167..6b4561f 100644
--- a/testing/legion/examples/subprocess/subprocess_test.isolate
+++ b/testing/legion/examples/subprocess/subprocess_test.isolate
@@ -5,7 +5,7 @@
{
'includes': [
'../../legion.isolate',
- 'client.isolate'
+ 'task.isolate'
],
'conditions': [
['multi_machine == 1', {
diff --git a/testing/legion/examples/subprocess/subprocess_test.py b/testing/legion/examples/subprocess/subprocess_test.py
index 6d8ce87..28e3fb8 100755
--- a/testing/legion/examples/subprocess/subprocess_test.py
+++ b/testing/legion/examples/subprocess/subprocess_test.py
@@ -13,29 +13,29 @@ import logging
import time
import xmlrpclib
-import host_controller
+import test_controller
-class ExampleController(host_controller.HostController):
+class ExampleTestController(test_controller.TestController):
"""An example controller using the remote subprocess functions."""
def __init__(self):
- super(ExampleController, self).__init__()
- self.client = None
+ super(ExampleTestController, self).__init__()
+ self.task = None
def SetUp(self):
- """Creates the client machine and waits until it connects."""
- self.client = self.NewClient(
- isolate_file='client.isolate',
+ """Creates the task machine and waits until it connects."""
+ self.task = self.CreateNewTask(
+ isolate_file='task.isolate',
config_vars={'multi_machine': '1'},
dimensions={'os': 'legion-linux'},
idle_timeout_secs=90, connection_timeout_secs=90,
verbosity=logging.DEBUG)
- self.client.Create()
- self.client.WaitForConnection()
+ self.task.Create()
+ self.task.WaitForConnection()
- def Task(self):
- """Main method to run the task code."""
+ def RunTest(self):
+ """Main method to run the test code."""
self.TestLs()
self.TestTerminate()
self.TestMultipleProcesses()
@@ -43,37 +43,37 @@ class ExampleController(host_controller.HostController):
def TestMultipleProcesses(self):
start = time.time()
- sleep20 = self.client.rpc.subprocess.Popen(['sleep', '20'])
- sleep10 = self.client.rpc.subprocess.Popen(['sleep', '10'])
+ sleep20 = self.task.rpc.subprocess.Popen(['sleep', '20'])
+ sleep10 = self.task.rpc.subprocess.Popen(['sleep', '10'])
- self.client.rpc.subprocess.Wait(sleep10)
+ self.task.rpc.subprocess.Wait(sleep10)
elapsed = time.time() - start
assert elapsed >= 10 and elapsed < 11
- self.client.rpc.subprocess.Wait(sleep20)
+ self.task.rpc.subprocess.Wait(sleep20)
elapsed = time.time() - start
assert elapsed >= 20
- self.client.rpc.subprocess.Delete(sleep20)
- self.client.rpc.subprocess.Delete(sleep10)
+ self.task.rpc.subprocess.Delete(sleep20)
+ self.task.rpc.subprocess.Delete(sleep10)
def TestTerminate(self):
start = time.time()
- proc = self.client.rpc.subprocess.Popen(['sleep', '20'])
- self.client.rpc.subprocess.Terminate(proc) # Implicitly deleted
+ proc = self.task.rpc.subprocess.Popen(['sleep', '20'])
+ self.task.rpc.subprocess.Terminate(proc) # Implicitly deleted
try:
- self.client.rpc.subprocess.Wait(proc)
+ self.task.rpc.subprocess.Wait(proc)
except xmlrpclib.Fault:
pass
assert time.time() - start < 20
def TestLs(self):
- proc = self.client.rpc.subprocess.Popen(['ls'])
- self.client.rpc.subprocess.Wait(proc)
- assert self.client.rpc.subprocess.GetReturncode(proc) == 0
- assert 'client.isolate' in self.client.rpc.subprocess.ReadStdout(proc)
- self.client.rpc.subprocess.Delete(proc)
+ proc = self.task.rpc.subprocess.Popen(['ls'])
+ self.task.rpc.subprocess.Wait(proc)
+ assert self.task.rpc.subprocess.GetReturncode(proc) == 0
+ assert 'task.isolate' in self.task.rpc.subprocess.ReadStdout(proc)
+ self.task.rpc.subprocess.Delete(proc)
if __name__ == '__main__':
- ExampleController().RunController()
+ ExampleTestController().RunController()
diff --git a/testing/legion/examples/subprocess/client.isolate b/testing/legion/examples/subprocess/task.isolate
index 611562c..534275df 100644
--- a/testing/legion/examples/subprocess/client.isolate
+++ b/testing/legion/examples/subprocess/task.isolate
@@ -11,10 +11,10 @@
'variables': {
'command': [
'python',
- '../../client_controller.py',
+ '../../run_task.py',
],
'files': [
- 'client.isolate'
+ 'task.isolate'
],
},
}],
diff --git a/testing/legion/host_controller.py b/testing/legion/host_controller.py
deleted file mode 100644
index dadcba4..0000000
--- a/testing/legion/host_controller.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Defines the host controller base library.
-
-This module is the basis on which host controllers are built and executed.
-"""
-
-import logging
-import sys
-
-#pylint: disable=relative-import
-import client_lib
-import common_lib
-import discovery_server
-
-
-class HostController(object):
- """The base host controller class."""
-
- def __init__(self):
- self._discovery_server = discovery_server.DiscoveryServer()
-
- def SetUp(self):
- """Setup method used by the subclass."""
- pass
-
- def Task(self):
- """Main task method used by the subclass."""
- pass
-
- def TearDown(self):
- """Teardown method used by the subclass."""
- pass
-
- def NewClient(self, *args, **kwargs):
- controller = client_lib.ClientController(*args, **kwargs)
- self._discovery_server.RegisterClientCallback(
- controller.otp, controller.OnConnect)
- return controller
-
- def RunController(self):
- """Main entry point for the controller."""
- print ' '.join(sys.argv)
- common_lib.InitLogging()
- self._discovery_server.Start()
-
- error = None
- tb = None
- try:
- self.SetUp()
- self.Task()
- except Exception as e:
- # Defer raising exceptions until after TearDown and _TearDown are called.
- error = e
- tb = sys.exc_info()[-1]
- try:
- self.TearDown()
- except Exception as e:
- # Defer raising exceptions until after _TearDown is called.
- # Note that an error raised here will obscure any errors raised
- # previously.
- error = e
- tb = sys.exc_info()[-1]
-
- self._discovery_server.Shutdown()
- client_lib.ClientController.ReleaseAllControllers()
- if error:
- raise error, None, tb #pylint: disable=raising-bad-type
diff --git a/testing/legion/legion.isolate b/testing/legion/legion.isolate
index 463764d..774b27a 100644
--- a/testing/legion/legion.isolate
+++ b/testing/legion/legion.isolate
@@ -6,14 +6,14 @@
'variables': {
'files': [
'__init__.py',
- 'client_controller.py',
- 'client_lib.py',
- 'client_rpc_methods.py',
- 'client_rpc_server.py',
'common_lib.py',
- 'discovery_server.py',
- 'host_controller.py',
'legion.isolate',
+ 'rpc_methods.py',
+ 'rpc_server.py',
+ 'run_task.py',
+ 'task_controller.py',
+ 'task_registration_server.py',
+ 'test_controller.py',
'../../tools/swarming_client/',
],
},
diff --git a/testing/legion/client_rpc_methods.py b/testing/legion/rpc_methods.py
index e43a7d8..7f17e23 100644
--- a/testing/legion/client_rpc_methods.py
+++ b/testing/legion/rpc_methods.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Defines the client RPC methods."""
+"""Defines the task RPC methods."""
import os
import sys
diff --git a/testing/legion/client_rpc_server.py b/testing/legion/rpc_server.py
index 7a5f565..43b4317 100644
--- a/testing/legion/client_rpc_server.py
+++ b/testing/legion/rpc_server.py
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""The client RPC server code.
+"""The task RPC server code.
This server is an XML-RPC server which serves code from
-client_rpc_methods.RPCMethods.
+rpc_methods.RPCMethods.
This server will run until shutdown is called on the server object. This can
be achieved in 2 ways:
@@ -22,8 +22,8 @@ import SimpleXMLRPCServer
import SocketServer
#pylint: disable=relative-import
-import client_rpc_methods
import common_lib
+import rpc_methods
class RequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
@@ -33,10 +33,10 @@ class RequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
"""
def do_POST(self):
- """Verifies the client is authorized to perform RPCs."""
+ """Verifies the task is authorized to perform RPCs."""
if self.client_address[0] != self.server.authorized_address:
logging.error('Received unauthorized RPC request from %s',
- self.client_address[0])
+ self.task_address[0])
self.send_response(403)
response = 'Forbidden'
self.send_header('Content-type', 'text/plain')
@@ -60,7 +60,7 @@ class RPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer,
self.authorized_address = authorized_address
self.idle_timeout_secs = idle_timeout_secs
- self.register_instance(client_rpc_methods.RPCMethods(self))
+ self.register_instance(rpc_methods.RPCMethods(self))
self._shutdown_requested_event = threading.Event()
self._rpc_received_event = threading.Event()
diff --git a/testing/legion/client_controller.py b/testing/legion/run_task.py
index dd80c29..6a55073 100755
--- a/testing/legion/client_controller.py
+++ b/testing/legion/run_task.py
@@ -3,11 +3,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""The main client_controller code.
-
-This code is the main entry point for the client machines and handles
-registering with the host server and running the local RPC server.
-"""
+"""The main task entrypoint."""
import argparse
import logging
@@ -16,32 +12,32 @@ import sys
import time
#pylint: disable=relative-import
-import client_rpc_server
import common_lib
+import rpc_server
def main():
print ' '.join(sys.argv)
common_lib.InitLogging()
- logging.info('Client controller starting')
+ logging.info('Task starting')
parser = argparse.ArgumentParser()
parser.add_argument('--otp',
help='One time token used to authenticate with the host')
- parser.add_argument('--host',
- help='The ip address of the host')
+ parser.add_argument('--controller',
+ help='The ip address of the controller machine')
parser.add_argument('--idle-timeout', type=int,
default=common_lib.DEFAULT_TIMEOUT_SECS,
help='The idle timeout for the rpc server in seconds')
args, _ = parser.parse_known_args()
logging.info(
- 'Registering with discovery server at %s using OTP %s', args.host,
- args.otp)
- server = common_lib.ConnectToServer(args.host).RegisterClient(
+ 'Registering with registration server at %s using OTP "%s"',
+ args.controller, args.otp)
+ server = common_lib.ConnectToServer(args.controller).RegisterTask(
args.otp, common_lib.MY_IP)
- server = client_rpc_server.RPCServer(args.host, args.idle_timeout)
+ server = rpc_server.RPCServer(args.controller, args.idle_timeout)
server.serve_forever()
return 0
diff --git a/testing/legion/client_lib.py b/testing/legion/task_controller.py
index 4656cac..e0812b4 100644
--- a/testing/legion/client_lib.py
+++ b/testing/legion/task_controller.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Defines the client library."""
+"""Defines the task controller library."""
import argparse
import datetime
@@ -30,11 +30,24 @@ class ConnectionTimeoutError(Error):
pass
-class ClientController(object):
- """Creates, configures, and controls a client machine."""
+class TaskController(object):
+ """Provisions, configures, and controls a task machine.
- _client_count = 0
- _controllers = []
+ This class is an abstraction of a physical task machine. It provides an
+ end to end API for controlling a task machine. Operations on the task machine
+ are performed using the instance's "rpc" property. A simple end to end
+ scenario is as follows:
+
+ task = TaskController(...)
+ task.Create()
+ task.WaitForConnection()
+ proc = task.rpc.subprocess.Popen(['ls'])
+ print task.rpc.subprocess.GetStdout(proc)
+ task.Release()
+ """
+
+ _task_count = 0
+ _tasks = []
def __init__(self, isolate_file, config_vars, dimensions, priority=100,
idle_timeout_secs=common_lib.DEFAULT_TIMEOUT_SECS,
@@ -42,10 +55,10 @@ class ClientController(object):
verbosity='ERROR', name=None):
assert isinstance(config_vars, dict)
assert isinstance(dimensions, dict)
- type(self)._controllers.append(self)
- type(self)._client_count += 1
+ type(self)._tasks.append(self)
+ type(self)._task_count += 1
self.verbosity = verbosity
- self._name = name or 'Client%d' % type(self)._client_count
+ self._name = name or 'Task%d' % type(self)._task_count
self._priority = priority
self._isolate_file = isolate_file
self._isolated_file = isolate_file + 'd'
@@ -61,14 +74,14 @@ class ClientController(object):
parser = argparse.ArgumentParser()
parser.add_argument('--isolate-server')
parser.add_argument('--swarming-server')
- parser.add_argument('--client-connection-timeout-secs',
+ parser.add_argument('--task-connection-timeout-secs',
default=common_lib.DEFAULT_TIMEOUT_SECS)
args, _ = parser.parse_known_args()
self._isolate_server = args.isolate_server
self._swarming_server = args.swarming_server
self._connection_timeout_secs = (connection_timeout_secs or
- args.client_connection_timeout_secs)
+ args.task_connection_timeout_secs)
@property
def name(self):
@@ -107,31 +120,31 @@ class ClientController(object):
self._verbosity = level #pylint: disable=attribute-defined-outside-init
@classmethod
- def ReleaseAllControllers(cls):
- for controller in cls._controllers:
- controller.Release()
+ def ReleaseAllTasks(cls):
+ for task in cls._tasks:
+ task.Release()
def _CreateOTP(self):
"""Creates the OTP."""
- host_name = socket.gethostname()
+ controller_name = socket.gethostname()
test_name = os.path.basename(sys.argv[0])
creation_time = datetime.datetime.utcnow()
- otp = 'client:%s-host:%s-test:%s-creation:%s' % (
- self._name, host_name, test_name, creation_time)
+ otp = 'task:%s controller:%s test:%s creation:%s' % (
+ self._name, controller_name, test_name, creation_time)
return otp
def Create(self):
- """Creates the client machine."""
+ """Creates the task machine."""
logging.info('Creating %s', self.name)
self._connect_event.clear()
self._ExecuteIsolate()
self._ExecuteSwarming()
def WaitForConnection(self):
- """Waits for the client machine to connect.
+ """Waits for the task machine to connect.
Raises:
- ConnectionTimeoutError if the client doesn't connect in time.
+ ConnectionTimeoutError if the task doesn't connect in time.
"""
logging.info('Waiting for %s to connect with a timeout of %d seconds',
self._name, self._connection_timeout_secs)
@@ -140,7 +153,7 @@ class ClientController(object):
raise ConnectionTimeoutError('%s failed to connect' % self.name)
def Release(self):
- """Quits the client's RPC server so it can release the machine."""
+ """Quits the task's RPC server so it can release the machine."""
if self._rpc is not None and self._connected:
logging.info('Releasing %s', self._name)
try:
@@ -186,7 +199,7 @@ class ClientController(object):
cmd.extend([
'--',
- '--host', common_lib.MY_IP,
+ '--controller', common_lib.MY_IP,
'--otp', self._otp,
'--verbosity', self._verbosity,
'--idle-timeout', str(self._idle_timeout_secs),
@@ -203,7 +216,7 @@ class ClientController(object):
raise Error(stderr)
def OnConnect(self, ip_address):
- """Receives client ip address on connection."""
+ """Receives task ip address on connection."""
self._ip_address = ip_address
self._connected = True
self._rpc = common_lib.ConnectToServer(self._ip_address)
diff --git a/testing/legion/discovery_server.py b/testing/legion/task_registration_server.py
index 94786ce..52ba727 100644
--- a/testing/legion/discovery_server.py
+++ b/testing/legion/task_registration_server.py
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""The discovery server used to register clients.
+"""The registration server used to register tasks.
-The discovery server is started by the host controller and allows the clients
-to register themselves when they start. Authentication of the client controllers
-is based on an OTP passed to the client controller binary on startup.
+The registration server is started by the test controller and allows the tasks
+to register themselves when they start. Authentication of the tasks controllers
+is based on an OTP passed to the run_task binary on startup.
"""
import logging
@@ -18,38 +18,38 @@ import SimpleXMLRPCServer
import common_lib
-class DiscoveryServer(object):
+class TaskRegistrationServer(object):
"""Discovery server run on the host."""
def __init__(self):
- self._expected_clients = {}
+ self._expected_tasks = {}
self._rpc_server = None
self._thread = None
- def _RegisterClientRPC(self, otp, ip):
- """The RPC used by a client to register with the discovery server."""
- assert otp in self._expected_clients
- cb = self._expected_clients.pop(otp)
+ def _RegisterTaskRPC(self, otp, ip):
+ """The RPC used by a task to register with the registration server."""
+ assert otp in self._expected_tasks
+ cb = self._expected_tasks.pop(otp)
cb(ip)
- def RegisterClientCallback(self, otp, callback):
+ def RegisterTaskCallback(self, otp, callback):
"""Registers a callback associated with an OTP."""
assert callable(callback)
- self._expected_clients[otp] = callback
+ self._expected_tasks[otp] = callback
def Start(self):
- """Starts the discovery server."""
- logging.debug('Starting discovery server')
+ """Starts the registration server."""
+ logging.debug('Starting task registration server')
self._rpc_server = SimpleXMLRPCServer.SimpleXMLRPCServer(
(common_lib.SERVER_ADDRESS, common_lib.SERVER_PORT),
allow_none=True, logRequests=False)
self._rpc_server.register_function(
- self._RegisterClientRPC, 'RegisterClient')
+ self._RegisterTaskRPC, 'RegisterTask')
self._thread = threading.Thread(target=self._rpc_server.serve_forever)
self._thread.start()
def Shutdown(self):
"""Shuts the discovery server down."""
if self._thread and self._thread.is_alive():
- logging.debug('Shutting down discovery server')
+ logging.debug('Shutting down task registration server')
self._rpc_server.shutdown()
diff --git a/testing/legion/test_controller.py b/testing/legion/test_controller.py
new file mode 100644
index 0000000..2703fad
--- /dev/null
+++ b/testing/legion/test_controller.py
@@ -0,0 +1,69 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines the test controller base library.
+
+This module is the basis on which test controllers are built and executed.
+"""
+
+import logging
+import sys
+
+#pylint: disable=relative-import
+import common_lib
+import task_controller
+import task_registration_server
+
+
+class TestController(object):
+ """The base test controller class."""
+
+ def __init__(self):
+ self._registration_server = (
+ task_registration_server.TaskRegistrationServer())
+
+ def SetUp(self):
+ """Setup method used by the subclass."""
+ pass
+
+ def RunTest(self):
+ """Main test method used by the subclass."""
+ raise NotImplementedError()
+
+ def TearDown(self):
+ """Teardown method used by the subclass."""
+ pass
+
+ def CreateNewTask(self, *args, **kwargs):
+ task = task_controller.TaskController(*args, **kwargs)
+ self._registration_server.RegisterTaskCallback(
+ task.otp, task.OnConnect)
+ return task
+
+ def RunController(self):
+ """Main entry point for the controller."""
+ print ' '.join(sys.argv)
+ common_lib.InitLogging()
+ self._registration_server.Start()
+
+ error = None
+ tb = None
+ try:
+ self.SetUp()
+ self.RunTest()
+ except Exception as e:
+ # Defer raising exceptions until after TearDown is called.
+ error = e
+ tb = sys.exc_info()[-1]
+ try:
+ self.TearDown()
+ except Exception as e:
+ if not tb:
+ error = e
+ tb = sys.exc_info()[-1]
+
+ self._registration_server.Shutdown()
+ task_controller.TaskController.ReleaseAllTasks()
+ if error:
+ raise error, None, tb #pylint: disable=raising-bad-type