diff --git a/software/slapos-master/test/test/test_erp5.py b/software/slapos-master/test/test/test_erp5.py index de0b6b6449ec8cbbfce9fc987bbe829fc81fba29..77e0191bb4689026b582571bfe7c3a51000f432e 100644 --- a/software/slapos-master/test/test/test_erp5.py +++ b/software/slapos-master/test/test/test_erp5.py @@ -47,11 +47,12 @@ class TestPublishedURLIsReachableMixin(object): # What happens is that instanciation just create the services, but does not # wait for ERP5 to be initialized. When this test run ERP5 instance is # instanciated, but zope is still busy creating the site and haproxy replies - # with 503 Service Unavailable. + # with 503 Service Unavailable, sometimes the first request is 404, so we + # retry in a loop. # If we can move the "create site" in slapos node instance, then this retry loop # would not be necessary. for i in range(1, 60): - r = requests.get(url, verify=False) # XXX can we get CA from caucase already ? + r = requests.get(url, verify=False) # XXX can we get CA from caucase already ? if r.status_code in (requests.codes.service_unavailable, requests.codes.not_found): delay = i * 2 @@ -85,6 +86,102 @@ class TestDefaultParameters(ERP5InstanceTestCase, TestPublishedURLIsReachableMix __partition_reference__ = 'defp' +class TestMedusa(ERP5InstanceTestCase, TestPublishedURLIsReachableMixin): + """Test ERP5 Medusa server + """ + __partition_reference__ = 'medusa' + + @classmethod + def getInstanceParameterDict(cls): + return {'_': json.dumps({'wsgi': False})} + + +class TestApacheBalancerPorts(ERP5InstanceTestCase): + """Instanciate with two zope families, this should create for each family: + - a balancer entry point with corresponding haproxy + - a balancer entry point for test runner + """ + __partition_reference__ = 'ap' + + @classmethod + def getInstanceParameterDict(cls): + return { + '_': + json.dumps({ + "zope-partition-dict": { + "family1": { + "instance-count": 3, + "family": "family1" + }, + "family2": { + "instance-count": 5, + "family": "family2" + }, + }, + }) + } + + def checkValidHTTPSURL(self, url): + parsed = urlparse.urlparse(url) + self.assertEqual(parsed.scheme, 'https') + self.assertTrue(parsed.hostname) + self.assertTrue(parsed.port) + + def test_published_family_parameters(self): + # when we request two families, we have two published family-{family_name} URLs + param_dict = self.getRootPartitionConnectionParameterDict() + for family_name in ('family1', 'family2'): + self.checkValidHTTPSURL( + param_dict['family-{family_name}'.format(family_name=family_name)]) + self.checkValidHTTPSURL( + param_dict['family-{family_name}-v6'.format(family_name=family_name)]) + + def test_published_test_runner_url(self): + # each family's also a list of test test runner URLs, by default 3 per family + param_dict = self.getRootPartitionConnectionParameterDict() + for family_name in ('family1', 'family2'): + family_test_runner_url_list = param_dict[ + '{family_name}-test-runner-url-list'.format(family_name=family_name)] + self.assertEqual(3, len(family_test_runner_url_list)) + for url in family_test_runner_url_list: + self.checkValidHTTPSURL(url) + + def test_zope_listen(self): + # we requested 3 zope in family1 and 5 zopes in family2, we should have 8 zope running. + with self.slap.instance_supervisor_rpc as supervisor: + all_process_info = supervisor.getAllProcessInfo() + self.assertEqual( + 3 + 5, + len([p for p in all_process_info if p['name'].startswith('zope-')])) + + def test_apache_listen(self): + # We have 2 families, apache should listen to a total of 3 ports per family + # normal access on ipv4 and ipv6 and test runner access on ipv4 only + with self.slap.instance_supervisor_rpc as supervisor: + all_process_info = supervisor.getAllProcessInfo() + process_info, = [p for p in all_process_info if p['name'] == 'apache'] + apache_process = psutil.Process(process_info['pid']) + self.assertEqual( + sorted([socket.AF_INET] * 4 + [socket.AF_INET6] * 2), + sorted([ + c.family + for c in apache_process.connections() + if c.status == 'LISTEN' + ])) + + def test_haproxy_listen(self): + # There is one haproxy per family + with self.slap.instance_supervisor_rpc as supervisor: + all_process_info = supervisor.getAllProcessInfo() + process_info, = [ + p for p in all_process_info if p['name'].startswith('haproxy-') + ] + haproxy_process = psutil.Process(process_info['pid']) + self.assertEqual([socket.AF_INET, socket.AF_INET], [ + c.family for c in haproxy_process.connections() if c.status == 'LISTEN' + ]) + + class TestDisableTestRunner(ERP5InstanceTestCase, TestPublishedURLIsReachableMixin): """Test ERP5 can be instanciated without test runner. """ @@ -98,9 +195,114 @@ class TestDisableTestRunner(ERP5InstanceTestCase, TestPublishedURLIsReachableMix """ # self.computer_partition_root_path is the path of root partition. # we want to assert that no scripts exist in any partition. - bin_programs = [os.path.basename(path) for path in - glob.glob("{}/../*/bin/*".format(self.computer_partition_root_path))] + bin_programs = map(os.path.basename, + glob.glob(self.computer_partition_root_path + "/../*/bin/*")) self.assertTrue(bin_programs) # just to check the glob was correct. self.assertNotIn('runUnitTest', bin_programs) self.assertNotIn('runTestSuite', bin_programs) + + def test_no_apache_testrunner_port(self): + # Apache only listen on two ports, there is no apache ports allocated for test runner + with self.slap.instance_supervisor_rpc as supervisor: + all_process_info = supervisor.getAllProcessInfo() + process_info, = [p for p in all_process_info if p['name'] == 'apache'] + apache_process = psutil.Process(process_info['pid']) + self.assertEqual( + sorted([socket.AF_INET, socket.AF_INET6]), + sorted( + c.family + for c in apache_process.connections() + if c.status == 'LISTEN' + )) + +class TestZopeNodeParameterOverride(ERP5InstanceTestCase, TestPublishedURLIsReachableMixin): + """Test override zope node parameters + """ + __partition_reference__ = 'override' + + @classmethod + def getInstanceParameterDict(cls): + # The following example includes the most commonly used options, + # but not necessarily in a meaningful way. + return {'_': json.dumps({ + "zodb": [{ + "type": "zeo", + "server": {}, + "cache-size-bytes": "20MB", + "cache-size-bytes!": [ + ("bb-0", 1<<20), + ("bb-.*", "500MB"), + ], + "pool-timeout": "10m", + "storage-dict": { + "cache-size!": [ + ("a-.*", "50MB"), + ], + }, + }], + "zope-partition-dict": { + "a": { + "instance-count": 3, + }, + "bb": { + "instance-count": 5, + "port-base": 2300, + }, + }, + })} + + def test_zope_conf(self): + zeo_addr = json.loads( + self.getComputerPartition('zodb').getConnectionParameter('_') + )["storage-dict"]["root"]["server"] + + def checkParameter(line, kw): + k, v = line.split() + self.assertFalse(k.endswith('!'), k) + try: + expected = kw.pop(k) + except KeyError: + if k == 'server': + return + self.assertIsNotNone(expected) + self.assertEqual(str(expected), v) + + def checkConf(zodb, storage): + zodb["mount-point"] = "/" + zodb["pool-size"] = 4 + zodb["pool-timeout"] = "10m" + storage["storage"] = "root" + storage["server"] = zeo_addr + with open('%s/etc/zope-%s.conf' % (partition, zope)) as f: + conf = map(str.strip, f.readlines()) + i = conf.index("<zodb_db root>") + 1 + conf = iter(conf[i:conf.index("</zodb_db>", i)]) + for line in conf: + if line == '<zeoclient>': + for line in conf: + if line == '</zeoclient>': + break + checkParameter(line, storage) + for k, v in storage.iteritems(): + self.assertIsNone(v, k) + del storage + else: + checkParameter(line, zodb) + for k, v in zodb.iteritems(): + self.assertIsNone(v, k) + + partition = self.getComputerPartitionPath('zope-a') + for zope in xrange(3): + checkConf({ + "cache-size-bytes": "20MB", + }, { + "cache-size": "50MB", + }) + partition = self.getComputerPartitionPath('zope-bb') + for zope in xrange(5): + checkConf({ + "cache-size-bytes": "500MB" if zope else 1<<20, + }, { + "cache-size": None, + })