def setUpClass(self):

	self.csProcess = SubProcessProtocol()
	self.csProcess.waitOnStartUp(['container_server.py'], \
				     path = os.path.join(agdevicecontrol.path,'tests'))
		
	print "csProcess started"
	time.sleep(1)
    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 setUpClass(self):
        """Start a DeviceServer in a child process to test against"""

        # deviceserver startup script directory
        bindir = os.path.join(agdevicecontrol.path, 'bin')

        # keep track of temporary files for deletion in tearDown
        self.tempfiles = []

        # create a temporary deviceserver config file
        filename = 'test_deviceserver.conf'
        fqfilename = bindir + os.sep + filename
        f = open(fqfilename,'w')
        f.write(deviceserver_config_contents)
        f.close()
        self.tempfiles.append(fqfilename)

        # start deviceserver as a child process
        self.process = SubProcessProtocol()
        self.process.waitOnStartUp(['server.py', filename, '-n'], path = bindir)
        if self.process.running is False:
            raise unittest.SkipTest, "DeviceServer didn't start correctly, skipping tests"
class TestConnector(SignalMixin, unittest.TestCase):

    def setUpClass(self):
        """Start an Aggregator in a child process to test against"""

        # aggregator startup script directory
        bindir = os.path.join(agdevicecontrol.path, 'server')

        # keep track of temporary files for deletion in tearDown
        self.tempfiles = []

        # create a temporary aggregator config file
        filename = 'test_aggregator.conf'
        fqfilename = bindir + os.sep + filename
        f = open(fqfilename,'w')
        f.write(aggregator_config_contents)
        f.close()
        self.tempfiles.append(fqfilename)

        # start aggregator as a child process
        self.process = SubProcessProtocol()
        self.process.waitOnStartUp(['aggregator.py', filename, '-n', '--test'], path = bindir)
        if self.process.running is False:
            raise unittest.SkipTest, "Aggregator didn't start correctly, skipping tests"
        import time
        time.sleep(1)


    def tearDownClass(self):
        """Stop the Aggregator running in a child process"""
        print "*** tearDownClass: ", self.process.done
        self.process.waitOnShutDown()

        # clean-up temporary config files
        for f in self.tempfiles:
            os.remove(f)



    def setUp(self):
        """Per test initalization"""
        self.done = False
        self.failure = None

    def tearDown(self):
        """Per test cleanup code"""
        if self.connector:
            self.connector.close()


    def succeeded(self, *args):
        """Allow reactor iteration loop in test proper to exit and pass test"""
        self.done = True
        self.timeout.cancel()  # safety timeout no longer necessary
        self.lastargs = args  # make persistent for later checks


    def failed(self, reason, unknown):
        """Allow reactor iteration loop in test proper to exit and fail test"""
        self.done = True
        self.failure = reason
        self.lastargs = None


    def test_simple_connect(self):
        """Obtain perspective on Aggregator"""

        # safety timeout
        self.timeout = reactor.callLater(10, self.failed, "attempt to connect to Aggregator timed out ... failing")

        self.connector = Connector('localhost', port=8789)
        self.connector.connect(callback=self.succeeded, errback=self.failed, password='******')
        
        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)

        connector = self.lastargs[0]
        assert connector == self.connector

        # paranoia check
        assert self.connector.connected is True

        

    
    if False:
        test_simple_connect.skip = True
