blob: d2f42bf10583cf3830723448f8eb65b82dbb03a6 [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 pylons import tmpl_context as c
from datadiff.tools import assert_equal
from nose.tools import assert_not_equal
from mock import patch
from tg import config
from allura.lib import helpers as h
from allura.tests import decorators as td
from allura import model as M
from alluratest.controller import TestRestApiBase
from forgetracker import model as TM
class TestTrackerApiBase(TestRestApiBase):
def setUp(self):
super(TestTrackerApiBase, self).setUp()
self.setup_with_tools()
@td.with_tool('test', 'Tickets', 'bugs',
TicketMonitoringEmail='test@localhost',
TicketMonitoringType='AllTicketChanges')
def setup_with_tools(self):
h.set_context('test', 'bugs', neighborhood='Projects')
self.tracker_globals = c.app.globals
def create_ticket(self, summary=None, status=None):
return self.api_post(
'/rest/p/test/bugs/new',
wrap_args='ticket_form',
params=dict(
summary=summary or 'test new ticket',
status=self.tracker_globals.open_status_names.split()[0],
labels='',
description='',
assigned_to='',
**{'custom_fields._milestone': ''}),
status=status)
class TestRestNewTicket(TestTrackerApiBase):
def test_new_ticket(self):
summary = 'test new ticket'
ticket_view = self.api_post(
'/rest/p/test/bugs/new',
wrap_args='ticket_form',
params=dict(
summary=summary,
status=self.tracker_globals.open_status_names.split()[0],
labels='foo,bar',
description='descr',
assigned_to='',
**{'custom_fields._milestone': ''}
))
json = ticket_view.json['ticket']
assert json['status'] == 'open', json
assert json['summary'] == 'test new ticket', json
assert json['reported_by'] == 'test-admin'
assert json['labels'] == ['foo', 'bar'], json
assert json['description'] == 'descr', json
assert json['private'] == False, json
def test_invalid_ticket(self):
self.app.get('/rest/p/test/bugs/2', status=404)
def test_create_limit(self):
self.create_ticket(summary='First ticket')
# Set rate limit to unlimit
with h.push_config(config, **{'forgetracker.rate_limits': '{}'}):
summary = 'Second ticket'
self.create_ticket(summary=summary)
t = TM.Ticket.query.get(summary=summary)
assert_not_equal(t, None)
# Set rate limit to 1 in first hour of project
with h.push_config(config, **{'forgetracker.rate_limits': '{"3600": 1}'}):
summary = 'Third ticket'
self.create_ticket(summary=summary, status=429)
t = TM.Ticket.query.get(summary=summary)
assert_equal(t, None)
class TestRestUpdateTicket(TestTrackerApiBase):
def setUp(self):
super(TestRestUpdateTicket, self).setUp()
ticket_view = self.create_ticket()
self.ticket_args = ticket_view.json['ticket']
def test_update_ticket(self):
args = dict(self.ticket_args, summary='test update ticket', labels='',
assigned_to=self.ticket_args['assigned_to_id'] or '')
for bad_key in ('ticket_num', 'assigned_to_id', 'created_date',
'reported_by', 'reported_by_id', '_id', 'votes_up', 'votes_down'):
del args[bad_key]
args['private'] = str(args['private'])
args['discussion_disabled'] = str(args['discussion_disabled'])
ticket_view = self.api_post(
'/rest/p/test/bugs/1/save', wrap_args='ticket_form', params=h.encode_keys(args))
assert ticket_view.status_int == 200, ticket_view.showbrowser()
json = ticket_view.json['ticket']
assert int(json['ticket_num']) == 1
assert json['summary'] == 'test update ticket', json
class TestRestIndex(TestTrackerApiBase):
def setUp(self):
super(TestRestIndex, self).setUp()
self.create_ticket()
def test_ticket_index(self):
tickets = self.api_get('/rest/p/test/bugs/')
assert len(tickets.json['tickets']) == 1, tickets.json
assert (tickets.json['tickets'][0]
== dict(ticket_num=1, summary='test new ticket')), tickets.json['tickets'][0]
assert tickets.json['tracker_config'][
'options']['mount_point'] == 'bugs'
assert tickets.json['tracker_config']['options'][
'TicketMonitoringType'] == 'AllTicketChanges'
assert not tickets.json['tracker_config']['options']['EnableVoting']
assert tickets.json['tracker_config']['options'][
'TicketMonitoringEmail'] == 'test@localhost'
assert tickets.json['tracker_config'][
'options']['mount_label'] == 'Tickets'
assert tickets.json['saved_bins'][0]['sort'] == 'mod_date_dt desc'
assert tickets.json['saved_bins'][0][
'terms'] == '!status:wont-fix && !status:closed'
assert tickets.json['saved_bins'][0]['summary'] == 'Changes'
assert len(tickets.json['saved_bins'][0]) == 4
assert tickets.json['milestones'][0]['name'] == '1.0'
assert tickets.json['milestones'][1]['name'] == '2.0'
def test_ticket_index_noauth(self):
tickets = self.api_get('/rest/p/test/bugs', user='*anonymous')
assert 'TicketMonitoringEmail' not in tickets.json[
'tracker_config']['options']
# make sure it didn't get removed from the db too
ticket_config = M.AppConfig.query.get(
project_id=c.project._id, tool_name='tickets')
assert_equal(ticket_config.options.get('TicketMonitoringEmail'),
'test@localhost')
@td.with_tool('test', 'Tickets', 'dummy')
def test_move_ticket_redirect(self):
p = M.Project.query.get(shortname='test')
dummy_tracker = p.app_instance('dummy')
self.app.post(
'/p/test/bugs/1/move',
params={'tracker': str(dummy_tracker.config._id)}).follow()
ticket = self.api_get('/rest/p/test/bugs/1/')
assert_equal(ticket.request.path, '/rest/p/test/dummy/1/')
class TestRestDiscussion(TestTrackerApiBase):
def setUp(self):
super(TestRestDiscussion, self).setUp()
ticket_view = self.create_ticket()
self.ticket_args = ticket_view.json['ticket']
def test_post(self):
r = self.api_get('/rest/p/test/bugs/1/')
thread_id = r.json['ticket']['discussion_thread']['_id']
post = self.api_post(
'/rest/p/test/bugs/_discuss/thread/%s/new' % thread_id,
text='This is a comment', wrap_args=None)
thread = self.api_get('/rest/p/test/bugs/_discuss/thread/%s/' % thread_id)
assert len(thread.json['thread']['posts']) == 1, thread.json
assert post.json['post']['text'] == 'This is a comment', post.json
reply = self.api_post(
'/rest/p/test/bugs/_discuss/thread/%s/%s/reply' % (thread.json['thread']
['_id'], post.json['post']['slug']),
text='This is a reply', wrap_args=None)
assert reply.json['post']['text'] == 'This is a reply', reply.json
thread = self.api_get('/rest/p/test/bugs/_discuss/thread/%s/' % thread_id)
assert len(thread.json['thread']['posts']) == 2, thread.json
class TestRestSearch(TestTrackerApiBase):
@property
def ticket(self):
return TM.Ticket(
ticket_num=5,
summary='our test ticket',
status='open',
labels=['tiny', 'minor'])
@patch('forgetracker.model.Ticket.paged_search')
def test_no_criteria(self, paged_search):
paged_search.return_value = dict(tickets=[self.ticket])
r = self.api_get('/rest/p/test/bugs/search')
assert_equal(r.status_int, 200)
assert_equal(r.json['tickets'][0]['summary'], 'our test ticket')
assert_equal(r.json['tickets'][0]['ticket_num'], 5)
assert_equal(r.json['tickets'][0]['status'], 'open')
assert_equal(r.json['tickets'][0]['labels'], ['tiny', 'minor'])
assert 'description' not in r.json
assert 'discussion_thread' not in r.json
@patch('forgetracker.model.Ticket.paged_search')
def test_some_criteria(self, paged_search):
q = 'labels:testing && status:open'
paged_search.return_value = dict(
tickets=[self.ticket],
sort='status',
limit=2,
count=1,
page=0,
q=q,
)
r = self.api_get('/rest/p/test/bugs/search',
q=q, sort='status', limit='2')
assert_equal(r.status_int, 200)
assert_equal(r.json['limit'], 2)
assert_equal(r.json['q'], q)
assert_equal(r.json['sort'], 'status')
assert_equal(r.json['count'], 1)
assert_equal(r.json['page'], 0)
assert_equal(r.json['tickets'][0]['summary'], 'our test ticket')
assert_equal(r.json['tickets'][0]['ticket_num'], 5)
assert_equal(r.json['tickets'][0]['status'], 'open')
assert_equal(r.json['tickets'][0]['labels'], ['tiny', 'minor'])
assert 'description' not in r.json
assert 'discussion_thread' not in r.json
class TestRestHasAccess(TestTrackerApiBase):
def test_has_access_no_params(self):
r = self.api_get('/rest/p/test/bugs/has_access', status=404)
r = self.api_get('/rest/p/test/bugs/has_access?user=root', status=404)
r = self.api_get('/rest/p/test/bugs/has_access?perm=read', status=404)
def test_has_access_unknown_params(self):
"""Unknown user and/or permission always False for has_access API"""
r = self.api_get(
'/rest/p/test/bugs/has_access?user=babadook&perm=read',
user='root')
assert_equal(r.status_int, 200)
assert_equal(r.json['result'], False)
r = self.api_get(
'/rest/p/test/bugs/has_access?user=test-user&perm=jump',
user='root')
assert_equal(r.status_int, 200)
assert_equal(r.json['result'], False)
def test_has_access_not_admin(self):
"""
User which has no 'admin' permission on neighborhood can't use
has_access API
"""
self.api_get(
'/rest/p/test/bugs/has_access?user=test-admin&perm=admin',
user='test-user',
status=403)
def test_has_access(self):
r = self.api_get(
'/rest/p/test/bugs/has_access?user=test-admin&perm=delete',
user='root')
assert_equal(r.status_int, 200)
assert_equal(r.json['result'], True)
r = self.api_get(
'/rest/p/test/bugs/has_access?user=test-user&perm=delete',
user='root')
assert_equal(r.status_int, 200)
assert_equal(r.json['result'], False)