import json import os from unittest.mock import patch, call, mock_open from spoc import app from spoc import config TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), 'test_data') with open(os.path.join(TEST_DATA_DIR, 'repository.json'), encoding='utf-8') as f: MOCK_REPODATA = json.load(f) MOCK_ENV = 'RAILS_ENV=test\n' \ 'POSTGRES_PASSWORD=asdf=1234\n' \ 'SOMEKEY=someval\n' MOCK_ENV_DATA = { 'RAILS_ENV': 'test', 'POSTGRES_PASSWORD': 'asdf=1234', 'SOMEKEY': 'someval', } def test_init(): instance = app.App('someapp') assert instance.app_name == 'someapp' assert instance.env_file == os.path.join(config.DATA_DIR, 'someapp.env') @patch('spoc.repo.get_apps', return_value=MOCK_REPODATA) def test_get_definition(repo_get_apps): instance = app.App('someapp') definition = instance.get_definition() assert definition == MOCK_REPODATA['someapp'] repo_get_apps.assert_called_once() @patch('spoc.repo.get_apps') @patch('builtins.open', new_callable=mock_open, read_data=json.dumps(MOCK_REPODATA['someapp'])) def test_get_definition_from_file(file_open, repo_get_apps): instance = app.App('someapp') definition = instance.get_definition('somefile') assert definition == MOCK_REPODATA['someapp'] file_open.assert_called_once_with('somefile', encoding='utf-8') repo_get_apps.assert_not_called() @patch('spoc.app.App.get_definition', return_value=MOCK_REPODATA['someapp']) @patch('spoc.app.App.get_existing_volumes', return_value=set('somevol')) @patch('spoc.app.App.remove_volumes') @patch('spoc.app.App.create_volumes') @patch('spoc.app.App.read_env_vars') @patch('spoc.app.App.write_env_vars') @patch('spoc.app.App.create_pod') @patch('spoc.app.App.create_containers') def test_install(create_containers, create_pod, write_env_vars, #pylint: disable=too-many-arguments read_env_vars, create_volumes, remove_volumes, get_existing_volumes, get_definition): instance = app.App('someapp') instance.install() get_definition.assert_called_once() get_existing_volumes.assert_called_once() remove_volumes.assert_called_once_with(set('somevol')) create_volumes.assert_called_once_with(set(('migrate', 'storage', 'uploads', 'postgres-data'))) read_env_vars.assert_not_called() write_env_vars.assert_called_once_with(MOCK_REPODATA['someapp']['environment']) create_pod.assert_called_once_with('0.23.5-210416') create_containers.assert_called_once_with(MOCK_REPODATA['someapp']['containers']) @patch('spoc.app.App.get_definition', return_value=MOCK_REPODATA['someapp']) @patch('spoc.app.App.get_existing_volumes', return_value=set(('somevol', 'migrate', 'storage'))) @patch('spoc.app.App.remove_volumes') @patch('spoc.app.App.create_volumes') @patch('spoc.app.App.read_env_vars', return_value=MOCK_ENV_DATA) @patch('spoc.app.App.write_env_vars') @patch('spoc.app.App.create_pod') @patch('spoc.app.App.create_containers') def test_update(create_containers, create_pod, write_env_vars, #pylint: disable=too-many-arguments read_env_vars, create_volumes, remove_volumes, get_existing_volumes, get_definition): instance = app.App('someapp') instance.update(from_file='somefile') get_definition.assert_called_once() get_existing_volumes.assert_called_once() remove_volumes.assert_called_once_with(set(('somevol',))) create_volumes.assert_called_once_with(set(('uploads', 'postgres-data'))) read_env_vars.assert_called_once() expected_env_data = MOCK_REPODATA['someapp']['environment'].copy() expected_env_data.update(MOCK_ENV_DATA) del expected_env_data['SOMEKEY'] write_env_vars.assert_called_once_with(expected_env_data) create_pod.assert_called_once_with('0.23.5-210416') create_containers.assert_called_once_with(MOCK_REPODATA['someapp']['containers']) @patch('spoc.autostart.set_app') @patch('spoc.app.App.remove_pod') @patch('spoc.app.App.remove_env_vars') @patch('spoc.app.App.get_existing_volumes', return_value=set(('somevol', 'anothervol'))) @patch('spoc.app.App.remove_volumes') def test_uninstall(remove_volumes, get_existing_volumes, remove_env_vars, remove_pod, autostart): instance = app.App('someapp') instance.uninstall() autostart.assert_called_with('someapp', False) remove_pod.assert_called_once() remove_env_vars.assert_called_once() get_existing_volumes.assert_called_once() remove_volumes.assert_called_once_with(set(('somevol', 'anothervol'))) @patch('spoc.podman.remove_pod') @patch('spoc.podman.create_pod') def test_create_pod(create_pod, remove_pod): instance = app.App('someapp') instance.create_pod('0.1') remove_pod.assert_called_once_with('someapp') create_pod.assert_called_once_with('someapp', '0.1') @patch('spoc.podman.remove_pod') def test_remove_pod(remove_pod): instance = app.App('someapp') instance.remove_pod() remove_pod.assert_called_once_with('someapp') @patch('builtins.open', new_callable=mock_open, read_data=MOCK_ENV) def test_read_env_vars(env_open): instance = app.App('someapp') env_vars = instance.read_env_vars() env_file = os.path.join(config.DATA_DIR, 'someapp.env') env_open.assert_called_once_with(env_file, encoding='utf-8') assert env_vars == MOCK_ENV_DATA @patch('builtins.open', side_effect=FileNotFoundError('someapp.env')) def test_read_env_vars_filenotfound(env_open): instance = app.App('someapp') env_vars = instance.read_env_vars() env_file = os.path.join(config.DATA_DIR, 'someapp.env') env_open.assert_called_once_with(env_file, encoding='utf-8') assert not env_vars @patch('os.makedirs') @patch('builtins.open', new_callable=mock_open) def test_write_env_vars(env_open, makedirs): instance = app.App('someapp') instance.write_env_vars(MOCK_ENV_DATA) makedirs.assert_called_once_with(config.DATA_DIR, exist_ok=True) env_file = os.path.join(config.DATA_DIR, 'someapp.env') env_open.assert_called_once_with(env_file, 'w', encoding='utf-8') expected_writes = [call(line) for line in MOCK_ENV.splitlines(True)] env_open().write.assert_has_calls(expected_writes, any_order=True) @patch('os.unlink') def test_remove_env_vars(unlink): instance = app.App('someapp') instance.remove_env_vars() env_file = os.path.join(config.DATA_DIR, 'someapp.env') unlink.assert_called_once_with(env_file) @patch('os.unlink', side_effect=FileNotFoundError('someapp.env')) def test_remove_env_vars_filenotfound(unlink): instance = app.App('someapp') instance.remove_env_vars() env_file = os.path.join(config.DATA_DIR, 'someapp.env') unlink.assert_called_once_with(env_file) @patch('spoc.podman.get_volumes_for_app', return_value={'someapp-vol1', 'someapp-vol2'}) def test_get_existing_volumes(get_volume_names): instance = app.App('someapp') volumes = instance.get_existing_volumes() get_volume_names.assert_called_once_with('someapp') assert volumes == {'vol1', 'vol2'} @patch('spoc.app.App.create_volume') def test_create_volumes(create_volume): instance = app.App('someapp') instance.create_volumes({'vol1', 'vol2'}) create_volume.assert_has_calls([ call('vol1'), call('vol2'), ], any_order=True) @patch('spoc.app.App.remove_volume') def test_remove_volumes(remove_volume): instance = app.App('someapp') instance.remove_volumes({'vol1', 'vol2'}) remove_volume.assert_has_calls([ call('vol1'), call('vol2'), ], any_order=True) @patch('spoc.podman.create_volume') def test_create_volume(create_volume): instance = app.App('someapp') instance.create_volume('vol1') create_volume.assert_called_once_with('someapp', 'someapp-vol1') @patch('spoc.podman.remove_volume') def test_remove_volume(remove_volume): instance = app.App('someapp') instance.remove_volume('vol1') remove_volume.assert_called_once_with('someapp-vol1') @patch('spoc.app.App.create_container') def test_create_containers(create_container): instance = app.App('someapp') definitions = MOCK_REPODATA['someapp']['containers'] instance.create_containers(definitions) # Ordered by dependency create_container.assert_has_calls([ call('postgres', definitions['postgres'], {'someapp', 'postgres'}), call('someapp', definitions['someapp'], {'someapp', 'postgres'}), ]) @patch('spoc.podman.create_container') def test_create_container(create_container): instance = app.App('someapp') definition = MOCK_REPODATA['someapp']['containers']['someapp'] instance.create_container('someapp', definition, {'someapp', 'postgres'}) env_file = os.path.join(config.DATA_DIR, 'someapp.env') volumes = {'someapp-migrate': '/srv/app/db/migrate', 'someapp-storage': '/srv/app/storage', 'someapp-uploads': '/srv/app/public/uploads'} create_container.assert_called_once_with('someapp', 'someapp-someapp', 'example.com/someapp:0.23.6-210515', env_file=env_file, volumes=volumes, requires={'someapp-postgres'}, hosts={'someapp', 'postgres'}) @patch('spoc.app.App') def test_module_install(instance): app.install('someapp') instance.assert_called_once_with('someapp') instance.return_value.install.assert_called_once_with(from_file=None) @patch('spoc.app.App') def test_module_update(instance): app.update('someapp', from_file='somefile') instance.assert_called_once_with('someapp') instance.return_value.update.assert_called_once_with(from_file='somefile') @patch('spoc.app.App') def test_module_uninstall(instance): app.uninstall('someapp') instance.assert_called_once_with('someapp') instance.return_value.uninstall.assert_called_once()