class TestAggregator(SignalMixin, unittest.TestCase):

    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 tearDownClass(self):
        """Stop the DeviceServer running in a child process"""
        print "*** tearDownClass: ", self.deviceserverprocess.done
        self.deviceserverprocess.waitOnShutDown()


    def succeeded(self, *args):
        """Allow reactor iteration loop in test proper to exit and pass test"""
        self.done = True
	if self.timeout is not None:
	    self.timeout.cancel()  # safety timeout no longer necessary
        self.timeout = None
        self.lastargs = args  # make persistent for later checks


    def failed(self, reason):
        """Allow reactor iteration loop in test proper to exit and fail test"""
        self.done = True
        self.failure = reason
        self.timeout.cancel()  # safety timeout no longer necessary
        self.timeout = None

    def setUp(self):
        """I'm called at the very beginning of each test"""
        self.done = False
        self.failure = None
        self.timeout = None


    def tearDown(self):
        """I'm called at the end of each test"""
        if self.timeout:
            self.timeout.cancel()


    def timedOut(self):
        """I'm called when the safety timer expires indicating test probably won't complete"""

        print "timedOut callback, test did not complete"
        self.failed("Safety timeout callback ... test did not complete")
        reactor.crash()


        

    #---------- tests proper ------------------------------------

    def test_handled_configurator(self):
        """Aggregator instantiated with a configurator rather than .conf filename"""
        assert 'DeviceServer1' in self.aggregator.config


    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 test_devicelist_as_deferred(self):
        """Return aggregated device list"""

        # safety timeout
        self.timeout = reactor.callLater(10, self.failed, "retrieving devicelist timed out ... failing")

        d = self.aggregator.getDeviceList()
        assert isinstance(d, defer.Deferred)
        d.addCallback(self.succeeded)
        
        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
            reactor.iterate(0.1)
        
        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.failed(self.failure)

        devicelist = self.lastargs[0]
        assert len(devicelist) == 2
        assert 'Device1' in devicelist
        assert 'Device2' in devicelist



    def test_devicemap_as_deferred(self):
        """Return aggregated device map"""

        # safety timeout
        self.timeout = reactor.callLater(10, self.failed, "retrieving devicemap timed out ... failing")

        d = self.aggregator.getDeviceMap()
        assert isinstance(d, defer.Deferred)

        # caution: as this deferred is ready-to-go, the callback is called *immediately*
        d.addCallback(self.succeeded)
        # i.e., self.succeeded has now been called
        
        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
             reactor.iterate(0.1)
        
        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.failed(self.failure)

        devicemap = self.lastargs[0]
        print devicemap
        assert type(devicemap) == types.DictType
        assert len(devicemap) == 1
        assert 'PseudoDevice' in devicemap
        assert len(devicemap['PseudoDevice']) == 2
        assert 'Device1' in devicemap['PseudoDevice']
        assert 'Device2' in devicemap['PseudoDevice']



    def test_device_execute(self):
        """Proxy forward command to correct DeviceServer"""

        # safety timeout
        self.timeout = reactor.callLater(10, self.failed, "executing remote setParameter timed out ... failing")

        # 3-digit random integer
        value = int(random.random()*1000)
	
	# get a device key for use in next step
	self.done = False
	d = self.aggregator.getDeviceList()
	d.addCallback(self.succeeded)
	d.addErrback(self.failed)

	while not self.done:
	    reactor.iterate(0.1)

	if self.failure:
	    self.fail(self.failure)

	print
	print "DEBUG:"
	device = self.lastargs[0][0]
	print device.name

        # store number in 'remote' PseudoDevice
        d = self.aggregator.deviceExecute(device, 'setParameter', value)
        assert isinstance(d, defer.Deferred)
        d.addCallback(self.succeeded)
        
        # idle until code above triggers succeeded or timeout causes failure
        self.done = False
        while not self.done:
            reactor.iterate(0.1)
        
        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.failed(self.failure)


        # safety timeout
        self.timeout = reactor.callLater(10, self.failed, "executing remote getParameter timed out ... failing")

        # store number in 'remote' PseudoDevice
        d = self.aggregator.deviceExecute(device, 'getParameter')
        assert isinstance(d, defer.Deferred)
        d.addCallback(self.succeeded)
        
        # idle until code above triggers succeeded or timeout causes failure
        self.done = False
        while not self.done:
            reactor.iterate(0.1)
        
        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.failed(self.failure)

        returnvalue = self.lastargs[0]
        assert returnvalue == value


    if False:
        test_handled_configurator = True
        test_devicelist_as_deferred = True
        test_devicemap_as_deferred = True
        test_device_execute = True
        test_password = True
class TestContainer(SignalMixin, unittest.TestCase):

    def setUpClass(self):

	self.csProcess = SubProcessProtocol()
	self.csProcess.waitOnStartUp(['container_server.py'], \
				     path = os.path.join(agdevicecontrol.path,'tests'))
		
	print "csProcess started"
	time.sleep(1)

    def tearDownClass(self):
	print "tearDownClass"
	self.csProcess.waitOnShutDown()

    def setUp(self):
	print
	print "setUP"
	self.done = False
	self.failure = None


    def succeeded(self, *args):
        """Allow reactor iteration loop in test proper to exit and pass test"""
	self.done = True
	self.timeout.cancel()  # safety timeout no longer necessary
        self.lastargs = args  # make persistent for later checks


    def failed(self, reason):
        """Allow reactor iteration loop in test proper to exit and fail test"""
	print 
	print "DEBUG: failed"
        self.done = True
        self.failure = reason
        self.lastargs = None

