text: #       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 __future__ import unicode_literals
  from __future__ import absolute_import
  from tg 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', 'discussion_thread'):
              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 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):
          self.api_get('/rest/p/test/bugs/has_access', status=404)
          self.api_get('/rest/p/test/bugs/has_access?user=root', status=404)
          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)
  