1e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved. 2e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 3e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)# found in the LICENSE file. 4e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 5e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)import alerts 6e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)import json 7e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)import random 8e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)import string 9e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)import unittest 10e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)import webtest 11e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 12e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)from google.appengine.api import memcache 13e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)from google.appengine.ext import testbed 14e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 15e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 16e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)class AlertsTest(unittest.TestCase): 17e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def setUp(self): 18e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testbed = testbed.Testbed() 19e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testbed.activate() 20e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testbed.init_memcache_stub() 21e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testapp = webtest.TestApp(alerts.app) 22e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 23e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def tearDown(self): 24e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testbed.deactivate() 25e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 26e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def check_json_headers(self, res): 27e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.assertEqual(res.content_type, 'application/json') 28e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) # This is necessary for cross-site tools to retrieve alerts 29e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.assertEqual(res.headers['access-control-allow-origin'], '*') 30e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 31e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def test_get_no_data_cached(self): 32e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) res = self.testapp.get('/alerts') 33e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.check_json_headers(res) 34e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.assertEqual(res.body, '') 35e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 36e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def test_happy_path(self): 37e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) # Set it. 38e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) params = {'content': '{"alerts": ["hello", "world"]}'} 39e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testapp.post('/alerts', params) 40e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 41e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) # Get it. 42e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) res = self.testapp.get('/alerts') 43e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.check_json_headers(res) 44e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) alerts = json.loads(res.body) 45e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 46e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) # The server should have stuck a 'date' on there. 47e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.assertTrue('date' in alerts) 48e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.assertEqual(type(alerts['date']), int) 49e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 50e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.assertEqual(alerts['alerts'], ['hello', 'world']) 51e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 52e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def test_post_invalid_data_not_reflected(self): 53e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) params = {'content': '[{"this is not valid JSON'} 54e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testapp.post('/alerts', params, status=400) 55e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) res = self.testapp.get('/alerts') 56e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.assertEqual(res.body, '') 57e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 58e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def test_post_invalid_data_does_not_overwrite_valid_data(self): 59e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) # Populate the cache with something valid 60e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) params = {'content': '{"alerts": "everything is OK"}'} 61e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testapp.post('/alerts', params) 62e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testapp.post('/alerts', {'content': 'woozlwuzl'}, status=400) 63e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) res = self.testapp.get('/alerts') 64e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.check_json_headers(res) 65e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) alerts = json.loads(res.body) 66e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.assertEqual(alerts['alerts'], 'everything is OK') 67e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 68e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def test_large_number_of_alerts(self): 69e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) # This generates ~2.5MB of JSON that compresses to ~750K. Real 70e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) # data compresses about 6x better. 71e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) random.seed(0xf00f00) 72e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) put_alerts = self.generate_fake_alerts(4000) 73e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 74e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) params = {'content': json.dumps(put_alerts)} 75e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.testapp.post('/alerts', params) 76e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 77e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) res = self.testapp.get('/alerts') 78e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) got_alerts = json.loads(res.body) 79e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self.assertEquals(got_alerts['alerts'], put_alerts['alerts']) 80e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 81e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def generate_fake_alerts(self, n): 82e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return {'alerts': [self.generate_fake_alert() for _ in range(n)]} 83e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 84e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def generate_fake_alert(self): 85e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) # fake labels 86e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) labels = [['', 'last_', 'latest_', 'failing_', 'passing_'], 87e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) ['build', 'builder', 'revision'], 88e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) ['', 's', '_url', '_reason', '_name']] 89e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 90e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def label(): 91e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return string.join(map(random.choice, labels), '') 92e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 93e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) # fake values 94e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def time(): 95e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return random.randint(1407976107614, 1408076107614) / 101.0 96e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 97e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def build(): 98e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return random.randint(2737, 2894) 99e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 100e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def revision(): 101e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return random.randint(288849, 289415) 102e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 103e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) tests = [['Activity', 'Async', 'Browser', 'Content', 'Input'], 104e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) ['Manager', 'Card', 'Sandbox', 'Container'], 105e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) ['Test.'], 106e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) ['', 'Basic', 'Empty', 'More'], 107e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) ['Mouse', 'App', 'Selection', 'Network', 'Grab'], 108e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) ['Input', 'Click', 'Failure', 'Capture']] 109e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 110e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def test(): 111e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return string.join(map(random.choice, tests), '') 112e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 113e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def literal_array(): 114e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) generator = random.choice([time, build, revision]) 115e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return [generator() for _ in range(random.randint(0, 10))] 116e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 117e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def literal_map(): 118e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) generators = [build, revision, test, literal_array] 119e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) obj = {} 120e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) for _ in range(random.randint(3, 9)): 121e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) obj[label()] = random.choice(generators)() 122e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return obj 123e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 124e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) def value(): 125e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) generators = [time, build, revision, test, literal_array, 126e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) literal_map] 127e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return random.choice(generators)() 128e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) 129e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) alert = {} 130e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) for _ in range(random.randint(6, 9)): 131e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) alert[label()] = value() 132e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) return alert 133