blob: f767cdd446483cd8bbeaa8c9c507637db1b354ba [file]
#!/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 = {
"id": [bot_id],
"os": oses or ["Linux", "Ubuntu", "Ubuntu-16.04"],
"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="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()