Commit 2f5cac00 authored by Ivan Tyagov's avatar Ivan Tyagov

Merge remote-tracking branch 'origin/feat/end-to-end-testing' into e2e-testing-beremiz

parents 525c02f6 b5231b27
# End To End Testing
This software release is used to run end-to-end test of SlapOS softwares on an actual SlapOS cloud such as Rapid.Space. Since it can supply softwares and request instances on an actual cloud, it needs a SlaPOS client certificate.
Input parameters:
```
{
"client.crt": <content of client.crt>
"client.key": <content of client.key>
"master-url": <url of SlapOS master>
}
```
A convenience script `generate_parameters.py` is provided to compute these parameters in JSON format from an existing SlapOS client configuration:
```
python3 generate_parameters.py --cfg <path to slapos-client.cfg> -o <output path>
```
[instance.cfg]
filename = instance.cfg.in
md5sum = 0e49345c3b7b7988adf2aaa7c666a415
[test_test.py]
filename = test_test.py
md5sum = c074373dbb4154aa924ef5781dade7a0
[test_kvm.py]
filename = test_kvm.py
md5sum = cbaa8e36097f36caf1a377fa71341a09
import argparse
import configparser
import json
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--cfg', required=True)
parser.add_argument('-o', '--output', required=True)
args = parser.parse_args()
configp = configparser.ConfigParser()
configp.read(args.cfg)
with open(configp.get('slapconsole', 'cert_file')) as f:
crt = f.read()
with open(configp.get('slapconsole', 'key_file')) as f:
key = f.read()
url = configp.get('slapos', 'master_url')
with open(args.output, 'w') as f:
json.dump({
'client.crt': crt,
'client.key': key,
'master-url': url
}, f, indent=2)
if __name__ == '__main__':
main()
[buildout]
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
extends =
${nxdtest-instance.cfg:output}
parts =
.nxdtest
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration.serialised
computer = $${slap-connection:computer-id}
partition = $${slap-connection:partition-id}
url = $${slap-connection:server-url}
key = $${slap-connection:key-file}
cert = $${slap-connection:cert-file}
[directory]
recipe = slapos.cookbook:mkdirectory
home = $${buildout:directory}
bin = $${buildout:directory}/bin
etc = $${buildout:directory}/etc
var = $${buildout:directory}/var
cfg = $${buildout:directory}/.slapos
testdir = $${:var}/tests
nxdtestdir = $${:var}/nxdtest
[client.crt]
recipe = slapos.recipe.template
output = $${directory:cfg}/client.crt
inline = $${slap-configuration:configuration.client.crt}
[client.key]
recipe = slapos.recipe.template
output = $${directory:cfg}/client.key
inline = $${slap-configuration:configuration.client.key}
[slapos-client.cfg]
recipe = slapos.recipe.template
output = $${directory:cfg}/slapos-client.cfg
inline =
[slapos]
master_url = $${slap-configuration:configuration.master-url}
[slapconsole]
cert_file = $${client.crt:output}
key_file = $${client.key:output}
[env.sh]
recipe = slapos.recipe.template:jinja2
output = $${directory:cfg}/env.sh
inline =
export HOME=$${directory:home}
[runTestSuite]
# extended from stack/nxdtest
env.sh = $${env.sh:output}
workdir = $${directory:nxdtestdir}
[.nxdtest]
recipe = slapos.recipe.template:jinja2
output = $${runTestSuite:workdir}/.nxdtest
python_for_test = ${python_for_test:executable}
tests =
$${test_test.py:output}
$${test_kvm.py:output}
context =
key tests :tests
key python_for_test :python_for_test
inline =
import os
tests = {{ repr(tests) }}
for test in tests.splitlines():
directory, filename = os.path.split(test)
name, _ = os.path.splitext(filename)
TestCase(
name,
[{{ repr(python_for_test) }} , '-m', 'unittest', '-v', name],
cwd=directory,
summaryf=UnitTest.summary,
)
[test_test.py]
recipe = slapos.recipe.template
output = $${directory:testdir}/test_test.py
url = ${test_test.py:target}
[test_kvm.py]
recipe = slapos.recipe.template
output = $${directory:testdir}/test_kvm.py
url = ${test_kvm.py:target}
[buildout]
extends =
../../component/pygolang/buildout.cfg
../../stack/slapos.cfg
../../stack/nxdtest.cfg
buildout.hash.cfg
parts =
instance.cfg
slapos-cookbook
[instance.cfg]
recipe = slapos.recipe.template
output = ${buildout:directory}/instance.cfg
url = ${:_profile_base_location_}/${:filename}
[test_test.py]
recipe = slapos.recipe.build:download
output = ${buildout:directory}/${:filename}
url = ${:_profile_base_location_}/${:filename}
[test_kvm.py]
recipe = slapos.recipe.build:download
output = ${buildout:directory}/${:filename}
url = ${:_profile_base_location_}/${:filename}
[python_for_test]
<= python-interpreter
interpreter = python_for_test
executable = ${buildout:bin-directory}/${:interpreter}
depends = ${lxml-python:egg}
eggs =
${pygolang:egg}
slapos.core
{
"name": "End-To-End-Testing",
"description": "End-To-End Testing on SlapOS Cloud",
"serialisation": "xml",
"software-type": {
"default": {
"title": "default",
"software-type": "default",
"description": "default"
}
}
}
import configparser
import json
import logging
import time
import unittest
import slapos.client
class EndToEndTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
configp = configparser.ConfigParser()
configp.read('${slapos-client.cfg:output}')
args = type("empty_args", (), {})()
conf = slapos.client.ClientConfig(args, configp)
local = slapos.client.init(conf, logging.getLogger(__name__))
cls.slap = local['slap']
cls.supply = staticmethod(local['supply'])
cls._request = staticmethod(local['request'])
cls.product = staticmethod(local['product'])
cls._requested = {}
@classmethod
def tearDownClass(cls):
for args, kw in cls._requested.values():
kw['state'] = 'destroyed'
cls._request(*args, **kw)
@classmethod
def request(cls, *args, **kw):
instance_name = args[1]
cls._requested[instance_name] = (args, kw)
partition = cls._request(*args, **kw)
return cls.unwrapConnectionDict(partition.getConnectionParameterDict())
@staticmethod
def unwrapConnectionDict(connection_dict):
try:
connection_json = connection_dict['_']
except KeyError:
return connection_dict
return json.loads(connection_json)
@classmethod
def getInstanceInfos(cls, instance_name):
# adapated from cli/info
infos = cls.slap.registerOpenOrder().getInformation(instance_name)
class Infos:
def __init__(self, **kw):
self.__dict__.update(kw)
connection_dict = {
e['connection_key'] : e['connection_value']
for e in infos._connection_dict
}
return Infos(
software_url = infos._software_release_url,
software_type = infos._source_reference,
shared = bool(infos._root_slave),
requested_state = infos._requested_state,
parameter_dict = infos._parameter_dict,
connection_dict = cls.unwrapConnectionDict(connection_dict),
news = infos._news,
)
@classmethod
def getInstanceNews(cls, instance_name):
try:
news = cls.slap.registerOpenOrder().getInformation(instance_name)._news
except Exception:
return ()
return news['instance']
@classmethod
def getInstanceStatus(cls, instance_name):
# adapated from cli/info
status = 0b00
for e in cls.getInstanceNews(instance_name):
text = e.get('text', '')
if text.startswith('#access'):
status |= 0b01
elif text.startswith('#error'):
status |= 0b10
if status == 0b11:
break
return ('none', 'green', 'red', 'orange')[status]
@classmethod
def waitUntilGreen(cls, instance_name, timeout=80):
t0 = time.time()
while (status := cls.getInstanceStatus(instance_name)) != 'green':
msg = 'Instance %s status is still %s' % (instance_name, status)
print(msg)
if (time.time() - t0) > 60 * timeout:
raise TimeoutError(msg)
time.sleep(60)
class KvmTest(EndToEndTestCase):
def test(self):
instance_name = time.strftime('e2e-test-kvm-%Y-%B-%d-%H:%M:%S')
# instance_name = 'e2e-kvm-test' # avoid timestamp to reuse instance
self.request(self.product.kvm, instance_name)
self.waitUntilGreen(instance_name)
connection_dict = self.request(self.product.kvm, instance_name)
self.assertIn('url', connection_dict)
import unittest
class Test(unittest.TestCase):
def test_fail(self):
self.assertEqual(0, 1)
def test_succeed(self):
self.assertEqual(0, 0)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment