| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| from ming.odm import session, Mapper, ThreadLocalODMSession |
| from mock import patch |
| from tg import app_globals as g |
| |
| from alluratest.controller import TestController |
| from allura.tests.decorators import audits, out_audits, with_user_project |
| from allura import model as M |
| from allura.scripts import delete_projects |
| from allura.lib import plugin |
| from alluratest.pytest_helpers import with_nose_compatibility |
| |
| |
| @with_nose_compatibility |
| class TestDeleteProjects(TestController): |
| |
| def setup_method(self, method): |
| super().setup_method(method) |
| n = M.Neighborhood.query.get(name='Projects') |
| admin = M.User.by_username('test-admin') |
| self.p_shortname = 'test-delete' |
| self.proj = n.register_project(self.p_shortname, admin) |
| |
| def run_script(self, options): |
| cls = delete_projects.DeleteProjects |
| opts = cls.parser().parse_args(options) |
| cls.execute(opts) |
| |
| def things_related_to_project(self, pid): |
| result = [] |
| ac_ids = [ac._id for ac in M.AppConfig.query.find(dict(project_id=pid))] |
| for m in Mapper.all_mappers(): |
| cls = m.mapped_class |
| things = None |
| if 'project_id' in m.property_index: |
| things = cls.query.find(dict(project_id=pid)).all() |
| elif 'app_config_id' in m.property_index: |
| things = cls.query.find(dict(app_config_id={'$in': ac_ids})).all() |
| if things: |
| result.extend(things) |
| return result |
| |
| def test_project_is_deleted(self): |
| p = M.Project.query.get(shortname=self.p_shortname) |
| assert p is not None, 'Can not find project to delete' |
| self.run_script([f'p/{p.shortname}']) |
| session(p).expunge(p) |
| p = M.Project.query.get(shortname=p.shortname) |
| assert p is None, 'Project is not deleted' |
| |
| def test_artifacts_are_deleted(self): |
| pid = M.Project.query.get(shortname=self.p_shortname)._id |
| things = self.things_related_to_project(pid) |
| assert len(things) > 0, 'No things related to project to begin with' |
| self.run_script([f'p/{self.p_shortname}']) |
| things = self.things_related_to_project(pid) |
| assert len(things) == 0, 'Not all things are deleted: %s' % things |
| |
| def test_subproject_is_deleted(self): |
| p = M.Project.query.get(shortname='test/sub1') |
| assert p is not None, 'Can not find subproject to delete' |
| self.run_script(['p/test/sub1']) |
| session(p).expunge(p) |
| p = M.Project.query.get(shortname='test/sub1') |
| assert p is None, 'Project is not deleted' |
| p = M.Project.query.get(shortname='test') |
| assert p is not None, 'Parent project should not be deleted' |
| |
| def test_subproject_artifacts_are_deleted(self): |
| parent_pid = M.Project.query.get(shortname='test')._id |
| pid = M.Project.query.get(shortname='test/sub1')._id |
| things = self.things_related_to_project(pid) |
| assert len(things) > 0, 'No things related to subproject to begin with' |
| parent_things_before = self.things_related_to_project(parent_pid) |
| self.run_script(['p/test/sub1']) |
| things = self.things_related_to_project(pid) |
| assert len(things) == 0, 'Not all things are deleted: %s' % things |
| parent_things_after = self.things_related_to_project(parent_pid) |
| assert len(parent_things_before) == len(parent_things_after) |
| |
| @patch('allura.lib.plugin.solr_del_project_artifacts', autospec=True) |
| def test_solr_index_is_deleted(self, del_solr): |
| pid = M.Project.query.get(shortname=self.p_shortname)._id |
| self.run_script([f'p/{self.p_shortname}']) |
| del_solr.post.assert_called_once_with(pid) |
| |
| @with_user_project('test-user') |
| @patch('allura.model.auth.request') |
| @patch('allura.lib.helpers.request') |
| def test_userproject_does_disable(self, req, req2): |
| req.remote_addr = None |
| req.user_agent = 'MozFoo' |
| req2.url = None |
| self.run_script(['u/test-user']) |
| assert M.User.by_username('test-user').disabled |
| |
| @patch.object(plugin.g, 'post_event', autospec=True) |
| def test_event_is_fired(self, post_event): |
| pid = M.Project.query.get(shortname=self.p_shortname)._id |
| self.run_script([f'p/{self.p_shortname}']) |
| post_event.assert_called_once_with('project_deleted', project_id=pid, reason=None) |
| |
| @patch.object(plugin.g, 'post_event', autospec=True) |
| @patch('allura.scripts.delete_projects.log', autospec=True) |
| def test_delete_with_reason(self, log, post_event): |
| p = M.Project.query.get(shortname=self.p_shortname) |
| pid = p._id |
| assert p is not None, 'Can not find project to delete' |
| self.run_script(['-r', 'The Reason¢¢', f'p/{p.shortname}']) |
| session(p).expunge(p) |
| p = M.Project.query.get(shortname=p.shortname) |
| assert p is None, 'Project is not deleted' |
| log.info.assert_called_once_with('Purging %s Reason: %s', '/p/test-delete/', 'The Reason¢¢') |
| post_event.assert_called_once_with('project_deleted', project_id=pid, reason='The Reason¢¢') |
| |
| def _disable_users(self, disable): |
| dev = M.User.by_username('test-user') |
| self.proj.add_user(dev, ['Developer']) |
| ThreadLocalODMSession.flush_all() |
| g.credentials.clear() |
| proj = f'p/{self.p_shortname}' |
| msg = f'Account disabled because project /{proj} is deleted. Reason: The Reason' |
| opts = ['-r', 'The Reason', proj] |
| if disable: |
| opts.insert(0, '--disable-users') |
| _audit = audits if disable else out_audits |
| with _audit(msg, user=True): |
| self.run_script(opts) |
| admin = M.User.by_username('test-admin') |
| dev = M.User.by_username('test-user') |
| assert admin.disabled is disable |
| assert dev.disabled is disable |
| |
| @patch('allura.model.auth.request') |
| @patch('allura.lib.helpers.request') |
| def test_disable_users(self, req, req2): |
| req.remote_addr = None |
| req.user_agent = 'MozFoo' |
| req2.url = None |
| self._disable_users(disable=True) |
| |
| def test_not_disable_users(self): |
| self._disable_users(disable=False) |