#----------------------------------------------------------------------	

    def test_hashable(self):
        """Containers need to be hashable"""
        b = Container()
        assert hash(b)


    def test_hashable(self):
        """Comparison for equality"""

        b1 = Container()
        b1.name = 'Device1'
        b2 = copy(b1)
        
        self.assertEqual(b1,b2)


    def test_attributes(self):
        """Can iterate over previously set attributes of container"""

        b = Container()
        b.int = 1234
        b.float = 3.14
        b.string = "sample string"
        


    def test_serializable(self):
        """Confirm containers can travel the wire"""

        b = Container()
        b.name = 'Device'
        b.type = 'PseudoDevice'
        b.description = "A string describing this device"

        # Jelly is the low-level serializer of the twisted framework
        assert jelly(b)


    def test_unique_ids(self):
        """Confirm that reasonably large number of discrete containers all get unique ids"""

        ids = []
        instances = []
        for i in range(1000):
            instance = Container()
            assert instance.id not in ids
            ids.append(instance.id)
            instances.append(instance)


    def test_zzz_echo_tcp(self):
	"""Test container can travel over a TCP connection"""
	# safety timeout
        self.timeout = reactor.callLater(5, self.failed, "Something Bad happened... Bailing")
	
	factory = pb.PBClientFactory()
	reactor.connectTCP("localhost",8800, factory)
	deferred = factory.getRootObject()
	deferred.addCallback(self._got_reference)
	deferred.addErrback(self.failed)

	while self.done is False:
	    reactor.iterate(0.1)

	if self.failure:
	    self.fail(self.failure)	

    def _got_reference(self, remote):
	self.remote = remote
	d = self.remote.callRemote("get_bucket")
	d.addCallback(self.succeeded)
	d.addErrback(self.failed)
