Project import generated by Copybara.

GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/project/test/projectexport_test.py b/project/test/projectexport_test.py
new file mode 100644
index 0000000..6dbe990
--- /dev/null
+++ b/project/test/projectexport_test.py
@@ -0,0 +1,148 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file or at
+# https://developers.google.com/open-source/licenses/bsd
+
+"""Unittests for the projectexport servlet."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+from mock import Mock, patch
+
+from framework import permissions
+from project import projectexport
+from proto import tracker_pb2
+from services import service_manager
+from services.template_svc import TemplateService
+from testing import fake
+from testing import testing_helpers
+
+
+class ProjectExportTest(unittest.TestCase):
+
+  def setUp(self):
+    self.services = service_manager.Services()
+    self.servlet = projectexport.ProjectExport(
+        'req', 'res', services=self.services)
+
+  def testAssertBasePermission(self):
+    mr = testing_helpers.MakeMonorailRequest(
+        perms=permissions.OWNER_ACTIVE_PERMISSIONSET)
+    self.assertRaises(permissions.PermissionException,
+                      self.servlet.AssertBasePermission, mr)
+    mr.auth.user_pb.is_site_admin = True
+    self.servlet.AssertBasePermission(mr)
+
+
+class ProjectExportJSONTest(unittest.TestCase):
+
+  def setUp(self):
+    self.services = service_manager.Services(
+        config=fake.ConfigService(),
+        project=fake.ProjectService(),
+        user=fake.UserService(),
+        template=Mock(spec=TemplateService))
+    self.services.user.TestAddUser('user1@example.com', 111)
+    self.servlet = projectexport.ProjectExportJSON(
+        'req', 'res', services=self.services)
+    self.project = fake.Project(project_id=789)
+    self.mr = testing_helpers.MakeMonorailRequest(
+        perms=permissions.OWNER_ACTIVE_PERMISSIONSET)
+    self.mr.auth.user_pb.is_site_admin = True
+    self.mr.project = self.project
+
+  @patch('time.time')
+  def testHandleRequest_Normal(self, mockTime):
+    mockTime.return_value = 123456789
+    self.services.project.GetProject = Mock(return_value=self.project)
+    test_config = fake.MakeTestConfig(project_id=789, labels=[], statuses=[])
+    self.services.config.GetProjectConfig = Mock(return_value=test_config)
+    test_templates = testing_helpers.DefaultTemplates()
+    self.services.template.GetProjectTemplates = Mock(
+        return_value=test_templates)
+    self.services.config.UsersInvolvedInConfig = Mock(return_value=[111])
+
+    json_data = self.servlet.HandleRequest(self.mr)
+
+    expected = {
+      'project': {
+        'committers': [],
+        'owners': [],
+        'recent_activity': 0,
+        'name': 'proj',
+        'contributors': [],
+        'perms': [],
+        'attachment_quota': None,
+        'process_inbound_email': False,
+        'revision_url_format': None,
+        'summary': '',
+        'access': 'ANYONE',
+        'state': 'LIVE',
+        'read_only_reason': None,
+        'only_owners_remove_restrictions': False,
+        'only_owners_see_contributors': False,
+        'attachment_bytes': 0,
+        'issue_notify_address': None,
+        'description': ''
+      },
+      'config': {
+        'templates': [{
+          'status': 'Accepted',
+          'members_only': True,
+          'labels': [],
+          'summary_must_be_edited': True,
+          'owner': None,
+          'owner_defaults_to_member': True,
+          'component_required': False,
+          'name': 'Defect report from developer',
+          'summary': 'Enter one-line summary',
+          'content': 'What steps will reproduce the problem?\n1. \n2. \n3. \n'
+            '\n'
+            'What is the expected output?\n\n\nWhat do you see instead?\n'
+            '\n\n'
+            'Please use labels and text to provide additional information.\n',
+          'admins': []
+        }, {
+          'status': 'New',
+          'members_only': False,
+          'labels': [],
+          'summary_must_be_edited': True,
+          'owner': None,
+          'owner_defaults_to_member': True,
+          'component_required': False,
+          'name': 'Defect report from user',
+          'summary': 'Enter one-line summary', 'content': 'What steps will '
+            'reproduce the problem?\n1. \n2. \n3. \n\nWhat is the expected '
+            'output?\n\n\nWhat do you see instead?\n\n\nWhat version of the '
+            'product are you using? On what operating system?\n\n\nPlease '
+            'provide any additional information below.\n',
+          'admins': []
+        }],
+        'labels': [],
+        'statuses_offer_merge': ['Duplicate'],
+        'exclusive_label_prefixes': ['Type', 'Priority', 'Milestone'],
+        'only_known_values': False,
+        'statuses': [],
+        'list_spec': '',
+        'developer_template': 0,
+        'user_template': 0,
+        'grid_y': '',
+        'grid_x': '',
+        'components': [],
+        'list_cols': 'ID Type Status Priority Milestone Owner Summary'
+      },
+      'emails': ['user1@example.com'],
+      'metadata': {
+        'version': 1,
+        'when': 123456789,
+        'who': None,
+      }
+    }
+    self.assertDictEqual(expected, json_data)
+    self.services.template.GetProjectTemplates.assert_called_once_with(
+        self.mr.cnxn, 789)
+    self.services.config.UsersInvolvedInConfig.assert_called_once_with(
+        test_config, test_templates)