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