blob: cdcd63af4d812fc234d9913dbf730a7d8a83dfc6 [file] [log] [blame]
#!/usr/bin/env vpython
# Copyright 2018 The LUCI Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
import datetime
import hashlib
import json
import logging
import sys
import unittest
# pylint: disable=wrong-import-position
import test_env
test_env.setup_test_env()
from google.appengine.ext import ndb
from components import utils
from server import bot_management
from server import named_caches
from server import pools_config
from test_support import test_case
def _bot_event(bot_id, pool, caches, oses):
"""Calls bot_management.bot_event with default arguments."""
dimensions = {
u'id': [bot_id],
u'os': oses or [u'Linux', u'Ubuntu', u'Ubuntu-16.04'],
u'pool': [pool],
}
# Format is named_caches: {name: [['shortname', size], timestamp]}.
state = {
'named_caches': {
name: [['a', size], 10] for name, size in caches.items()
}
}
bot_management.bot_event(
event_type='request_sleep',
bot_id=bot_id,
external_ip='8.8.4.4',
authenticated_as=u'bot:%s.domain' % bot_id,
dimensions=dimensions,
state=state or {'ram': 65},
version=unicode(hashlib.sha256().hexdigest()),
register_dimensions=True)
class NamedCachesTest(test_case.TestCase):
APP_DIR = test_env.APP_DIR
def setUp(self):
super(NamedCachesTest, self).setUp()
self.mock(utils, 'enqueue_task', self._enqueue_task)
self.mock(pools_config, 'known', lambda: ['first', 'second'])
@ndb.non_transactional
def _enqueue_task(self, url, queue_name, payload):
if queue_name == 'named-cache-task':
params = json.loads(payload)
self.assertEqual(True, named_caches.task_update_pool(params['pool']))
return True
self.fail(url)
return False
def test_simple(self):
_bot_event('first1', 'first', {'git': 1}, None)
_bot_event('first2', 'first', {'build': 100000, 'git': 1000}, None)
self.assertEqual(2, named_caches.cron_update_named_caches())
self.assertEqual(2, named_caches.NamedCache.query().count())
oses = ['Linux']
hints = named_caches.get_hints('first', oses, ['git', 'build', 'new'])
self.assertEqual([1000, 100000, -1], hints)
def test_p95(self):
# Create 45 bots with cache 'foo' size between 1 and 45.
for i in range(45):
_bot_event('second%d' % i, 'second', {'foo': i + 1}, None)
self.assertEqual(2, named_caches.cron_update_named_caches())
self.assertEqual(1, named_caches.NamedCache.query().count())
oses = ['Linux']
hints = named_caches.get_hints('second', oses, ['foo'])
# Roughly p95.
self.assertEqual([43], hints)
def test_fuzzy_other_os(self):
# Use the hint from 'Mac' (the larger one) even if requesting for Linux.
_bot_event('first1', 'first', {'build': 50000}, ['Android'])
_bot_event('first2', 'first', {'build': 100000}, ['Mac'])
self.assertEqual(2, named_caches.cron_update_named_caches())
self.assertEqual(2, named_caches.NamedCache.query().count())
oses = ['Linux']
hints = named_caches.get_hints('first', oses, ['build'])
self.assertEqual([100000], hints)
def test_expired(self):
now = datetime.datetime(2015, 1, 1, 1, 1, 1)
self.mock_now(now)
_bot_event('first1', 'first', {'build': 100000}, ['Mac'])
self.assertEqual(2, named_caches.cron_update_named_caches())
self.assertEqual([now], [e.ts for e in named_caches.NamedCache.query()])
self.mock_now(now, 8 * 24 * 60 * 60)
self.assertEqual(2, named_caches.cron_update_named_caches())
self.assertEqual(1, named_caches.NamedCache.query().count())
self.assertEqual([now], [e.ts for e in named_caches.NamedCache.query()])
self.mock_now(now, 8 * 24 * 60 * 60 + 1)
self.assertEqual(2, named_caches.cron_update_named_caches())
self.assertEqual(0, named_caches.NamedCache.query().count())
if __name__ == '__main__':
if '-v' in sys.argv:
unittest.TestCase.maxDiff = None
logging.basicConfig(
level=logging.DEBUG if '-v' in sys.argv else logging.CRITICAL)
unittest.main()