1# Copyright 2015 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import unittest 6 7import webapp2 8import webtest 9 10from google.appengine.api import users 11 12from dashboard import edit_site_config 13from dashboard import namespaced_stored_object 14from dashboard import stored_object 15from dashboard import testing_common 16from dashboard import xsrf 17 18 19class EditSiteConfigTest(testing_common.TestCase): 20 21 def setUp(self): 22 super(EditSiteConfigTest, self).setUp() 23 app = webapp2.WSGIApplication( 24 [('/edit_site_config', edit_site_config.EditSiteConfigHandler)]) 25 self.testapp = webtest.TestApp(app) 26 testing_common.SetIsInternalUser('internal@chromium.org', True) 27 testing_common.SetIsInternalUser('foo@chromium.org', False) 28 self.SetCurrentUser('internal@chromium.org', is_admin=True) 29 30 def testGet_NoKey_ShowsPageWithNoTextArea(self): 31 response = self.testapp.get('/edit_site_config') 32 self.assertEqual(0, len(response.html('textarea'))) 33 34 def testGet_WithNonNamespacedKey_ShowsPageWithCurrentValue(self): 35 stored_object.Set('foo', 'XXXYYY') 36 response = self.testapp.get('/edit_site_config?key=foo') 37 self.assertEqual(1, len(response.html('form'))) 38 self.assertIn('XXXYYY', response.body) 39 40 def testGet_WithNamespacedKey_ShowsPageWithBothVersions(self): 41 namespaced_stored_object.Set('foo', 'XXXYYY') 42 namespaced_stored_object.SetExternal('foo', 'XXXinternalYYY') 43 response = self.testapp.get('/edit_site_config?key=foo') 44 self.assertEqual(1, len(response.html('form'))) 45 self.assertIn('XXXYYY', response.body) 46 self.assertIn('XXXinternalYYY', response.body) 47 48 def testPost_NoXsrfToken_ReturnsErrorStatus(self): 49 self.testapp.post('/edit_site_config', { 50 'key': 'foo', 51 'value': '[1, 2, 3]', 52 }, status=403) 53 54 def testPost_ExternalUser_ShowsErrorMessage(self): 55 self.SetCurrentUser('foo@chromium.org') 56 response = self.testapp.post('/edit_site_config', { 57 'key': 'foo', 58 'value': '[1, 2, 3]', 59 'xsrf_token': xsrf.GenerateToken(users.get_current_user()), 60 }) 61 self.assertIn('Only internal users', response.body) 62 63 def testPost_WithKey_UpdatesNonNamespacedValues(self): 64 self.testapp.post('/edit_site_config', { 65 'key': 'foo', 66 'value': '[1, 2, 3]', 67 'xsrf_token': xsrf.GenerateToken(users.get_current_user()), 68 }) 69 self.assertEqual([1, 2, 3], stored_object.Get('foo')) 70 71 def testPost_WithSomeInvalidJSON_ShowsErrorAndDoesNotModify(self): 72 stored_object.Set('foo', 'XXX') 73 response = self.testapp.post('/edit_site_config', { 74 'key': 'foo', 75 'value': '[1, 2, this is not json', 76 'xsrf_token': xsrf.GenerateToken(users.get_current_user()), 77 }) 78 self.assertIn('Invalid JSON', response.body) 79 self.assertEqual('XXX', stored_object.Get('foo')) 80 81 def testPost_WithKey_UpdatesNamespacedValues(self): 82 namespaced_stored_object.Set('foo', 'XXXinternalYYY') 83 namespaced_stored_object.SetExternal('foo', 'XXXYYY') 84 self.testapp.post('/edit_site_config', { 85 'key': 'foo', 86 'external_value': '{"x": "y"}', 87 'internal_value': '{"x": "yz"}', 88 'xsrf_token': xsrf.GenerateToken(users.get_current_user()), 89 }) 90 self.assertEqual({'x': 'yz'}, namespaced_stored_object.Get('foo')) 91 self.assertEqual({'x': 'y'}, namespaced_stored_object.GetExternal('foo')) 92 93 def testPost_SendsNotificationEmail(self): 94 namespaced_stored_object.SetExternal('foo', {'x': 10, 'y': 2}) 95 namespaced_stored_object.Set('foo', {'z': 3, 'x': 1}) 96 self.testapp.post('/edit_site_config', { 97 'key': 'foo', 98 'external_value': '{"x": 1, "y": 2}', 99 'internal_value': '{"x": 1, "z": 3, "y": 2}', 100 'xsrf_token': xsrf.GenerateToken(users.get_current_user()), 101 }) 102 messages = self.mail_stub.get_sent_messages() 103 self.assertEqual(1, len(messages)) 104 self.assertEqual('gasper-alerts@google.com', messages[0].sender) 105 self.assertEqual('chrome-perf-dashboard-alerts@google.com', messages[0].to) 106 self.assertEqual( 107 'Config "foo" changed by internal@chromium.org', messages[0].subject) 108 self.assertIn( 109 'Non-namespaced value diff:\n' 110 ' null\n' 111 '\n' 112 'Externally-visible value diff:\n' 113 ' {\n' 114 '- "x": 10, \n' 115 '? -\n' 116 '\n' 117 '+ "x": 1, \n' 118 ' "y": 2\n' 119 ' }\n' 120 '\n' 121 'Internal-only value diff:\n' 122 ' {\n' 123 ' "x": 1, \n' 124 '+ "y": 2, \n' 125 ' "z": 3\n' 126 ' }\n', 127 str(messages[0].body)) 128 129 130class HelperFunctionTests(unittest.TestCase): 131 132 def testDiffJson_NoneToEmptyString(self): 133 self.assertEqual('- null\n+ ""', edit_site_config._DiffJson(None, '')) 134 135 def testDiffJson_AddListItem(self): 136 self.assertEqual( 137 ' [\n 1, \n+ 2, \n 3\n ]', 138 edit_site_config._DiffJson([1, 3], [1, 2, 3])) 139 140 141if __name__ == '__main__': 142 unittest.main() 143