class TestConnector(SignalMixin, unittest.TestCase):

    def setUpClass(self):
        """Start a DeviceServer in a child process to test against"""

        # deviceserver startup script directory
        bindir = os.path.join(agdevicecontrol.path, 'bin')

        # keep track of temporary files for deletion in tearDown
        self.tempfiles = []

        # create a temporary deviceserver config file
        filename = 'test_deviceserver.conf'
        fqfilename = bindir + os.sep + filename
        f = open(fqfilename,'w')
        f.write(deviceserver_config_contents)
        f.close()
        self.tempfiles.append(fqfilename)

        # start deviceserver as a child process
        self.process = SubProcessProtocol()
        self.process.waitOnStartUp(['server.py', filename, '-n'], path = bindir)
        if self.process.running is False:
            raise unittest.SkipTest, "DeviceServer didn't start correctly, skipping tests"


    def tearDownClass(self):
        """Stop the DeviceServer running in a child process"""
        print "*** tearDownClass: ", self.process.done
        self.process.waitOnShutDown()

        # clean-up temporary config files
        for f in self.tempfiles:
            os.remove(f)



    def setUp(self):
        """Per test initalization"""
        self.done = False
        self.failure = None

    def tearDown(self):
        """Per test cleanup code"""
        if self.connector:
            self.connector.close()


    def succeeded(self, *args):
        """Allow reactor iteration loop in test proper to exit and pass test"""
        self.done = True
        self.timeout.cancel()  # safety timeout no longer necessary
        self.lastargs = args  # make persistent for later checks


    def failed(self, reason):
        """Allow reactor iteration loop in test proper to exit and fail test"""
        self.done = True
        self.failure = reason
        self.lastargs = None



    def test_unauthorized_connect(self):
        """Should fail to connect (unauthorized)"""

        # safety timeout
        self.timeout = reactor.callLater(10, self.failed, "attempt to connect to DeviceServer timed out ... failing")

        self.connector = Connector('localhost')
        self.connector.connect(callback=self.failed, errback=self.succeeded)
        
        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)

        # paranoia check
        assert self.connector.connected is False




    def test_simple_connect(self):
        """Obtain perspective on DeviceServer"""

        # safety timeout
        self.timeout = reactor.callLater(10, self.failed, "attempt to connect to DeviceServer timed out ... failing")

        self.connector = Connector('localhost')
        self.connector.connect(callback=self.succeeded, errback=self.failed, password='******')
        
        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)

        connector = self.lastargs[0]
        assert connector == self.connector

        # paranoia check
        assert self.connector.connected is True



    def test_connect_to_nonexistent_server(self):
        """Attempt to connect to known non-existent deviceserver"""

        # safety timeout
        self.timeout = reactor.callLater(15, self.failed, "attempt to connect to DeviceServer timed out ... failing")

        self.connector = Connector('localhost', port=9999)  # assumption
        self.connector.connect(callback=self.failed, errback=self.succeeded, password='******')
         
        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
            reactor.iterate(0.1)
            print "self.connector.connected: ", self.connector.connected

        # paranoia check
        assert self.connector.connected is False
 
        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)



    def test_connect_and_execute(self):
        """Connect and issue simple command"""

        # wait for slow, single CPU machine to get twisted going in another thread.
        import time
        time.sleep(1)
        # safety timeout
        self.timeout = reactor.callLater(5, self.failed, "attempt to connect to DeviceServer timed out ... failing")

        self.connector = Connector('localhost')
        self.connector.connect(callback=self.succeeded, errback=self.failed, password='******')
        
        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)


	self.timeout = reactor.callLater(5, self.failed, "Attempt to get devicelist timed out ... failing")

	# get a device key for use in next step
	self.done = False
	self.connector.getDeviceList(self.succeeded, errback=self.failed)

	while not self.done:
	    reactor.iterate(0.1)

	if self.failure:
	    self.fail(self.failure)

	print
	print "DEBUG:"
	print self.lastargs[0][0]
	device = self.lastargs[0][0]
	    

        # safety timeout
        self.timeout = reactor.callLater(5, self.failed, "attempt to getParameter timed out ... failing")

        self.connector.deviceExecute(device, 'getParameter', callback=self.succeeded, errback=self.failed)

        # idle until code above triggers succeeded or timeout causes failure
        self.done = False
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)

        # expected return values
        value, connector, device, command, params = self.lastargs
        assert type(value) == types.IntType
        assert connector == self.connector
        assert device == 'Device1'
        assert command == 'getParameter'
        assert params == None


    def test_connect_and_get_devicemap(self):
        """Connect and retrieve devicemap"""

        # safety timeout
        self.timeout = reactor.callLater(5, self.failed, "attempt to connect to DeviceServer timed out ... failing")

        self.connector = Connector('localhost')
        self.connector.connect(callback=self.succeeded, errback=self.failed, password='******')
         
        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)

        # safety timeout
        self.timeout = reactor.callLater(5, self.failed, "attempt to getDeviceMap timed out ... failing")

        self.connector.getDeviceMap(callback=self.succeeded, errback=self.failed)

        # idle until code above triggers succeeded or timeout causes failure
        self.done = False
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)

        # expected return values
        devmap = self.lastargs[0]
        assert len(devmap) == 1
        assert 'PseudoDevice' in devmap
        assert len(devmap['PseudoDevice']) == 2
        assert 'Device1' in devmap['PseudoDevice']
        assert 'Device2' in devmap['PseudoDevice']



    def test_connect_and_raise_exception(self):
        """Connect and raise pseudodevice error"""

        # safety timeout
        self.timeout = reactor.callLater(5, self.failed, "attempt to connect to DeviceServer timed out ... failing")

        self.connector = Connector('localhost')
        self.connector.connect(callback=self.succeeded, errback=self.failed, password='******')
         
        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)


        # safety timeout
        self.timeout = reactor.callLater(5, self.failed, "attempt to raise remote exception timed out ... failing")
        self.done = False

        self.connector.deviceExecute('Device1', 'raiseException', callback=self.failed, errback=self.succeeded)

        # idle until code above triggers succeeded or timeout causes failure
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            self.fail(self.failure)

        # expecting returnvalue of exception
        # should still be connected ...

        # safety timeout
        self.timeout = reactor.callLater(5, self.failed, "attempt to getDeviceMap timed out ... failing")

        self.connector.getDeviceMap(callback=self.succeeded, errback=self.failed)

        # idle until code above triggers succeeded or timeout causes failure
        self.done = False
        while not self.done:
            reactor.iterate(0.1)

        # will arrive here eventually when either succeeded or failed method has fired
        if self.failure:
            assert connector.connected is False
            self.fail(self.failure)

        # expected return values
        devmap = self.lastargs[0]
        self.assertEqual(self.connector.connected, True)
        

    
    if False:
        test_unauthorized_connect.skip = True
        test_simple_connect.skip = True
        test_connect_to_nonexistent_server.skip = True
        test_connect_and_execute.skip = True
        test_connect_and_get_devicemap.skip = True
        test_connect_and_raise_exception.skip = True