def test_can_create_device(self): """Instantiate an actual device""" c = Configurator('test_configurator.conf') k, d = c.createDevice('dev1') assert hash(k) self.assertEqual(d.getDeviceType(), 'PseudoDevice') self.assertEqual(d.port, 9)
def test_get_password(self): """Password gleaned correctly from config file""" c = Configurator() c.fromString(configdata) self.assertEqual(len(c), 2) self.assertEqual(c.getPassword(), 'password123')
def test_case_insensitivity(self): """Authentication section name should be case insensitive""" c = Configurator() c.fromString(configdata2) self.assertEqual(len(c), 2) self.assertEqual(c.getPassword(), 'password123')
def test_password(self): """Aggregator should have random password""" assert type(self.aggregator.getPassword()) == type("") # ensure a second instance has differing password ... conf = Configurator() conf.fromString('') other = Aggregator(conf) assert other.getPassword() != self.aggregator.getPassword()
def setUpClass(self): """Start a DeviceServer in a child process to test against""" self.deviceserverprocess = SubProcessProtocol() self.deviceserverprocess.waitOnStartUp( ['server.py', 'deviceserver.conf', '-n'], \ path=os.path.join(agdevicecontrol.path,'bin') ) if self.deviceserverprocess.running is False: raise unittest.SkipTest, "DeviceServer didn't start correctly, skipping tests" #wait for slow single CPU buildbots to catch up import time time.sleep(1) # use the config above conf = Configurator() conf.fromString(configdata) # can be set by timeout self.failure = False # safety timeout self.timeout = reactor.callLater(10, self.failed, "Aggregator failed to connect to all deviceservers ... failing") self.aggregator = Aggregator(conf) self.done = False while not self.done: print "Waiting for aggregator to connect to deviceservers" reactor.iterate(0.1) if self.aggregator.connected: self.succeeded() if self.failure: raise unittest.SkipTest, "Aggregator didn't connect to all deviceservers ... skipping tests" # FIXME: we really should handle missing and newly appearing deviceservers. # safety timeout self.timeout = reactor.callLater(10, self.failed, "Aggregator failed to map all deviceservers ... failing") self.aggregator.notifyOnMapped(self.succeeded) self.done = False while not self.done: print "Waiting for aggregator to map deviceservers" reactor.iterate(0.1) if self.failure: raise unittest.SkipTest, "Aggregator didn't start correctly, skipping tests"
def setUp(self): """I'm called at the very beginning of each test""" c = Configurator() c.fromString(configdata) self.ds = DeviceServer(c) self.finished = False self.failed = None self.pending_deferreds = [] # safety timeout self.timeout = reactor.callLater(10, self.timedOut)
def loadConfig(self, config_file): self.config = Configurator(config_file)
class Aggregator: implements(IDeviceServer,IAggregator) def __init__(self, config, testmode=False): self.servers = [] # keyed by server, pbroot objects for RPC self.perspectives = {} # each server has a devicemap, each a dictionary keyed by devicetype # containing devices on the server self.devicemaps = {} # composite devicemap aggregating all deviceservers # by the devicetype, each a list of device names self.aggregatormap = {} # key by device name, corresponding server name containing the device self.devicedict = {} # becomes True only once we have perspectives on all DeviceServers self.connected = False # user can register to be informed when the Aggregator has completed # full connection to all constituent DeviceServers self._notifyonmappedcb = None # random password unless in testmode if not testmode: self.password = self._generatePassword() else: print "Test mode enabled with preconfigured password (shouldn't see this in normal use)" self.password = '******' # hey, it had to be something ... # becomes True only once we have aggregatormap compiled self.mapped = False self.config = config if not isinstance(config,Configurator): self.loadConfig(config) self._connectAll() def _generatePassword(self, length=10): """http://mail.python.org/pipermail/python-list/2004-February/208169.html""" twoletters = [c+d for c in string.letters for d in string.letters] n = len(twoletters) l2 = length // 2 lst = [None] * l2 for i in xrange(l2): lst[i] = twoletters[int(random.random() * n)] if length & 1: lst.append(random.choice(string.letters)) return "".join(lst) def getPassword(self): return self.password def notifyOnMapped(self, callback): self._notifyonmappedcb = callback def loadConfig(self, config_file): self.config = Configurator(config_file) def _connectAll(self): for server in self.config.sections(): self._connect(server) def _connect(self, server): host = self.config.get(server,'host') port = int(self.config.get(server,'port')) factory = pb.PBClientFactory() reactor.connectTCP(host, port, factory) password = self.config.get(server,'password') d = factory.login(credentials.UsernamePassword(version.apiversion,password)) d.addCallback(self._onConnectSuccess, server) d.addErrback(self._onConnectFailure, server) self.servers.append(server) def _onConnectSuccess(self, perspective, server): """I'm called on successful connection to each deviceserver 'server'""" self.perspectives[server] = perspective d = perspective.callRemote("getDeviceMap") d.addCallback(self._onDeviceMapSuccess, server) d.addErrback(self._onDeviceMapFailure, server) # have we got all the perspectives yet? if len(self.perspectives) == len(self.servers): self.connected = True def _onConnectFailure(self, failure, server): """Failed connection to a deviceserver""" # FIXME: notify of failure, have we finished getting perspectives? return failure def _onDeviceMapSuccess(self, devicemap, server): """I'm called on successful devicemap for every device server""" # paranioa check assert not server in self.devicemaps print server self.devicemaps[server] = devicemap for devicetype,devicelist in devicemap.items(): if devicetype in self.aggregatormap: self.aggregatormap[devicetype].extend( devicelist ) else: self.aggregatormap[devicetype] = devicelist # we'll need to discern server given a device name for device in devicelist: print " DEBUG:" print device.id assert not device in self.devicedict self.devicedict[device] = server # have we got all the devicemaps? (FIXME: can't complete if a # DeviceServer doesn't connect) if len(self.devicemaps) == len(self.servers): self.mapped = True if self._notifyonmappedcb: self._notifyonmappedcb(self) def _onDeviceMapFailure(self, failure, server): """Failed to retrieve a devicemap deviceserver""" return failure def getDeviceList(self): """Return aggregated devicelist (assumes built-up during connection chain""" return defer.succeed(self.devicedict.keys()) def getDeviceMap(self): """Return aggregated devicemap (assumes built-up during connection chain""" return defer.succeed(self.aggregatormap) def deviceExecute(self, device, command, params=None): print print "DEBUG:" print device print device.id server = self.devicedict[device] return self.perspectives[server].callRemote("deviceExecute", device, command, params)
class DeviceServer: implements(IDeviceServer) def __init__(self, config): self.config = config if not isinstance(config,Configurator): self.loadConfig(config) #dictionary of devices, keyed by a Container with relevant info in it. self.devices = {} # each device has a command queue self.queues = {} # dictionary of device containers, keyed by type. self._devicemap = {} for device in self.config.sections(): con = Container() key, instance = self.config.createDevice(device) con.name = key con.type = instance.getDeviceType() try: self._devicemap[instance.getDeviceType()].append(con) except KeyError: self._devicemap[instance.getDeviceType()] = [con] self.devices[con] = instance self.queues[con] = DeviceQueue() def loadConfig(self, config): self.config = Configurator(config) def getPassword(self): return self.config.getPassword() def deviceExecute(self, device, command, param=None): if device in self.getDeviceList(): if command in self.getCommandList(device): # bound method of desired device device_method = getattr(self.devices[device], command) # convenient reference queue = self.queues[device] # add to device queue d = queue.submit(device_method, param) return d def getDeviceList(self): return self.devices.keys() def getDeviceType(self, device): return self.devices[device].getDeviceType() def getCommandList(self, device): return self.devices[device].getCommandList() def getDeviceMap(self): return self._devicemap
def test_load_from_string(self): """Create a config file from string data""" c = Configurator() c.fromString(configdata) self.assertIn('dev1', c)
def test_no_password(self): """Anonymous password gleaned correctly from config file""" c = Configurator() self.assertEqual(c.getPassword(), '')
class DeviceServer: implements(IDeviceServer) def __init__(self, config): self.config = config if not isinstance(config,Configurator): self.loadConfig(config) # dictionary of device instances keyed by name self.devices = {} # each device has a command queue self.queues = {} self._devicemap = {} for device in self.config.sections(): key, instance = self.config.createDevice(device) try: self._devicemap[instance.getDeviceType()].append(device) except KeyError: self._devicemap[instance.getDeviceType()] = [device] self.devices[key] = instance self.queues[key] = DeviceQueue() self.message = "MESSAGE::TO::PASS" def loadConfig(self, config): self.config = Configurator(config) def setMessage(self, message): self.message = message def getPassword(self): return self.config.getPassword() def deviceExecute(self, device, command, param=None): if device in self.getDeviceList(): if command in self.getCommandList(device): # bound method of desired device device_method = getattr(self.devices[device], command) # convenient reference queue = self.queues[device] # add to device queue d = queue.submit(device_method, param) return d def getDeviceList(self): return self.devices.keys() def getDeviceType(self, device): return self.devices[device].getDeviceType() def getCommandList(self, device): return self.devices[device].getCommandList() def getDeviceMap(self): return self._devicemap