Project import generated by Copybara.
GitOrigin-RevId: d9e9e3fb4e31372ec1fb43b178994ca78fa8fe70
diff --git a/sitewide/test/__init__.py b/sitewide/test/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sitewide/test/__init__.py
diff --git a/sitewide/test/custom_404_test.py b/sitewide/test/custom_404_test.py
new file mode 100644
index 0000000..71b52f8
--- /dev/null
+++ b/sitewide/test/custom_404_test.py
@@ -0,0 +1,44 @@
+# Copyright 2017 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
+
+"""Unit tests for the custom_404 servlet."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import httplib
+import unittest
+
+from framework import exceptions
+from services import service_manager
+from sitewide import custom_404
+from testing import fake
+from testing import testing_helpers
+
+
+class Custom404Test(unittest.TestCase):
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ project=fake.ProjectService())
+ self.servlet = custom_404.ErrorPage('req', 'res', services=self.services)
+
+ def testGatherPageData_NoProjectSpecified(self):
+ """Project was not included in URL, so raise exception, will cause 400."""
+ _, mr = testing_helpers.GetRequestObjects(
+ path='/not/a/project/url')
+
+ with self.assertRaises(exceptions.InputException):
+ self.servlet.GatherPageData(mr)
+
+ def testGatherPageData_Normal(self):
+ """Return page_data dict with a 404 response code specified."""
+ _project = self.services.project.TestAddProject('proj')
+ _, mr = testing_helpers.GetRequestObjects(path='/p/proj/junk')
+
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertEqual(
+ {'http_response_code': httplib.NOT_FOUND},
+ page_data)
diff --git a/sitewide/test/group_helpers_test.py b/sitewide/test/group_helpers_test.py
new file mode 100644
index 0000000..af03d08
--- /dev/null
+++ b/sitewide/test/group_helpers_test.py
@@ -0,0 +1,51 @@
+# 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
+
+"""Unit test for User Group helpers."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+from proto import user_pb2
+from proto import usergroup_pb2
+from sitewide import group_helpers
+
+
+class GroupHelpersTest(unittest.TestCase):
+
+ def testGroupVisibilityView(self):
+ gvv_anyone = group_helpers.GroupVisibilityView(
+ usergroup_pb2.MemberVisibility.ANYONE)
+ gvv_members = group_helpers.GroupVisibilityView(
+ usergroup_pb2.MemberVisibility.MEMBERS)
+ gvv_owners = group_helpers.GroupVisibilityView(
+ usergroup_pb2.MemberVisibility.OWNERS)
+ self.assertEqual('Anyone on the Internet', gvv_anyone.name)
+ self.assertEqual('Group Members', gvv_members.name)
+ self.assertEqual('Group Owners', gvv_owners.name)
+
+ def testGroupMemberView(self):
+ user = user_pb2.MakeUser(1, email='test@example.com')
+ gmv = group_helpers.GroupMemberView(user, 888, 'member')
+ self.assertEqual(888, gmv.group_id)
+ self.assertEqual('member', gmv.role)
+
+ def testBuildUserGroupVisibilityOptions(self):
+ vis_views = group_helpers.BuildUserGroupVisibilityOptions()
+ self.assertEqual(3, len(vis_views))
+
+ def testGroupTypeView(self):
+ gt_cia = group_helpers.GroupTypeView(
+ usergroup_pb2.GroupType.CHROME_INFRA_AUTH)
+ gt_mdb = group_helpers.GroupTypeView(
+ usergroup_pb2.GroupType.MDB)
+ self.assertEqual('Chrome-infra-auth', gt_cia.name)
+ self.assertEqual('MDB', gt_mdb.name)
+
+ def testBuildUserGroupTypeOptions(self):
+ group_types = group_helpers.BuildUserGroupTypeOptions()
+ self.assertEqual(4, len(group_types))
diff --git a/sitewide/test/groupadmin_test.py b/sitewide/test/groupadmin_test.py
new file mode 100644
index 0000000..d1f7e0f
--- /dev/null
+++ b/sitewide/test/groupadmin_test.py
@@ -0,0 +1,85 @@
+# 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
+
+"""Unit test for User Group admin servlet."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+from framework import permissions
+from proto import usergroup_pb2
+from services import service_manager
+from sitewide import groupadmin
+from testing import fake
+from testing import testing_helpers
+
+
+class GrouAdminTest(unittest.TestCase):
+ """Tests for the GroupAdmin servlet."""
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ user=fake.UserService(),
+ usergroup=fake.UserGroupService(),
+ project=fake.ProjectService())
+ self.services.user.TestAddUser('a@example.com', 111)
+ self.services.user.TestAddUser('b@example.com', 222)
+ self.services.user.TestAddUser('c@example.com', 333)
+ self.services.user.TestAddUser('group@example.com', 888)
+ self.services.user.TestAddUser('importgroup@example.com', 999)
+ self.services.usergroup.TestAddGroupSettings(888, 'group@example.com')
+ self.services.usergroup.TestAddGroupSettings(
+ 999, 'importgroup@example.com', external_group_type='mdb')
+ self.servlet = groupadmin.GroupAdmin(
+ 'req', 'res', services=self.services)
+ self.mr = testing_helpers.MakeMonorailRequest()
+ self.mr.viewed_username = 'group@example.com'
+ self.mr.viewed_user_auth.user_id = 888
+
+ def testAssertBasePermission(self):
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(None, {}, None))
+ mr.viewed_user_auth.user_id = 888
+ self.assertRaises(
+ permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+ self.services.usergroup.TestAddMembers(888, [111], 'owner')
+ self.servlet.AssertBasePermission(self.mr)
+
+ def testGatherPageData_Normal(self):
+ page_data = self.servlet.GatherPageData(self.mr)
+ self.assertEqual('group@example.com', page_data['groupname'])
+ self.assertEqual('Group Members', page_data['initial_visibility'].name)
+ self.assertEqual(3, len(page_data['visibility_levels']))
+
+ def testGatherPageData_Import(self):
+ mr = testing_helpers.MakeMonorailRequest()
+ mr.viewed_username = 'importgroup@example.com'
+ mr.viewed_user_auth.user_id = 999
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertEqual('importgroup@example.com', page_data['groupname'])
+ self.assertTrue(page_data['import_group'])
+ self.assertEqual('MDB', page_data['initial_group_type'].name)
+
+ def testProcessFormData_Normal(self):
+ post_data = fake.PostData(visibility='0')
+ url = self.servlet.ProcessFormData(self.mr, post_data)
+ self.assertIn('/g/group@example.com/groupadmin', url)
+ group_settings = self.services.usergroup.GetGroupSettings(None, 888)
+ self.assertEqual(usergroup_pb2.MemberVisibility.OWNERS,
+ group_settings.who_can_view_members)
+
+ def testProcessFormData_Import(self):
+ post_data = fake.PostData(
+ group_type='1', import_group=['on'])
+ url = self.servlet.ProcessFormData(self.mr, post_data)
+ self.assertIn('/g/group@example.com/groupadmin', url)
+ group_settings = self.services.usergroup.GetGroupSettings(None, 888)
+ self.assertEqual(usergroup_pb2.MemberVisibility.OWNERS,
+ group_settings.who_can_view_members)
+ self.assertEqual(usergroup_pb2.GroupType.MDB,
+ group_settings.ext_group_type)
diff --git a/sitewide/test/groupcreate_test.py b/sitewide/test/groupcreate_test.py
new file mode 100644
index 0000000..bf7be8d
--- /dev/null
+++ b/sitewide/test/groupcreate_test.py
@@ -0,0 +1,101 @@
+# 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
+
+"""Unit test for User Group creation servlet."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+import settings
+from framework import permissions
+from proto import site_pb2
+from proto import usergroup_pb2
+from services import service_manager
+from sitewide import groupcreate
+from testing import fake
+from testing import testing_helpers
+
+
+class GroupCreateTest(unittest.TestCase):
+ """Tests for the GroupCreate servlet."""
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ user=fake.UserService(),
+ usergroup=fake.UserGroupService(),
+ project=fake.ProjectService())
+ self.servlet = groupcreate.GroupCreate(
+ 'req', 'res', services=self.services)
+ self.mr = testing_helpers.MakeMonorailRequest()
+
+ def CheckAssertBasePermissions(
+ self, restriction, expect_admin_ok, expect_nonadmin_ok):
+ old_group_creation_restriction = settings.group_creation_restriction
+ settings.group_creation_restriction = restriction
+
+ # Anon users can never do it
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(None, {}, None))
+ self.assertRaises(
+ permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+
+ mr = testing_helpers.MakeMonorailRequest()
+ if expect_admin_ok:
+ self.servlet.AssertBasePermission(mr)
+ else:
+ self.assertRaises(
+ permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(mr.auth.user_pb, {111}, None))
+ if expect_nonadmin_ok:
+ self.servlet.AssertBasePermission(mr)
+ else:
+ self.assertRaises(
+ permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+
+ settings.group_creation_restriction = old_group_creation_restriction
+
+ def testAssertBasePermission(self):
+ self.CheckAssertBasePermissions(
+ site_pb2.UserTypeRestriction.ANYONE, True, True)
+ self.CheckAssertBasePermissions(
+ site_pb2.UserTypeRestriction.ADMIN_ONLY, True, False)
+ self.CheckAssertBasePermissions(
+ site_pb2.UserTypeRestriction.NO_ONE, False, False)
+
+ def testGatherPageData(self):
+ page_data = self.servlet.GatherPageData(self.mr)
+ self.assertEqual('', page_data['initial_name'])
+
+ def testProcessFormData_Normal(self):
+ post_data = fake.PostData(
+ groupname=['group@example.com'], visibility='1')
+ url = self.servlet.ProcessFormData(self.mr, post_data)
+ self.assertIn('/g/3444127190/', url)
+ group_id = self.services.user.LookupUserID('cnxn', 'group@example.com')
+ group_settings = self.services.usergroup.GetGroupSettings('cnxn', group_id)
+ self.assertIsNotNone(group_settings)
+ members_after, owners_after = self.services.usergroup.LookupMembers(
+ 'cnxn', [group_id])
+ self.assertEqual(0, len(members_after[group_id] + owners_after[group_id]))
+
+ def testProcessFormData_Import(self):
+ post_data = fake.PostData(
+ groupname=['group@example.com'], group_type='1',
+ import_group=['on'])
+ self.servlet.ProcessFormData(self.mr, post_data)
+ group_id = self.services.user.LookupUserID('cnxn', 'group@example.com')
+ group_settings = self.services.usergroup.GetGroupSettings('cnxn', group_id)
+ self.assertIsNotNone(group_settings)
+ self.assertEqual(usergroup_pb2.MemberVisibility.OWNERS,
+ group_settings.who_can_view_members)
+ self.assertEqual(usergroup_pb2.GroupType.MDB,
+ group_settings.ext_group_type)
diff --git a/sitewide/test/groupdetail_test.py b/sitewide/test/groupdetail_test.py
new file mode 100644
index 0000000..4440bb8
--- /dev/null
+++ b/sitewide/test/groupdetail_test.py
@@ -0,0 +1,146 @@
+# 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
+
+"""Unit test for User Group Detail servlet."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+from framework import exceptions
+from framework import permissions
+from services import service_manager
+from sitewide import groupdetail
+from testing import fake
+from testing import testing_helpers
+
+
+class GroupDetailTest(unittest.TestCase):
+ """Tests for the GroupDetail servlet."""
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ project=fake.ProjectService(),
+ user=fake.UserService(),
+ usergroup=fake.UserGroupService())
+ self.services.user.TestAddUser('a@example.com', 111)
+ self.services.user.TestAddUser('b@example.com', 222)
+ self.services.user.TestAddUser('c@example.com', 333)
+ self.services.user.TestAddUser('group@example.com', 888)
+ self.services.usergroup.TestAddGroupSettings(888, 'group@example.com')
+ self.servlet = groupdetail.GroupDetail(
+ 'req', 'res', services=self.services)
+ self.mr = testing_helpers.MakeMonorailRequest()
+ self.mr.viewed_username = 'group@example.com'
+ self.mr.viewed_user_auth.user_id = 888
+
+ def testAssertBasePermission(self):
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(None, {}, None))
+ mr.viewed_user_auth.user_id = 888
+ mr.auth.effective_ids = set([111])
+ self.assertRaises(
+ permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+ self.services.usergroup.TestAddMembers(888, [111], 'member')
+ self.servlet.AssertBasePermission(mr)
+
+ def testAssertBasePermission_IgnoreNoSuchGroup(self):
+ """The permission check does not crash for non-existent user groups."""
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(None, {}, None))
+ mr.viewed_user_auth.user_id = 404
+ mr.auth.effective_ids = set([111])
+ self.servlet.AssertBasePermission(mr)
+
+ def testAssertBasePermission_IndirectMembership(self):
+ self.services.usergroup.TestAddGroupSettings(999, 'subgroup@example.com')
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(None, {}, None))
+ mr.viewed_user_auth.user_id = 888
+ mr.auth.effective_ids = set([111])
+ self.assertRaises(
+ permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+ self.services.usergroup.TestAddMembers(888, [999], 'member')
+ self.services.usergroup.TestAddMembers(999, [111], 'member')
+ self.servlet.AssertBasePermission(mr)
+
+ def testGatherPagData_ZeroMembers(self):
+ page_data = self.servlet.GatherPageData(self.mr)
+ pagination = page_data['pagination']
+ self.assertEqual(0, len(pagination.visible_results))
+
+ def testGatherPagData_NonzeroMembers(self):
+ self.services.usergroup.TestAddMembers(888, [111, 222, 333])
+ page_data = self.servlet.GatherPageData(self.mr)
+ pagination = page_data['pagination']
+ self.assertEqual(3, len(pagination.visible_results))
+ self.assertEqual(3, pagination.total_count)
+ self.assertEqual(1, pagination.start)
+ self.assertEqual(3, pagination.last)
+ user_view_a, user_view_b, user_view_c = pagination.visible_results
+ self.assertEqual('a@example.com', user_view_a.email)
+ self.assertEqual('b@example.com', user_view_b.email)
+ self.assertEqual('c@example.com', user_view_c.email)
+
+ def testProcessAddMembers_NoneAdded(self):
+ post_data = fake.PostData(addmembers=[''], role=['member'])
+ url = self.servlet.ProcessAddMembers(self.mr, post_data)
+ self.assertIn('/g/group@example.com/?', url)
+ members_after, _ = self.services.usergroup.LookupMembers('cnxn', [888])
+ self.assertEqual(0, len(members_after[888]))
+
+ self.services.usergroup.TestAddMembers(888, [111, 222, 333])
+ url = self.servlet.ProcessAddMembers(self.mr, post_data)
+ self.assertIn('/g/group@example.com/?', url)
+ members_after, _ = self.services.usergroup.LookupMembers('cnxn', [888])
+ self.assertEqual(3, len(members_after[888]))
+
+ def testProcessAddMembers_SomeAdded(self):
+ self.services.usergroup.TestAddMembers(888, [111])
+ post_data = fake.PostData(
+ addmembers=['b@example.com, c@example.com'], role=['member'])
+ url = self.servlet.ProcessAddMembers(self.mr, post_data)
+ self.assertIn('/g/group@example.com/?', url)
+ members_after, _ = self.services.usergroup.LookupMembers('cnxn', [888])
+ self.assertEqual(3, len(members_after[888]))
+
+ def testProcessRemoveMembers_SomeRemoved(self):
+ self.services.usergroup.TestAddMembers(888, [111, 222, 333])
+ post_data = fake.PostData(remove=['b@example.com', 'c@example.com'])
+ url = self.servlet.ProcessRemoveMembers(self.mr, post_data)
+ self.assertIn('/g/group@example.com/?', url)
+ members_after, _ = self.services.usergroup.LookupMembers('cnxn', [888])
+ self.assertEqual(1, len(members_after[888]))
+
+ def testProcessFormData_NoPermission(self):
+ """Group members cannot edit group."""
+ self.services.usergroup.TestAddMembers(888, [111], 'member')
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(None, {}, None))
+ mr.viewed_user_auth.user_id = 888
+ mr.auth.effective_ids = set([111])
+ self.assertRaises(permissions.PermissionException,
+ self.servlet.ProcessFormData, mr, {})
+
+ def testProcessFormData_OwnerPermission(self):
+ """Group owners cannot edit group."""
+ self.services.usergroup.TestAddMembers(888, [111], 'owner')
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(None, {}, None))
+ mr.viewed_user_auth.user_id = 888
+ mr.auth.effective_ids = set([111])
+ self.servlet.ProcessFormData(mr, {})
+
+ def testGatherPagData_NoSuchUserGroup(self):
+ """If there is no such user group, raise an exception."""
+ self.mr.viewed_user_auth.user_id = 404
+ self.assertRaises(
+ exceptions.NoSuchGroupException,
+ self.servlet.GatherPageData, self.mr)
+
+
diff --git a/sitewide/test/grouplist_test.py b/sitewide/test/grouplist_test.py
new file mode 100644
index 0000000..9ec6bd5
--- /dev/null
+++ b/sitewide/test/grouplist_test.py
@@ -0,0 +1,84 @@
+# 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
+
+"""Unit test for User Group List servlet."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+from google.appengine.ext import testbed
+
+from framework import permissions
+from services import service_manager
+from sitewide import grouplist
+from testing import fake
+from testing import testing_helpers
+
+
+class GroupListTest(unittest.TestCase):
+ """Tests for the GroupList servlet."""
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ usergroup=fake.UserGroupService())
+ self.servlet = grouplist.GroupList('req', 'res', services=self.services)
+ self.mr = testing_helpers.MakeMonorailRequest()
+ self.testbed = testbed.Testbed()
+ self.testbed.activate()
+ self.testbed.init_memcache_stub()
+ self.testbed.init_datastore_v3_stub()
+
+ def tearDown(self):
+ self.testbed.deactivate()
+
+ def testAssertBasePermission_Anon(self):
+ self.mr.perms = permissions.READ_ONLY_PERMISSIONSET
+ with self.assertRaises(permissions.PermissionException):
+ self.servlet.AssertBasePermission(self.mr)
+
+ def testAssertBasePermission_RegularUsers(self):
+ self.mr.perms = permissions.COMMITTER_ACTIVE_PERMISSIONSET
+ with self.assertRaises(permissions.PermissionException):
+ self.servlet.AssertBasePermission(self.mr)
+
+ def testAssertBasePermission_SiteAdmin(self):
+ self.mr.perms = permissions.ADMIN_PERMISSIONSET
+ self.servlet.AssertBasePermission(self.mr)
+
+ def testGatherPagData_ZeroGroups(self):
+ page_data = self.servlet.GatherPageData(self.mr)
+ self.assertEqual([], page_data['groups'])
+
+ def testGatherPagData_NonzeroGroups(self):
+ self.services.usergroup.TestAddGroupSettings(777, 'group_a@example.com')
+ self.services.usergroup.TestAddGroupSettings(888, 'group_b@example.com')
+ self.services.usergroup.TestAddMembers(888, [111, 222, 333])
+ page_data = self.servlet.GatherPageData(self.mr)
+ group_view_a, group_view_b = page_data['groups']
+ self.assertEqual('group_a@example.com', group_view_a.name)
+ self.assertEqual(0, group_view_a.num_members)
+ self.assertEqual('group_b@example.com', group_view_b.name)
+ self.assertEqual(3, group_view_b.num_members)
+
+ def testProcessFormData_NoPermission(self):
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.USER_PERMISSIONSET)
+ post_data = fake.PostData(
+ removebtn=[1])
+ self.assertRaises(permissions.PermissionException,
+ self.servlet.ProcessFormData, mr, post_data)
+
+ def testProcessFormData_Normal(self):
+ self.services.usergroup.TestAddGroupSettings(
+ 888, 'group_b@example.com', friend_projects=[789])
+ self.services.usergroup.TestAddMembers(888, [111, 222, 333])
+
+ post_data = fake.PostData(
+ remove=[888],
+ removebtn=[1])
+ self.servlet.ProcessFormData(self.mr, post_data)
+ self.assertNotIn(888, self.services.usergroup.group_settings)
diff --git a/sitewide/test/hostinghome_test.py b/sitewide/test/hostinghome_test.py
new file mode 100644
index 0000000..f51c9ec
--- /dev/null
+++ b/sitewide/test/hostinghome_test.py
@@ -0,0 +1,146 @@
+# 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
+
+"""Tests for the Monorail home page."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import mock
+import unittest
+
+import ezt
+
+import settings
+from framework import permissions
+from proto import project_pb2
+from proto import site_pb2
+from services import service_manager
+from sitewide import hostinghome
+from sitewide import projectsearch
+from testing import fake
+from testing import testing_helpers
+
+
+class MockProjectSearchPipeline(object):
+
+ def __init__(self, _mr, services):
+ self.visible_results = services.mock_visible_results
+ self.pagination = None
+
+ def SearchForIDs(self, domain=None):
+ pass
+
+ def GetProjectsAndPaginate(self, cnxn, list_page_url):
+ pass
+
+
+class HostingHomeTest(unittest.TestCase):
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ project=fake.ProjectService(),
+ project_star=fake.ProjectStarService())
+ self.services.mock_visible_results = []
+ self.project_a = self.services.project.TestAddProject('a', project_id=1)
+ self.project_b = self.services.project.TestAddProject('b', project_id=2)
+
+ self.servlet = hostinghome.HostingHome('req', 'res', services=self.services)
+ self.mr = testing_helpers.MakeMonorailRequest(user_info={'user_id': 111})
+
+ self.orig_pipeline_class = projectsearch.ProjectSearchPipeline
+ projectsearch.ProjectSearchPipeline = MockProjectSearchPipeline
+
+ def tearDown(self):
+ projectsearch.ProjectSearchPipeline = self.orig_pipeline_class
+
+ def testSearch_ZeroResults(self):
+ self.services.mock_visible_results = []
+ page_data = self.servlet.GatherPageData(self.mr)
+ self.assertEqual([], page_data['projects'])
+
+ def testSearch_NonzeroResults(self):
+ self.services.mock_visible_results = [self.project_a, self.project_b]
+ page_data = self.servlet.GatherPageData(self.mr)
+ self.assertEqual(['a', 'b'],
+ [pv.project_name for pv in page_data['projects']])
+
+ def testStarCounts(self):
+ """Test the display of star counts on each displayed project."""
+ self.services.mock_visible_results = [self.project_a, self.project_b]
+ # We go straight to the services layer because this is a test set up
+ # rather than an actual user request.
+ self.services.project_star.SetStar('fake cnxn', 1, 111, True)
+ self.services.project_star.SetStar('fake cnxn', 1, 222, True)
+ page_data = self.servlet.GatherPageData(self.mr)
+ project_view_a, project_view_b = page_data['projects']
+ self.assertEqual(2, project_view_a.num_stars)
+ self.assertEqual(0, project_view_b.num_stars)
+
+ def testStarredProjects(self):
+ self.services.mock_visible_results = [self.project_a, self.project_b]
+ self.services.project_star.SetStar('fake cnxn', 1, 111, True)
+ page_data = self.servlet.GatherPageData(self.mr)
+ project_view_a, project_view_b = page_data['projects']
+ self.assertTrue(project_view_a.starred)
+ self.assertFalse(project_view_b.starred)
+
+ def testGatherPageData(self):
+ mr = testing_helpers.MakeMonorailRequest()
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertEqual(settings.learn_more_link, page_data['learn_more_link'])
+
+ def testGatherPageData_CanCreateProject(self):
+ mr = testing_helpers.MakeMonorailRequest()
+ mr.perms = permissions.PermissionSet([permissions.CREATE_PROJECT])
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertEqual(
+ ezt.boolean(settings.project_creation_restriction ==
+ site_pb2.UserTypeRestriction.ANYONE),
+ page_data['can_create_project'])
+
+ mr.perms = permissions.PermissionSet([])
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertEqual(ezt.boolean(False), page_data['can_create_project'])
+
+ @mock.patch('settings.domain_to_default_project', {})
+ def testMaybeRedirectToDomainDefaultProject_NoMatch(self):
+ """No redirect if the user is not accessing via a configured domain."""
+ mr = testing_helpers.MakeMonorailRequest()
+ mr.request.host = 'example.com'
+ msg = self.servlet._MaybeRedirectToDomainDefaultProject(mr)
+ print('msg: ' + msg)
+ self.assertTrue(msg.startswith('No configured'))
+
+ @mock.patch('settings.domain_to_default_project', {'example.com': 'huh'})
+ def testMaybeRedirectToDomainDefaultProject_NoSuchProject(self):
+ """No redirect if the configured project does not exist."""
+ mr = testing_helpers.MakeMonorailRequest()
+ mr.request.host = 'example.com'
+ print('host is %r' % mr.request.host)
+ msg = self.servlet._MaybeRedirectToDomainDefaultProject(mr)
+ print('msg: ' + msg)
+ self.assertTrue(msg.endswith('not found'))
+
+ @mock.patch('settings.domain_to_default_project', {'example.com': 'a'})
+ def testMaybeRedirectToDomainDefaultProject_CantView(self):
+ """No redirect if the user can't view the configured project."""
+ self.project_a.access = project_pb2.ProjectAccess.MEMBERS_ONLY
+ mr = testing_helpers.MakeMonorailRequest()
+ mr.request.host = 'example.com'
+ msg = self.servlet._MaybeRedirectToDomainDefaultProject(mr)
+ print('msg: ' + msg)
+ self.assertTrue(msg.startswith('User cannot'))
+
+ @mock.patch('settings.domain_to_default_project', {'example.com': 'a'})
+ def testMaybeRedirectToDomainDefaultProject_Redirect(self):
+ """We redirect if there's a configured project that the user can view."""
+ mr = testing_helpers.MakeMonorailRequest()
+ mr.request.host = 'example.com'
+ self.servlet.redirect = mock.Mock()
+ msg = self.servlet._MaybeRedirectToDomainDefaultProject(mr)
+ print('msg: ' + msg)
+ self.assertTrue(msg.startswith('Redirected'))
+ self.servlet.redirect.assert_called_once()
diff --git a/sitewide/test/moved_test.py b/sitewide/test/moved_test.py
new file mode 100644
index 0000000..04b9165
--- /dev/null
+++ b/sitewide/test/moved_test.py
@@ -0,0 +1,113 @@
+# 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
+
+"""Unit tests for the moved project notification page servlet."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+import webapp2
+
+from framework import exceptions
+from services import service_manager
+from sitewide import moved
+from testing import fake
+from testing import testing_helpers
+
+
+class MovedTest(unittest.TestCase):
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ project=fake.ProjectService())
+ self.servlet = moved.ProjectMoved('req', 'res', services=self.services)
+ self.old_project = 'old-project'
+
+ def testGatherPageData_NoProjectSpecified(self):
+ # Project was not included in URL, so raise exception, will cause 400.
+ _, mr = testing_helpers.GetRequestObjects(
+ path='/hosting/moved')
+
+ with self.assertRaises(exceptions.InputException):
+ self.servlet.GatherPageData(mr)
+
+ def testGatherPageData_NoSuchProject(self):
+ # Project doesn't exist, so 404 NOT FOUND.
+ _, mr = testing_helpers.GetRequestObjects(
+ path='/hosting/moved?project=nonexistent')
+
+ with self.assertRaises(webapp2.HTTPException) as cm:
+ self.servlet.GatherPageData(mr)
+ self.assertEqual(404, cm.exception.code)
+
+ def testGatherPageData_NotMoved(self):
+ # Project exists but has not been moved, so 400 BAD_REQUEST.
+ self.services.project.TestAddProject(self.old_project)
+ _, mr = testing_helpers.GetRequestObjects(
+ path='/hosting/moved?project=%s' % self.old_project)
+
+ with self.assertRaises(webapp2.HTTPException) as cm:
+ self.servlet.GatherPageData(mr)
+ self.assertEqual(400, cm.exception.code)
+
+ def testGatherPageData_URL(self):
+ # Display the moved_to url if it is valid.
+ project = self.services.project.TestAddProject(self.old_project)
+ project.moved_to = 'https://other-tracker.bugs'
+ _, mr = testing_helpers.GetRequestObjects(
+ path='/hosting/moved?project=%s' % self.old_project)
+
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertItemsEqual(
+ ['project_name', 'moved_to_url'],
+ list(page_data.keys()))
+ self.assertEqual(self.old_project, page_data['project_name'])
+ self.assertEqual('https://other-tracker.bugs', page_data['moved_to_url'])
+
+ def testGatherPageData_ProjectName(self):
+ # Construct the moved-to url from just the project name.
+ project = self.services.project.TestAddProject(self.old_project)
+ project.moved_to = 'new-project'
+ _, mr = testing_helpers.GetRequestObjects(
+ path='/hosting/moved?project=%s' % self.old_project)
+
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertItemsEqual(
+ ['project_name', 'moved_to_url'],
+ list(page_data.keys()))
+ self.assertEqual(self.old_project, page_data['project_name'])
+ self.assertEqual('http://127.0.0.1/p/new-project/',
+ page_data['moved_to_url'])
+
+ def testGatherPageData_HttpProjectName(self):
+ # A project named "http-foo" gets treated as a project, not a url.
+ project = self.services.project.TestAddProject(self.old_project)
+ project.moved_to = 'http-project'
+ _, mr = testing_helpers.GetRequestObjects(
+ path='/hosting/moved?project=%s' % self.old_project)
+
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertItemsEqual(
+ ['project_name', 'moved_to_url'],
+ list(page_data.keys()))
+ self.assertEqual(self.old_project, page_data['project_name'])
+ self.assertEqual('http://127.0.0.1/p/http-project/',
+ page_data['moved_to_url'])
+
+ def testGatherPageData_BadScheme(self):
+ # We only display URLs that start with 'http(s)://'.
+ project = self.services.project.TestAddProject(self.old_project)
+ project.moved_to = 'javascript:alert(1)'
+ _, mr = testing_helpers.GetRequestObjects(
+ path='/hosting/moved?project=%s' % self.old_project)
+
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertItemsEqual(
+ ['project_name', 'moved_to_url'],
+ list(page_data.keys()))
+ self.assertEqual(self.old_project, page_data['project_name'])
+ self.assertEqual('#invalid-destination-url', page_data['moved_to_url'])
diff --git a/sitewide/test/projectcreate_test.py b/sitewide/test/projectcreate_test.py
new file mode 100644
index 0000000..8f468dd
--- /dev/null
+++ b/sitewide/test/projectcreate_test.py
@@ -0,0 +1,74 @@
+# 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 Project Creation servlet."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+import settings
+from framework import permissions
+from proto import project_pb2
+from proto import site_pb2
+from services import service_manager
+from sitewide import projectcreate
+from testing import fake
+from testing import testing_helpers
+
+
+class ProjectCreateTest(unittest.TestCase):
+
+ def setUp(self):
+ services = service_manager.Services()
+ self.servlet = projectcreate.ProjectCreate('req', 'res', services=services)
+
+ def CheckAssertBasePermissions(
+ self, restriction, expect_admin_ok, expect_nonadmin_ok):
+ old_project_creation_restriction = settings.project_creation_restriction
+ settings.project_creation_restriction = restriction
+
+ # Anon users can never do it
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(None, {}, None))
+ self.assertRaises(
+ permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+
+ mr = testing_helpers.MakeMonorailRequest()
+ if expect_admin_ok:
+ self.servlet.AssertBasePermission(mr)
+ else:
+ self.assertRaises(
+ permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+
+ mr = testing_helpers.MakeMonorailRequest(
+ perms=permissions.GetPermissions(mr.auth.user_pb, {111}, None))
+ if expect_nonadmin_ok:
+ self.servlet.AssertBasePermission(mr)
+ else:
+ self.assertRaises(
+ permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+
+ settings.project_creation_restriction = old_project_creation_restriction
+
+ def testAssertBasePermission(self):
+ self.CheckAssertBasePermissions(
+ site_pb2.UserTypeRestriction.ANYONE, True, True)
+ self.CheckAssertBasePermissions(
+ site_pb2.UserTypeRestriction.ADMIN_ONLY, True, False)
+ self.CheckAssertBasePermissions(
+ site_pb2.UserTypeRestriction.NO_ONE, False, False)
+
+ def testGatherPageData(self):
+ mr = testing_helpers.MakeMonorailRequest()
+ page_data = self.servlet.GatherPageData(mr)
+ self.assertEqual('', page_data['initial_name'])
+ self.assertEqual('', page_data['initial_summary'])
+ self.assertEqual('', page_data['initial_description'])
+ self.assertEqual([], page_data['labels'])
diff --git a/sitewide/test/projectsearch_test.py b/sitewide/test/projectsearch_test.py
new file mode 100644
index 0000000..a0d941d
--- /dev/null
+++ b/sitewide/test/projectsearch_test.py
@@ -0,0 +1,75 @@
+# 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 projectsearch module."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import mock
+import unittest
+
+from framework import profiler
+from proto import project_pb2
+from services import service_manager
+from sitewide import projectsearch
+from testing import fake
+from testing import testing_helpers
+
+
+class ProjectSearchTest(unittest.TestCase):
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ project=fake.ProjectService())
+ self.services.project.GetVisibleLiveProjects = mock.MagicMock()
+
+ for idx, letter in enumerate('abcdefghijklmnopqrstuvwxyz'):
+ self.services.project.TestAddProject(letter, project_id=idx + 1)
+ for idx in range(27, 110):
+ self.services.project.TestAddProject(str(idx), project_id=idx)
+
+ self.addCleanup(mock.patch.stopall())
+
+ def TestPipeline(self, expected_last, expected_len):
+ mr = testing_helpers.MakeMonorailRequest()
+ mr.can = 1
+
+ pipeline = projectsearch.ProjectSearchPipeline(mr, self.services)
+ pipeline.SearchForIDs()
+ pipeline.GetProjectsAndPaginate('fake cnxn', '/hosting/search')
+ self.assertEqual(1, pipeline.pagination.start)
+ self.assertEqual(expected_last, pipeline.pagination.last)
+ self.assertEqual(expected_len, len(pipeline.visible_results))
+
+ return pipeline
+
+ def testZeroResults(self):
+ self.services.project.GetVisibleLiveProjects.return_value = []
+
+ pipeline = self.TestPipeline(0, 0)
+
+ self.services.project.GetVisibleLiveProjects.assert_called_once()
+ self.assertListEqual([], pipeline.visible_results)
+
+ def testNonzeroResults(self):
+ self.services.project.GetVisibleLiveProjects.return_value = [1, 2, 3]
+
+ pipeline = self.TestPipeline(3, 3)
+
+ self.services.project.GetVisibleLiveProjects.assert_called_once()
+ self.assertListEqual(
+ [1, 2, 3], [p.project_id for p in pipeline.visible_results])
+
+ def testTwoPageResults(self):
+ """Test more than one pagination page of results."""
+ self.services.project.GetVisibleLiveProjects.return_value = list(
+ range(1, 106))
+
+ pipeline = self.TestPipeline(100, 100)
+
+ self.services.project.GetVisibleLiveProjects.assert_called_once()
+ self.assertEqual(
+ '/hosting/search?num=100&start=100', pipeline.pagination.next_url)
diff --git a/sitewide/test/sitewide_helpers_test.py b/sitewide/test/sitewide_helpers_test.py
new file mode 100644
index 0000000..d292b6f
--- /dev/null
+++ b/sitewide/test/sitewide_helpers_test.py
@@ -0,0 +1,170 @@
+# 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
+
+"""Unit tests for the sitewide_helpers module."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+from proto import project_pb2
+from services import service_manager
+from sitewide import sitewide_helpers
+from testing import fake
+
+
+REGULAR_USER_ID = 111
+ADMIN_USER_ID = 222
+OTHER_USER_ID = 333
+
+# Test project IDs
+REGULAR_OWNER_LIVE = 1001
+REGULAR_OWNER_ARCHIVED = 1002
+REGULAR_OWNER_DELETABLE = 1003
+REGULAR_COMMITTER_LIVE = 2001
+REGULAR_COMMITTER_ARCHIVED = 2002
+REGULAR_COMMITTER_DELETABLE = 2003
+OTHER_OWNER_LIVE = 3001
+OTHER_OWNER_ARCHIVED = 3002
+OTHER_OWNER_DELETABLE = 3003
+OTHER_COMMITTER_LIVE = 4001
+MEMBERS_ONLY = 5001
+
+
+class HelperFunctionsTest(unittest.TestCase):
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ project=fake.ProjectService(),
+ user=fake.UserService(),
+ project_star=fake.ProjectStarService())
+ self.cnxn = 'fake cnxn'
+
+ for user_id in (ADMIN_USER_ID, REGULAR_USER_ID, OTHER_USER_ID):
+ self.services.user.TestAddUser('ignored_%s@gmail.com' % user_id, user_id)
+
+ self.regular_owner_live = self.services.project.TestAddProject(
+ 'regular-owner-live', state=project_pb2.ProjectState.LIVE,
+ owner_ids=[REGULAR_USER_ID], project_id=REGULAR_OWNER_LIVE)
+ self.regular_owner_archived = self.services.project.TestAddProject(
+ 'regular-owner-archived', state=project_pb2.ProjectState.ARCHIVED,
+ owner_ids=[REGULAR_USER_ID], project_id=REGULAR_OWNER_ARCHIVED)
+ self.regular_owner_deletable = self.services.project.TestAddProject(
+ 'regular-owner-deletable', state=project_pb2.ProjectState.DELETABLE,
+ owner_ids=[REGULAR_USER_ID], project_id=REGULAR_OWNER_DELETABLE)
+ self.regular_committer_live = self.services.project.TestAddProject(
+ 'regular-committer-live', state=project_pb2.ProjectState.LIVE,
+ committer_ids=[REGULAR_USER_ID], project_id=REGULAR_COMMITTER_LIVE)
+ self.regular_committer_archived = self.services.project.TestAddProject(
+ 'regular-committer-archived', state=project_pb2.ProjectState.ARCHIVED,
+ committer_ids=[REGULAR_USER_ID], project_id=REGULAR_COMMITTER_ARCHIVED)
+ self.regular_committer_deletable = self.services.project.TestAddProject(
+ 'regular-committer-deletable', state=project_pb2.ProjectState.DELETABLE,
+ committer_ids=[REGULAR_USER_ID], project_id=REGULAR_COMMITTER_DELETABLE)
+ self.other_owner_live = self.services.project.TestAddProject(
+ 'other-owner-live', state=project_pb2.ProjectState.LIVE,
+ owner_ids=[OTHER_USER_ID], project_id=OTHER_OWNER_LIVE)
+ self.other_owner_archived = self.services.project.TestAddProject(
+ 'other-owner-archived', state=project_pb2.ProjectState.ARCHIVED,
+ owner_ids=[OTHER_USER_ID], project_id=OTHER_OWNER_ARCHIVED)
+ self.other_owner_deletable = self.services.project.TestAddProject(
+ 'other-owner-deletable', state=project_pb2.ProjectState.DELETABLE,
+ owner_ids=[OTHER_USER_ID], project_id=OTHER_OWNER_DELETABLE)
+ self.other_committer_live = self.services.project.TestAddProject(
+ 'other-committer-live', state=project_pb2.ProjectState.LIVE,
+ committer_ids=[OTHER_USER_ID], project_id=OTHER_COMMITTER_LIVE)
+
+ self.regular_user = self.services.user.GetUser(self.cnxn, REGULAR_USER_ID)
+
+ self.admin_user = self.services.user.TestAddUser(
+ 'administrator@chromium.org', ADMIN_USER_ID)
+ self.admin_user.is_site_admin = True
+
+ self.other_user = self.services.user.GetUser(self.cnxn, OTHER_USER_ID)
+
+ self.members_only_project = self.services.project.TestAddProject(
+ 'members-only', owner_ids=[REGULAR_USER_ID], project_id=MEMBERS_ONLY)
+ self.members_only_project.access = project_pb2.ProjectAccess.MEMBERS_ONLY
+
+ def assertProjectsAnyOrder(self, actual_projects, *expected_projects):
+ # Check names rather than Project objects so that output is easier to read.
+ actual_names = [p.project_name for p in actual_projects]
+ expected_names = [p.project_name for p in expected_projects]
+ self.assertItemsEqual(expected_names, actual_names)
+
+ def testFilterViewableProjects_CantViewArchived(self):
+ projects = list(sitewide_helpers.FilterViewableProjects(
+ list(self.services.project.test_projects.values()),
+ self.regular_user, {REGULAR_USER_ID}))
+ self.assertProjectsAnyOrder(
+ projects, self.regular_owner_live, self.regular_committer_live,
+ self.other_owner_live, self.other_committer_live,
+ self.members_only_project)
+
+ def testFilterViewableProjects_NonMemberCantViewMembersOnly(self):
+ projects = list(sitewide_helpers.FilterViewableProjects(
+ list(self.services.project.test_projects.values()),
+ self.other_user, {OTHER_USER_ID}))
+ self.assertProjectsAnyOrder(
+ projects, self.regular_owner_live, self.regular_committer_live,
+ self.other_owner_live, self.other_committer_live)
+
+ def testFilterViewableProjects_AdminCanViewAny(self):
+ projects = list(sitewide_helpers.FilterViewableProjects(
+ list(self.services.project.test_projects.values()),
+ self.admin_user, {ADMIN_USER_ID}))
+ self.assertProjectsAnyOrder(
+ projects, self.regular_owner_live, self.regular_committer_live,
+ self.other_owner_live, self.other_committer_live,
+ self.members_only_project)
+
+ def testGetStarredProjects_OnlyViewableLiveStarred(self):
+ viewed_user_id = 123
+ for p in self.services.project.test_projects.values():
+ # We go straight to the services layer because this is a test set up
+ # rather than an actual user request.
+ self.services.project_star.SetStar(
+ self.cnxn, p.project_id, viewed_user_id, True)
+
+ self.assertProjectsAnyOrder(
+ sitewide_helpers.GetViewableStarredProjects(
+ self.cnxn, self.services, viewed_user_id,
+ {REGULAR_USER_ID}, self.regular_user),
+ self.regular_owner_live, self.regular_committer_live,
+ self.other_owner_live, self.other_committer_live,
+ self.members_only_project)
+
+ def testGetStarredProjects_MembersOnly(self):
+ # Both users were able to star the project in the past. The stars do not
+ # go away even if access to the project changes.
+ self.services.project_star.SetStar(
+ self.cnxn, self.members_only_project.project_id, REGULAR_USER_ID, True)
+ self.services.project_star.SetStar(
+ self.cnxn, self.members_only_project.project_id, OTHER_USER_ID, True)
+
+ # But now, only one of them is currently a member, so only regular_user
+ # can see the starred project in the lists.
+ self.assertProjectsAnyOrder(
+ sitewide_helpers.GetViewableStarredProjects(
+ self.cnxn, self.services, REGULAR_USER_ID, {REGULAR_USER_ID},
+ self.regular_user),
+ self.members_only_project)
+ self.assertProjectsAnyOrder(
+ sitewide_helpers.GetViewableStarredProjects(
+ self.cnxn, self.services, OTHER_USER_ID, {REGULAR_USER_ID},
+ self.regular_user),
+ self.members_only_project)
+
+ # The other user cannot see the project, so they do not see it in either
+ # list of starred projects.
+ self.assertProjectsAnyOrder(
+ sitewide_helpers.GetViewableStarredProjects(
+ self.cnxn, self.services, REGULAR_USER_ID, {OTHER_USER_ID},
+ self.other_user)) # No expected projects listed.
+ self.assertProjectsAnyOrder(
+ sitewide_helpers.GetViewableStarredProjects(
+ self.cnxn, self.services, OTHER_USER_ID, {OTHER_USER_ID},
+ self.other_user)) # No expected projects listed.
diff --git a/sitewide/test/sitewide_views_test.py b/sitewide/test/sitewide_views_test.py
new file mode 100644
index 0000000..ed2515f
--- /dev/null
+++ b/sitewide/test/sitewide_views_test.py
@@ -0,0 +1,26 @@
+# 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
+
+"""Unit tests for sitewide_views module."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+from proto import usergroup_pb2
+from sitewide import sitewide_views
+
+
+class GroupViewTest(unittest.TestCase):
+
+ def testConstructor(self):
+ group_settings = usergroup_pb2.MakeSettings('anyone')
+ view = sitewide_views.GroupView('groupname', 123, group_settings, 999)
+
+ self.assertEqual('groupname', view.name)
+ self.assertEqual(123, view.num_members)
+ self.assertEqual('ANYONE', view.who_can_view_members)
+ self.assertEqual('/g/999/', view.detail_url)
diff --git a/sitewide/test/userprofile_test.py b/sitewide/test/userprofile_test.py
new file mode 100644
index 0000000..b830fb7
--- /dev/null
+++ b/sitewide/test/userprofile_test.py
@@ -0,0 +1,252 @@
+# 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
+
+"""Tests for the user profile page."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import mock
+import unittest
+import logging
+import webapp2
+import ezt
+
+from framework import framework_helpers
+from framework import framework_views
+from framework import permissions
+from proto import project_pb2
+from proto import user_pb2
+from services import service_manager
+from sitewide import userprofile
+from testing import fake
+from testing import testing_helpers
+
+from google.appengine.ext import testbed
+
+REGULAR_USER_ID = 111
+ADMIN_USER_ID = 222
+OTHER_USER_ID = 333
+STATES = {
+ 'live': project_pb2.ProjectState.LIVE,
+ 'archived': project_pb2.ProjectState.ARCHIVED,
+}
+
+
+def MakeReqInfo(
+ user_pb, user_id, viewed_user_pb, viewed_user_id, viewed_user_name,
+ perms=permissions.USER_PERMISSIONSET):
+ mr = fake.MonorailRequest(None, perms=perms)
+ mr.auth.user_pb = user_pb
+ mr.auth.user_id = user_id
+ mr.auth.effective_ids = {user_id}
+ mr.viewed_user_auth.email = viewed_user_name
+ mr.viewed_user_auth.user_pb = viewed_user_pb
+ mr.viewed_user_auth.user_id = viewed_user_id
+ mr.viewed_user_auth.effective_ids = {viewed_user_id}
+ mr.viewed_user_auth.user_view = framework_views.UserView(viewed_user_pb)
+ mr.viewed_user_name = viewed_user_name
+ mr.request = webapp2.Request.blank("/")
+ return mr
+
+
+class UserProfileTest(unittest.TestCase):
+
+ def setUp(self):
+ self.patcher_1 = mock.patch(
+ 'framework.framework_helpers.UserSettings.GatherUnifiedSettingsPageData')
+ self.mock_guspd = self.patcher_1.start()
+ self.mock_guspd.return_value = {'unified': None}
+
+ services = service_manager.Services(
+ project=fake.ProjectService(),
+ user=fake.UserService(),
+ usergroup=fake.UserGroupService(),
+ project_star=fake.ProjectStarService(),
+ user_star=fake.UserStarService())
+ self.servlet = userprofile.UserProfile('req', 'res', services=services)
+
+ for user_id in (
+ REGULAR_USER_ID, ADMIN_USER_ID, OTHER_USER_ID):
+ services.user.TestAddUser('%s@gmail.com' % user_id, user_id)
+
+ for user in ['regular', 'other']:
+ for relation in ['owner', 'member']:
+ for state_name, state in STATES.items():
+ services.project.TestAddProject(
+ '%s-%s-%s' % (user, relation, state_name), state=state)
+
+ # Add projects
+ for state_name, state in STATES.items():
+ services.project.TestAddProject(
+ 'regular-owner-%s' % state_name, state=state,
+ owner_ids=[REGULAR_USER_ID])
+ services.project.TestAddProject(
+ 'regular-member-%s' % state_name, state=state,
+ committer_ids=[REGULAR_USER_ID])
+ services.project.TestAddProject(
+ 'other-owner-%s' % state_name, state=state,
+ owner_ids=[OTHER_USER_ID])
+ services.project.TestAddProject(
+ 'other-member-%s' % state_name, state=state,
+ committer_ids=[OTHER_USER_ID])
+
+ self.regular_user = services.user.GetUser('fake cnxn', REGULAR_USER_ID)
+ self.admin_user = services.user.GetUser('fake cnxn', ADMIN_USER_ID)
+ self.admin_user.is_site_admin = True
+ self.other_user = services.user.GetUser('fake cnxn', OTHER_USER_ID)
+
+ self.testbed = testbed.Testbed()
+ self.testbed.activate()
+ self.testbed.init_memcache_stub()
+ self.testbed.init_datastore_v3_stub()
+
+ def tearDown(self):
+ self.testbed.deactivate()
+ mock.patch.stopall()
+
+ def assertProjectsAnyOrder(self, value_to_test, *expected_project_names):
+ actual_project_names = [project_view.project_name
+ for project_view in value_to_test]
+ self.assertItemsEqual(expected_project_names, actual_project_names)
+
+ def testGatherPageData_RegularUserViewingOtherUserProjects(self):
+ """A user can see the other users' live projects, but not archived ones."""
+ mr = MakeReqInfo(
+ self.regular_user, REGULAR_USER_ID, self.other_user,
+ OTHER_USER_ID, 'other@xyz.com')
+
+ page_data = self.servlet.GatherPageData(mr)
+
+ self.assertProjectsAnyOrder(page_data['owner_of_projects'],
+ 'other-owner-live')
+ self.assertProjectsAnyOrder(page_data['committer_of_projects'],
+ 'other-member-live')
+ self.assertFalse(page_data['owner_of_archived_projects'])
+ self.assertEqual('ot...@xyz.com', page_data['viewed_user_display_name'])
+ self.assertEqual(ezt.boolean(False), page_data['can_delete_user'])
+ self.mock_guspd.assert_called_once_with(
+ 111, mr.viewed_user_auth.user_view, mr.viewed_user_auth.user_pb,
+ None)
+
+ def testGatherPageData_RegularUserViewingOwnProjects(self):
+ """A user can see all their own projects: live or archived."""
+ mr = MakeReqInfo(
+ self.regular_user, REGULAR_USER_ID, self.regular_user,
+ REGULAR_USER_ID, 'self@xyz.com')
+
+ page_data = self.servlet.GatherPageData(mr)
+
+ self.assertEqual('self@xyz.com', page_data['viewed_user_display_name'])
+ self.assertEqual(ezt.boolean(False), page_data['can_delete_user'])
+ self.assertProjectsAnyOrder(page_data['owner_of_projects'],
+ 'regular-owner-live')
+ self.assertProjectsAnyOrder(page_data['committer_of_projects'],
+ 'regular-member-live')
+ self.assertProjectsAnyOrder(
+ page_data['owner_of_archived_projects'],
+ 'regular-owner-archived')
+ self.mock_guspd.assert_called_once_with(
+ 111, mr.viewed_user_auth.user_view, mr.viewed_user_auth.user_pb,
+ None)
+
+ def testGatherPageData_RegularUserViewingStarredUsers(self):
+ """A user can see display names of other users that they starred."""
+ mr = MakeReqInfo(
+ self.regular_user, REGULAR_USER_ID, self.regular_user,
+ REGULAR_USER_ID, 'self@xyz.com')
+ self.servlet.services.user_star.SetStar(
+ 'cnxn', OTHER_USER_ID, REGULAR_USER_ID, True)
+
+ page_data = self.servlet.GatherPageData(mr)
+
+ starred_users = page_data['starred_users']
+ self.assertEqual(1, len(starred_users))
+ self.assertEqual('333@gmail.com', starred_users[0].email)
+ self.assertEqual('["3...@gmail.com"]', page_data['starred_users_json'])
+ self.mock_guspd.assert_called_once_with(
+ 111, mr.viewed_user_auth.user_view, mr.viewed_user_auth.user_pb,
+ None)
+
+ def testGatherPageData_AdminViewingOtherUserAddress(self):
+ """Site admins always see full email addresses of other users."""
+ mr = MakeReqInfo(
+ self.admin_user, ADMIN_USER_ID, self.other_user,
+ OTHER_USER_ID, 'other@xyz.com',
+ perms=permissions.ADMIN_PERMISSIONSET)
+
+ page_data = self.servlet.GatherPageData(mr)
+
+ self.assertEqual('other@xyz.com', page_data['viewed_user_display_name'])
+ self.assertEqual(ezt.boolean(True), page_data['can_delete_user'])
+ self.mock_guspd.assert_called_once_with(
+ 222, mr.viewed_user_auth.user_view, mr.viewed_user_auth.user_pb,
+ mock.ANY)
+
+ def testGatherPageData_RegularUserViewingOtherUserAddressUnobscured(self):
+ """Email should be revealed to others depending on obscure_email."""
+ mr = MakeReqInfo(
+ self.regular_user, REGULAR_USER_ID, self.other_user,
+ OTHER_USER_ID, 'other@xyz.com')
+ mr.viewed_user_auth.user_view.obscure_email = False
+
+ page_data = self.servlet.GatherPageData(mr)
+
+ self.assertEqual('other@xyz.com', page_data['viewed_user_display_name'])
+ self.mock_guspd.assert_called_once_with(
+ 111, mr.viewed_user_auth.user_view, mr.viewed_user_auth.user_pb,
+ None)
+
+ def testGatherPageData_RegularUserViewingOtherUserAddressObscured(self):
+ """Email should be revealed to others depending on obscure_email."""
+ mr = MakeReqInfo(
+ self.regular_user, REGULAR_USER_ID, self.other_user,
+ OTHER_USER_ID, 'other@xyz.com')
+ mr.viewed_user_auth.user_view.obscure_email = True
+
+ page_data = self.servlet.GatherPageData(mr)
+
+ self.assertEqual('ot...@xyz.com', page_data['viewed_user_display_name'])
+ self.assertEqual(ezt.boolean(False), page_data['can_delete_user'])
+ self.mock_guspd.assert_called_once_with(
+ 111, mr.viewed_user_auth.user_view, mr.viewed_user_auth.user_pb,
+ None)
+
+ def testGatherPageData_NoLinkedAccounts(self):
+ """An account with no linked accounts should not show anything linked."""
+ mr = MakeReqInfo(
+ self.regular_user, REGULAR_USER_ID, self.other_user,
+ OTHER_USER_ID, 'other@xyz.com')
+
+ page_data = self.servlet.GatherPageData(mr)
+
+ self.assertIsNone(page_data['linked_parent'])
+ self.assertEqual([], page_data['linked_children'])
+
+ def testGatherPageData_ParentAccounts(self):
+ """An account with a parent linked account should show it."""
+ self.other_user.linked_parent_id = REGULAR_USER_ID
+ mr = MakeReqInfo(
+ self.regular_user, REGULAR_USER_ID, self.other_user,
+ OTHER_USER_ID, 'other@xyz.com')
+
+ page_data = self.servlet.GatherPageData(mr)
+
+ self.assertEqual('111@gmail.com', page_data['linked_parent'].email)
+ self.assertEqual([], page_data['linked_children'])
+
+ def testGatherPageData_ChildAccounts(self):
+ """An account with a child linked account should show them."""
+ self.other_user.linked_child_ids = [REGULAR_USER_ID, ADMIN_USER_ID]
+ mr = MakeReqInfo(
+ self.regular_user, REGULAR_USER_ID, self.other_user,
+ OTHER_USER_ID, 'other@xyz.com')
+
+ page_data = self.servlet.GatherPageData(mr)
+
+ self.assertEqual(None, page_data['linked_parent'])
+ self.assertEqual(
+ ['111@gmail.com', '222@gmail.com'],
+ [uv.email for uv in page_data['linked_children']])
diff --git a/sitewide/test/usersettings_test.py b/sitewide/test/usersettings_test.py
new file mode 100644
index 0000000..54c14ae
--- /dev/null
+++ b/sitewide/test/usersettings_test.py
@@ -0,0 +1,66 @@
+# 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
+
+"""Tests for the user settings page."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+import mox
+
+from framework import framework_helpers
+from framework import permissions
+from framework import template_helpers
+from proto import user_pb2
+from services import service_manager
+from sitewide import usersettings
+from testing import fake
+from testing import testing_helpers
+
+
+class UserSettingsTest(unittest.TestCase):
+
+ def setUp(self):
+ self.mox = mox.Mox()
+ self.services = service_manager.Services(user=fake.UserService())
+ self.servlet = usersettings.UserSettings(
+ 'req', 'res', services=self.services)
+
+ def tearDown(self):
+ self.mox.UnsetStubs()
+
+ def testAssertBasePermission(self):
+ mr = testing_helpers.MakeMonorailRequest()
+ mr.auth.user_id = 111
+
+ # The following should return without exception.
+ self.servlet.AssertBasePermission(mr)
+
+ # No logged in user means anonymous access, should raise error.
+ mr.auth.user_id = 0
+ self.assertRaises(permissions.PermissionException,
+ self.servlet.AssertBasePermission, mr)
+
+ def testGatherPageData(self):
+ self.mox.StubOutWithMock(
+ framework_helpers.UserSettings, 'GatherUnifiedSettingsPageData')
+ framework_helpers.UserSettings.GatherUnifiedSettingsPageData(
+ 0, None, mox.IsA(user_pb2.User), mox.IsA(user_pb2.UserPrefs)
+ ).AndReturn({'unified': None})
+ self.mox.ReplayAll()
+
+ mr = testing_helpers.MakeMonorailRequest()
+ page_data = self.servlet.GatherPageData(mr)
+
+ self.assertItemsEqual(
+ ['logged_in_user_pb', 'unified', 'user_tab_mode',
+ 'viewed_user', 'offer_saved_queries_subtab', 'viewing_self'],
+ list(page_data.keys()))
+ self.assertEqual(template_helpers.PBProxy(mr.auth.user_pb),
+ page_data['logged_in_user_pb'])
+
+ self.mox.VerifyAll()
diff --git a/sitewide/test/userupdates_test.py b/sitewide/test/userupdates_test.py
new file mode 100644
index 0000000..efae9bc
--- /dev/null
+++ b/sitewide/test/userupdates_test.py
@@ -0,0 +1,115 @@
+# 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 monorail.sitewide.userupdates."""
+from __future__ import print_function
+from __future__ import division
+from __future__ import absolute_import
+
+import unittest
+
+import mox
+
+from features import activities
+from services import service_manager
+from sitewide import sitewide_helpers
+from sitewide import userupdates
+from testing import fake
+from testing import testing_helpers
+
+
+class ProjectUpdatesTest(unittest.TestCase):
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ project=fake.ProjectService(),
+ user_star=fake.UserStarService())
+
+ self.user_id = 2
+ self.project_id = 987
+ self.project = self.services.project.TestAddProject(
+ 'proj', project_id=self.project_id)
+
+ self.mr = testing_helpers.MakeMonorailRequest(
+ services=self.services, project=self.project)
+ self.mr.cnxn = 'fake cnxn'
+ self.mr.viewed_user_auth.user_id = 100
+
+ self.mox = mox.Mox()
+
+ def tearDown(self):
+ self.mox.UnsetStubs()
+ self.mox.ResetAll()
+
+ def testUserUpdatesProjects(self):
+ uup = userupdates.UserUpdatesProjects(None, None, self.services)
+
+ self.mox.StubOutWithMock(sitewide_helpers, 'GetViewableStarredProjects')
+ sitewide_helpers.GetViewableStarredProjects(
+ self.mr.cnxn, self.services, self.mr.viewed_user_auth.user_id,
+ self.mr.auth.effective_ids, self.mr.auth.user_pb).AndReturn(
+ [self.project])
+
+ self.mox.StubOutWithMock(activities, 'GatherUpdatesData')
+ activities.GatherUpdatesData(
+ self.services, self.mr, user_ids=None,
+ project_ids=[self.project_id],
+ ending=uup._ENDING,
+ updates_page_url=uup._UPDATES_PAGE_URL,
+ highlight=uup._HIGHLIGHT).AndReturn({})
+
+ self.mox.ReplayAll()
+
+ page_data = uup.GatherPageData(self.mr)
+ self.mox.VerifyAll()
+ self.assertEqual(3, len(page_data))
+ self.assertEqual('st5', page_data['user_tab_mode'])
+ self.assertEqual('yes', page_data['viewing_user_page'])
+ self.assertEqual(uup._TAB_MODE, page_data['user_updates_tab_mode'])
+
+ def testUserUpdatesDevelopers(self):
+ uud = userupdates.UserUpdatesDevelopers(None, None, self.services)
+
+ self.mox.StubOutWithMock(self.services.user_star, 'LookupStarredItemIDs')
+ self.services.user_star.LookupStarredItemIDs(
+ self.mr.cnxn, self.mr.viewed_user_auth.user_id).AndReturn(
+ [self.user_id])
+
+ self.mox.StubOutWithMock(activities, 'GatherUpdatesData')
+ activities.GatherUpdatesData(
+ self.services, self.mr, user_ids=[self.user_id],
+ project_ids=None, ending=uud._ENDING,
+ updates_page_url=uud._UPDATES_PAGE_URL,
+ highlight=uud._HIGHLIGHT).AndReturn({})
+
+ self.mox.ReplayAll()
+
+ page_data = uud.GatherPageData(self.mr)
+ self.mox.VerifyAll()
+ self.assertEqual(3, len(page_data))
+ self.assertEqual('st5', page_data['user_tab_mode'])
+ self.assertEqual('yes', page_data['viewing_user_page'])
+ self.assertEqual(uud._TAB_MODE, page_data['user_updates_tab_mode'])
+
+ def testUserUpdatesIndividual(self):
+ uui = userupdates.UserUpdatesIndividual(None, None, self.services)
+
+ self.mox.StubOutWithMock(activities, 'GatherUpdatesData')
+ activities.GatherUpdatesData(
+ self.services, self.mr,
+ user_ids=[self.mr.viewed_user_auth.user_id],
+ project_ids=None, ending=uui._ENDING,
+ updates_page_url=uui._UPDATES_PAGE_URL,
+ highlight=uui._HIGHLIGHT).AndReturn({})
+
+ self.mox.ReplayAll()
+
+ page_data = uui.GatherPageData(self.mr)
+ self.mox.VerifyAll()
+ self.assertEqual(3, len(page_data))
+ self.assertEqual('st5', page_data['user_tab_mode'])
+ self.assertEqual('yes', page_data['viewing_user_page'])
+ self.assertEqual(uui._TAB_MODE, page_data['user_updates_tab_mode'])
+