Commit 2a6d87b3 authored by Jérome Perrin's avatar Jérome Perrin

plantuml: test for software release

parent 6c3076a7
Tests for PlantUML software release
┌───┐ ┌─────┐
│Bob│ │Alice│
└─┬─┘ └──┬──┘
│ hello │
│──────────────>│
│ │
│ Go Away │
│<──────────────│
┌─┴─┐ ┌──┴──┐
│Bob│ │Alice│
└───┘ └─────┘
##############################################################################
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from setuptools import setup, find_packages
import glob
import os
version = '0.0.1.dev0'
name = 'slapos.test.plantuml'
long_description = open("README.md").read()
setup(name=name,
version=version,
description="Test for SlapOS' PlantUML",
long_description=long_description,
long_description_content_type='text/markdown',
maintainer="Nexedi",
maintainer_email="info@nexedi.com",
url="https://lab.nexedi.com/nexedi/slapos",
packages=find_packages(),
install_requires=[
'slapos.core',
'slapos.libnetworkcache',
'erp5.util',
'supervisor',
'psutil',
'plantuml',
'requests'
],
zip_safe=True,
test_suite='test',
)
##############################################################################
# coding: utf-8
#
# Copyright (c) 2018 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import textwrap
import hashlib
from io import BytesIO
from PIL import Image
import requests
import plantuml
import utils
# for development: debugging logs and install Ctrl+C handler
if os.environ.get('DEBUG'):
import logging
logging.basicConfig(level=logging.DEBUG)
import unittest
unittest.installHandler()
class PlantUMLTestCase(utils.SlapOSInstanceTestCase):
@classmethod
def getSoftwareURLList(cls):
return (os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'software.cfg')), )
class TestSimpleDiagram(PlantUMLTestCase):
def setUp(self):
self.url = self.computer_partition.getConnectionParameterDict()["url"]
self.plantuml = plantuml.PlantUML(
url='{}/png/'.format(self.url),
http_opts={"disable_ssl_certificate_validation": True}
)
def assertImagesSimilar(self, i1, i2, tolerance=5):
"""Assert images difference between images is less than `tolerance` %.
taken from https://rosettacode.org/wiki/Percentage_difference_between_images
"""
pairs = zip(i1.getdata(), i2.getdata())
if len(i1.getbands()) == 1:
# for gray-scale jpegs
dif = sum(abs(p1-p2) for p1,p2 in pairs)
else:
dif = sum(abs(c1-c2) for p1,p2 in pairs for c1,c2 in zip(p1,p2))
ncomponents = i1.size[0] * i1.size[1] * 3
self.assertLessEqual((dif / 255.0 * 100) / ncomponents, tolerance)
def assertImagesSame(self, i1, i2):
"""Assert images are exactly same."""
self.assertImagesSimilar(i1, i2, 0)
def test_sequence_diagram(self):
png = self.plantuml.processes(textwrap.dedent("""\
@startuml
Bob -> Alice : hello
Alice -> Bob : Go Away
@enduml
"""))
# we cannot just compare the hash of the image against a reference that can be found with
# http://www.plantuml.com/plantuml/png/SoWkIImgAStDuNBAJrBGjLDmpCbCJbMmKiX8pSd9vuBmWC8WMIi5ztm5n_B4IYw7rBmKe1u0
# because plantuml include information about the server in the output image metadata ( you can
# use http://exif.regex.info/exif.cgi to see metadata )
# So we process the image to remove metadata.
reference = Image.open(os.path.join(os.path.dirname(__file__), "data", "test_sequence_diagram.png"))
self.assertImagesSame(Image.open(BytesIO(png)), reference)
def test_class_diagram(self):
"""Class diagram require a working graphviz installation"""
png = self.plantuml.processes(textwrap.dedent("""\
@startuml
class Car
Driver - Car : drives >
Car *- Wheel : have 4 >
Car -- Person : < owns
@enduml
"""))
# rendering is not exactly same on class diagrams, because of fonts and maybe also something in graphviz.
# We just compare that image are similar.
# http://www.plantuml.com/plantuml/png/SoWkIImgAStDuKhEIImkLd1EBEBYSYdAB4ijKj05yHIi5590t685EouGLqjN8JmZDJK7A9wHM9QgO08LrzLL24WjAixF0qhOAEINvnLpSJcavgK0ZGO0
reference = Image.open(os.path.join(os.path.dirname(__file__), "data", "test_class_diagram.png"))
self.assertImagesSimilar(Image.open(BytesIO(png)), reference)
def test_fonts(self):
"""Test slapos provided fonts are used"""
png = self.plantuml.processes(textwrap.dedent("""\
@startuml
listfonts 私は申し訳ありません:私は日本語を話さない。Je ne parle pas japonais.
@enduml
"""))
# URL on the reference implementation would be
# http://www.plantuml.com/plantuml/png/SoWkIImgAStDuSh9B2v9oyyhALPulhpnSUFwvrCsFswS_c85a6nwtDJrk77VuyRPZviclzyp2wBWsVIbp-QiUR5gtkEcIIzMRdpSEFLnuwh7ZIsF6vgyKXNoKXKA4ejoG6InGbPYGNvUOcQn7fT3QbuAq3O0
# but we don't have same fonts, so we compare against the fonts of a slapos instance.
reference = Image.open(os.path.join(os.path.dirname(__file__), "data", "test_fonts.png"))
self.assertImagesSimilar(Image.open(BytesIO(png)), reference)
def test_editor(self):
"""Test the embedded editor"""
r = requests.get('{}/uml/'.format(self.url), verify=False)
self.assertEqual(r.status_code, requests.codes.ok)
def test_svg(self):
"""Test svg rendering"""
image_key = plantuml.deflate_and_encode(textwrap.dedent("""\
@startuml
Bob -> Alice : hello
Alice -> Bob : Go Away
@enduml
"""))
svg = requests.get('{}/svg/{}'.format(self.url, image_key), verify=False).text
self.assertIn('<?xml version="1.0" encoding="UTF-8"', svg)
def test_ascii_art(self):
"""Test ascii art rendering"""
image_key = plantuml.deflate_and_encode(textwrap.dedent("""\
@startuml
Bob -> Alice : hello
Alice -> Bob : Go Away
@enduml
"""))
aa = requests.get('{}/txt/{}'.format(self.url, image_key), verify=False).content
with open(os.path.join(os.path.dirname(__file__), "data", "test_ascii_art.txt"), 'rb') as reference:
self.assertEqual(aa, reference.read())
class ServicesTestCase(PlantUMLTestCase):
@staticmethod
def generateHashFromFiles(file_list):
hasher = hashlib.md5()
for path in file_list:
with open(path, 'r') as afile:
buf = afile.read()
hasher.update("%s\n" % len(buf))
hasher.update(buf)
hash = hasher.hexdigest()
return hash
def test_hashes(self):
hash_files = [
'software_release/buildout.cfg',
'var/tomcat/conf/server.xml'
]
expected_process_names = [
'tomcat-instance-{hash}-on-watch',
]
supervisor = self.getSupervisorRPCServer().supervisor
process_names = [process['name']
for process in supervisor.getAllProcessInfo()]
hash_files = [os.path.join(self.computer_partition_root_path, path)
for path in hash_files]
for name in expected_process_names:
h = ServicesTestCase.generateHashFromFiles(hash_files)
expected_process_name = name.format(hash=h)
self.assertIn(expected_process_name, process_names)
This diff is collapsed.
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