blob: 12d6d69b5fdd312b426831fc1239a384c0362ebb [file] [log] [blame]
# 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)