| |
@@ -21,17 +21,18 @@
|
| |
# Written by Jan Kaluza <jkaluza@redhat.com>
|
| |
|
| |
from odcs.server import db, conf
|
| |
+ import odcs.server.backend
|
| |
from odcs.server.models import Compose
|
| |
from odcs.common.types import COMPOSE_STATES, COMPOSE_RESULTS
|
| |
from odcs.server.backend import RemoveExpiredComposesThread
|
| |
from odcs.server.pungi import PungiSourceType
|
| |
from datetime import datetime, timedelta
|
| |
|
| |
- from .utils import ModelsBaseTest
|
| |
+ from .utils import ModelsBaseTest, ConfigPatcher
|
| |
|
| |
import os
|
| |
import mock
|
| |
- from mock import patch
|
| |
+ from mock import patch, MagicMock
|
| |
|
| |
|
| |
class TestRemoveExpiredComposesThread(ModelsBaseTest):
|
| |
@@ -211,3 +212,149 @@
|
| |
self.thread._remove_compose_dir(toplevel_dir)
|
| |
unlink.assert_not_called()
|
| |
rmtree.assert_called_once()
|
| |
+
|
| |
+
|
| |
+ class TestRemoveExpiredComposesThreadPungiRunroot(ModelsBaseTest):
|
| |
+ maxDiff = None
|
| |
+
|
| |
+ def setUp(self):
|
| |
+ super(TestRemoveExpiredComposesThreadPungiRunroot, self).setUp()
|
| |
+
|
| |
+ compose = Compose.create(
|
| |
+ db.session, "unknown", PungiSourceType.MODULE, "testmodule-master",
|
| |
+ COMPOSE_RESULTS["repository"], 60)
|
| |
+ db.session.add(compose)
|
| |
+ db.session.commit()
|
| |
+
|
| |
+ self.config_patcher = ConfigPatcher(odcs.server.backend.conf)
|
| |
+ self.config_patcher.patch("pungi_runroot_enabled", True)
|
| |
+ self.config_patcher.start()
|
| |
+
|
| |
+ self.thread = RemoveExpiredComposesThread()
|
| |
+
|
| |
+ self.patch_make_koji_session = patch("odcs.server.utils.make_koji_session")
|
| |
+ self.make_koji_session = self.patch_make_koji_session.start()
|
| |
+ self.koji_session = MagicMock()
|
| |
+ self.make_koji_session.return_value = self.koji_session
|
| |
+
|
| |
+ self.patch_run_koji_runroot = patch("odcs.server.utils.run_koji_runroot")
|
| |
+ self.run_koji_runroot = self.patch_run_koji_runroot.start()
|
| |
+
|
| |
+ def tearDown(self):
|
| |
+ super(TestRemoveExpiredComposesThreadPungiRunroot, self).tearDown()
|
| |
+ self.config_patcher.stop()
|
| |
+ self.patch_make_koji_session.stop()
|
| |
+
|
| |
+ def _mock_glob(self, glob, dirs):
|
| |
+ glob_ret_values = [[], []]
|
| |
+ for d in dirs:
|
| |
+ path = os.path.join(conf.target_dir, d)
|
| |
+ if d.startswith("latest-"):
|
| |
+ glob_ret_values[0].append(path)
|
| |
+ else:
|
| |
+ glob_ret_values[1].append(path)
|
| |
+ glob.side_effect = glob_ret_values
|
| |
+
|
| |
+ @patch("os.path.isdir")
|
| |
+ @patch("glob.glob")
|
| |
+ def test_remove_left_composes(self, glob, isdir):
|
| |
+ isdir.return_value = True
|
| |
+ self._mock_glob(glob, ["latest-odcs-96-1", "odcs-96-1-20171005.n.0"])
|
| |
+ self.thread.do_work()
|
| |
+
|
| |
+ self.run_koji_runroot.assert_not_called()
|
| |
+
|
| |
+ @patch("os.path.isdir")
|
| |
+ @patch("glob.glob")
|
| |
+ def test_remove_left_composes_not_dir(
|
| |
+ self, glob, isdir):
|
| |
+ isdir.return_value = False
|
| |
+ self._mock_glob(glob, ["latest-odcs-96-1"])
|
| |
+ self.thread.do_work()
|
| |
+ self.run_koji_runroot.assert_not_called()
|
| |
+
|
| |
+ @patch("os.path.isdir")
|
| |
+ @patch("glob.glob")
|
| |
+ def test_remove_left_composes_wrong_dir(
|
| |
+ self, glob, isdir):
|
| |
+ isdir.return_value = True
|
| |
+ self._mock_glob(glob, ["latest-odcs-", "odcs-", "odcs-abc"])
|
| |
+ self.thread.do_work()
|
| |
+ self.run_koji_runroot.assert_not_called()
|
| |
+
|
| |
+ @patch("os.path.isdir")
|
| |
+ @patch("glob.glob")
|
| |
+ def test_remove_left_composes_valid_compose(
|
| |
+ self, glob, isdir):
|
| |
+ isdir.return_value = True
|
| |
+ self._mock_glob(glob, ["latest-odcs-1-1", "odcs-1-1-2017.n.0"])
|
| |
+ c = db.session.query(Compose).filter(Compose.id == 1).one()
|
| |
+ c.state = COMPOSE_STATES["done"]
|
| |
+ db.session.add(c)
|
| |
+ db.session.commit()
|
| |
+ self.thread.do_work()
|
| |
+ self.run_koji_runroot.assert_not_called()
|
| |
+
|
| |
+ @patch("os.path.isdir")
|
| |
+ @patch("glob.glob")
|
| |
+ @patch("os.path.realpath")
|
| |
+ @patch("os.path.exists")
|
| |
+ def test_remove_left_composes_expired_compose(
|
| |
+ self, exists, realpath, glob, isdir):
|
| |
+ exists.return_value = True
|
| |
+ realpath.return_value = "/odcs-real"
|
| |
+ isdir.return_value = True
|
| |
+ self._mock_glob(glob, ["latest-odcs-1-1", "odcs-1-1-2017.n.0"])
|
| |
+ c = db.session.query(Compose).filter(Compose.id == 1).one()
|
| |
+ c.state = COMPOSE_STATES["removed"]
|
| |
+ db.session.add(c)
|
| |
+ db.session.commit()
|
| |
+ self.thread.do_work()
|
| |
+ self.run_koji_runroot.assert_called_once_with(
|
| |
+ self.koji_session,
|
| |
+ ['rm', '-f', os.path.join(conf.target_dir, 'latest-odcs-1-1'), '&&',
|
| |
+ 'rm', '-rf', '/odcs-real', '&&',
|
| |
+ 'rm', '-f', os.path.join(conf.target_dir, 'odcs-1-1-2017.n.0'), '&&',
|
| |
+ 'rm', '-rf', '/odcs-real'])
|
| |
+
|
| |
+ @patch("os.path.realpath")
|
| |
+ @patch("os.path.exists")
|
| |
+ def test_remove_compose_dir_symlink(
|
| |
+ self, exists, realpath):
|
| |
+ exists.return_value = True
|
| |
+ toplevel_dir = "/odcs"
|
| |
+ realpath.return_value = "/odcs-real"
|
| |
+
|
| |
+ cmds = self.thread._get_remove_compose_dir_cmds(toplevel_dir)
|
| |
+ self.assertEqual(
|
| |
+ cmds, ['rm', '-f', '/odcs', '&&', 'rm', '-rf', '/odcs-real'])
|
| |
+
|
| |
+ @patch("shutil.rmtree")
|
| |
+ @patch("os.unlink")
|
| |
+ @patch("os.path.realpath")
|
| |
+ @patch("os.path.exists")
|
| |
+ def test_remove_compose_dir_broken_symlink(
|
| |
+ self, exists, realpath, unlink, rmtree):
|
| |
+ def mocked_exists(p):
|
| |
+ return p != "/odcs-real"
|
| |
+ exists.side_effect = mocked_exists
|
| |
+ toplevel_dir = "/odcs"
|
| |
+ realpath.return_value = "/odcs-real"
|
| |
+
|
| |
+ cmds = self.thread._get_remove_compose_dir_cmds(toplevel_dir)
|
| |
+ self.assertEqual(
|
| |
+ cmds, ['rm', '-f', '/odcs'])
|
| |
+
|
| |
+ @patch("shutil.rmtree")
|
| |
+ @patch("os.unlink")
|
| |
+ @patch("os.path.realpath")
|
| |
+ @patch("os.path.exists")
|
| |
+ def test_remove_compose_dir_real_dir(
|
| |
+ self, exists, realpath, unlink, rmtree):
|
| |
+ exists.return_value = True
|
| |
+ toplevel_dir = "/odcs"
|
| |
+ realpath.return_value = "/odcs"
|
| |
+
|
| |
+ cmds = self.thread._get_remove_compose_dir_cmds(toplevel_dir)
|
| |
+ self.assertEqual(
|
| |
+ cmds, ['rm', '-rf', '/odcs'])
|
| |
make_koji_session
is just moved to utils.py, so we can use it from other parts of ODCS too.