| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # coding=utf-8 | 2 # coding=utf-8 |
| 3 # Copyright 2015 The LUCI Authors. All rights reserved. | 3 # Copyright 2015 The LUCI Authors. All rights reserved. |
| 4 # Use of this source code is governed under the Apache License, Version 2.0 | 4 # Use of this source code is governed under the Apache License, Version 2.0 |
| 5 # that can be found in the LICENSE file. | 5 # that can be found in the LICENSE file. |
| 6 | 6 |
| 7 import base64 | 7 import base64 |
| 8 import datetime | 8 import datetime |
| 9 import json | 9 import json |
| 10 import logging | 10 import logging |
| (...skipping 1359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1370 } | 1370 } |
| 1371 self.assertEqual(expected, response.json) | 1371 self.assertEqual(expected, response.json) |
| 1372 | 1372 |
| 1373 | 1373 |
| 1374 class BotsApiTest(BaseTest): | 1374 class BotsApiTest(BaseTest): |
| 1375 api_service_cls = handlers_endpoints.SwarmingBotsService | 1375 api_service_cls = handlers_endpoints.SwarmingBotsService |
| 1376 | 1376 |
| 1377 def test_list_ok(self): | 1377 def test_list_ok(self): |
| 1378 """Asserts that BotInfo is returned for the appropriate set of bots.""" | 1378 """Asserts that BotInfo is returned for the appropriate set of bots.""" |
| 1379 self.set_as_privileged_user() | 1379 self.set_as_privileged_user() |
| 1380 then = datetime.datetime(2009, 1, 2, 3, 4, 5, 6) |
| 1381 then_str = unicode(then.strftime(self.DATETIME_FORMAT)) |
| 1382 self.mock_now(then) |
| 1383 # Add three bot events, corresponding to one dead bot, one quarantined bot, |
| 1384 # and one good bot |
| 1385 bot_management.bot_event( |
| 1386 event_type='bot_connected', bot_id='id3', |
| 1387 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', |
| 1388 dimensions={'foo': ['bar'], 'id': ['id3']}, state={'ram': 65}, |
| 1389 version='123456789', quarantined=False, task_id=None, task_name=None) |
| 1380 now = datetime.datetime(2010, 1, 2, 3, 4, 5, 6) | 1390 now = datetime.datetime(2010, 1, 2, 3, 4, 5, 6) |
| 1381 now_str = unicode(now.strftime(self.DATETIME_FORMAT)) | 1391 now_str = unicode(now.strftime(self.DATETIME_FORMAT)) |
| 1382 self.mock_now(now) | 1392 self.mock_now(now) |
| 1383 bot_management.bot_event( | 1393 bot_management.bot_event( |
| 1384 event_type='bot_connected', bot_id='id1', | 1394 event_type='bot_connected', bot_id='id1', |
| 1385 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', | 1395 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', |
| 1386 dimensions={'foo': ['bar'], 'id': ['id1']}, state={'ram': 65}, | 1396 dimensions={'foo': ['bar'], 'id': ['id1']}, state={'ram': 65}, |
| 1387 version='123456789', quarantined=False, task_id=None, task_name=None) | 1397 version='123456789', quarantined=False, task_id=None, task_name=None) |
| 1398 bot_management.bot_event( |
| 1399 event_type='bot_connected', bot_id='id2', |
| 1400 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', |
| 1401 dimensions={'foo': ['bar'], 'id': ['id2']}, state={'ram': 65}, |
| 1402 version='123456789', quarantined=True, task_id=None, task_name=None) |
| 1403 bot1 = { |
| 1404 u'authenticated_as': u'bot:whitelisted-ip', |
| 1405 u'bot_id': u'id1', |
| 1406 u'dimensions': [ |
| 1407 {u'key': u'foo', u'value': [u'bar']}, |
| 1408 {u'key': u'id', u'value': [u'id1']}, |
| 1409 ], |
| 1410 u'external_ip': u'8.8.4.4', |
| 1411 u'first_seen_ts': now_str, |
| 1412 u'is_dead': False, |
| 1413 u'last_seen_ts': now_str, |
| 1414 u'quarantined': False, |
| 1415 u'state': u'{"ram":65}', |
| 1416 u'version': u'123456789', |
| 1417 } |
| 1418 bot2 = { |
| 1419 u'authenticated_as': u'bot:whitelisted-ip', |
| 1420 u'bot_id': u'id2', |
| 1421 u'dimensions': [ |
| 1422 {u'key': u'foo', u'value': [u'bar']}, |
| 1423 {u'key': u'id', u'value': [u'id2']}, |
| 1424 ], |
| 1425 u'external_ip': u'8.8.4.4', |
| 1426 u'first_seen_ts': now_str, |
| 1427 u'is_dead': False, |
| 1428 u'last_seen_ts': now_str, |
| 1429 u'quarantined': True, |
| 1430 u'state': u'{"ram":65}', |
| 1431 u'version': u'123456789', |
| 1432 } |
| 1433 bot3 = { |
| 1434 u'authenticated_as': u'bot:whitelisted-ip', |
| 1435 u'bot_id': u'id3', |
| 1436 u'dimensions': [ |
| 1437 {u'key': u'foo', u'value': [u'bar']}, |
| 1438 {u'key': u'id', u'value': [u'id3']}, |
| 1439 ], |
| 1440 u'external_ip': u'8.8.4.4', |
| 1441 u'first_seen_ts': then_str, |
| 1442 u'is_dead': True, |
| 1443 u'last_seen_ts': then_str, |
| 1444 u'quarantined': False, |
| 1445 u'state': u'{"ram":65}', |
| 1446 u'version': u'123456789', |
| 1447 } |
| 1388 expected = { | 1448 expected = { |
| 1389 u'items': [ | 1449 u'items': [bot1, bot2, bot3], |
| 1390 { | |
| 1391 u'authenticated_as': u'bot:whitelisted-ip', | |
| 1392 u'bot_id': u'id1', | |
| 1393 u'dimensions': [ | |
| 1394 {u'key': u'foo', u'value': [u'bar']}, | |
| 1395 {u'key': u'id', u'value': [u'id1']}, | |
| 1396 ], | |
| 1397 u'external_ip': u'8.8.4.4', | |
| 1398 u'first_seen_ts': now_str, | |
| 1399 u'is_dead': False, | |
| 1400 u'last_seen_ts': now_str, | |
| 1401 u'quarantined': False, | |
| 1402 u'state': u'{"ram":65}', | |
| 1403 u'version': u'123456789', | |
| 1404 }, | |
| 1405 ], | |
| 1406 u'death_timeout': unicode(config.settings().bot_death_timeout_secs), | 1450 u'death_timeout': unicode(config.settings().bot_death_timeout_secs), |
| 1407 u'now': unicode(now.strftime(self.DATETIME_FORMAT)), | 1451 u'now': unicode(now.strftime(self.DATETIME_FORMAT)), |
| 1408 } | 1452 } |
| 1453 # All bots should be returned with no params |
| 1409 request = swarming_rpcs.BotsRequest() | 1454 request = swarming_rpcs.BotsRequest() |
| 1410 response = self.call_api('list', body=message_to_dict(request)) | 1455 response = self.call_api('list', body=message_to_dict(request)) |
| 1411 self.assertEqual(expected, response.json) | 1456 self.assertEqual(expected, response.json) |
| 1412 | 1457 # All bots should be returned if we don't care about quarantined |
| 1458 request = swarming_rpcs.BotsRequest( |
| 1459 quarantined=swarming_rpcs.ThreeStateBool.NONE) |
| 1460 response = self.call_api('list', body=message_to_dict(request)) |
| 1461 self.assertEqual(expected, response.json) |
| 1462 # All bots should be returned if we don't care about is_dead |
| 1463 request = swarming_rpcs.BotsRequest( |
| 1464 is_dead=swarming_rpcs.ThreeStateBool.NONE) |
| 1465 response = self.call_api('list', body=message_to_dict(request)) |
| 1466 self.assertEqual(expected, response.json) |
| 1467 # Only bot1 corresponds to these two dimensions |
| 1468 expected[u'items']=[bot1] |
| 1413 request = swarming_rpcs.BotsRequest(dimensions=['foo:bar', 'id:id1']) | 1469 request = swarming_rpcs.BotsRequest(dimensions=['foo:bar', 'id:id1']) |
| 1414 response = self.call_api('list', body=message_to_dict(request)) | 1470 response = self.call_api('list', body=message_to_dict(request)) |
| 1415 self.assertEqual(expected, response.json) | 1471 self.assertEqual(expected, response.json) |
| 1416 | 1472 # Only bot1 corresponds to being not dead and not quarantined and |
| 1473 # this dimension |
| 1474 request = swarming_rpcs.BotsRequest( |
| 1475 dimensions=['foo:bar'], |
| 1476 quarantined=swarming_rpcs.ThreeStateBool.FALSE, |
| 1477 is_dead=swarming_rpcs.ThreeStateBool.FALSE) |
| 1478 response = self.call_api('list', body=message_to_dict(request)) |
| 1479 self.assertEqual(expected, response.json) |
| 1480 # exclude bot2 only, which is quarantined |
| 1481 expected[u'items']=[bot1, bot3] |
| 1482 request = swarming_rpcs.BotsRequest( |
| 1483 quarantined=swarming_rpcs.ThreeStateBool.FALSE) |
| 1484 response = self.call_api('list', body=message_to_dict(request)) |
| 1485 self.assertEqual(expected, response.json) |
| 1486 # exclude bot3 only, which is dead |
| 1487 expected[u'items']=[bot1, bot2] |
| 1488 request = swarming_rpcs.BotsRequest( |
| 1489 is_dead=swarming_rpcs.ThreeStateBool.FALSE) |
| 1490 response = self.call_api('list', body=message_to_dict(request)) |
| 1491 self.assertEqual(expected, response.json) |
| 1492 # only bot2 is quarantined |
| 1493 expected[u'items']=[bot2] |
| 1494 request = swarming_rpcs.BotsRequest( |
| 1495 quarantined=swarming_rpcs.ThreeStateBool.TRUE) |
| 1496 response = self.call_api('list', body=message_to_dict(request)) |
| 1497 self.assertEqual(expected, response.json) |
| 1498 # quarantined:true can be paired with other dimensions and still work |
| 1499 request = swarming_rpcs.BotsRequest( |
| 1500 quarantined=swarming_rpcs.ThreeStateBool.TRUE, dimensions=['foo:bar']) |
| 1501 response = self.call_api('list', body=message_to_dict(request)) |
| 1502 self.assertEqual(expected, response.json) |
| 1503 # only bot3 is dead |
| 1504 expected[u'items']=[bot3] |
| 1505 request = swarming_rpcs.BotsRequest( |
| 1506 is_dead=swarming_rpcs.ThreeStateBool.TRUE) |
| 1507 response = self.call_api('list', body=message_to_dict(request)) |
| 1508 self.assertEqual(expected, response.json) |
| 1509 # is_dead:true can be paired with other dimensions and still work |
| 1510 request = swarming_rpcs.BotsRequest( |
| 1511 is_dead=swarming_rpcs.ThreeStateBool.TRUE, dimensions=['foo:bar']) |
| 1512 response = self.call_api('list', body=message_to_dict(request)) |
| 1513 self.assertEqual(expected, response.json) |
| 1514 # not:existing is a dimension that doesn't exist, nothing returned. |
| 1417 request = swarming_rpcs.BotsRequest(dimensions=['not:existing']) | 1515 request = swarming_rpcs.BotsRequest(dimensions=['not:existing']) |
| 1418 response = self.call_api('list', body=message_to_dict(request)) | 1516 response = self.call_api('list', body=message_to_dict(request)) |
| 1419 del expected[u'items'] | 1517 del expected[u'items'] |
| 1420 self.assertEqual(expected, response.json) | 1518 self.assertEqual(expected, response.json) |
| 1421 | 1519 # quarantined:true can be paired with other non-existing dimensions and |
| 1520 # still work |
| 1521 request = swarming_rpcs.BotsRequest( |
| 1522 quarantined=swarming_rpcs.ThreeStateBool.TRUE, dimensions=['not:exist']) |
| 1523 response = self.call_api('list', body=message_to_dict(request)) |
| 1524 self.assertEqual(expected, response.json) |
| 1525 # is_dead:true can be paired with other non-existing dimensions and |
| 1526 # still work |
| 1527 request = swarming_rpcs.BotsRequest( |
| 1528 is_dead=swarming_rpcs.ThreeStateBool.TRUE, dimensions=['not:exist']) |
| 1529 response = self.call_api('list', body=message_to_dict(request)) |
| 1530 self.assertEqual(expected, response.json) |
| 1531 # No bot is both dead and quarantined |
| 1532 request = swarming_rpcs.BotsRequest( |
| 1533 is_dead=swarming_rpcs.ThreeStateBool.TRUE, |
| 1534 quarantined=swarming_rpcs.ThreeStateBool.TRUE) |
| 1535 response = self.call_api('list', body=message_to_dict(request)) |
| 1536 self.assertEqual(expected, response.json) |
| 1537 # A bad request returns 400 |
| 1422 request = swarming_rpcs.BotsRequest(dimensions=['bad']) | 1538 request = swarming_rpcs.BotsRequest(dimensions=['bad']) |
| 1423 self.call_api('list', body=message_to_dict(request), status=400) | 1539 self.call_api('list', body=message_to_dict(request), status=400) |
| 1424 | 1540 |
| 1425 def test_count_ok(self): | 1541 def test_count_ok(self): |
| 1426 """Asserts that BotsCount is returned for the appropriate set of bots.""" | 1542 """Asserts that BotsCount is returned for the appropriate set of bots.""" |
| 1427 self.set_as_privileged_user() | 1543 self.set_as_privileged_user() |
| 1428 self.mock_now(datetime.datetime(2009, 1, 2, 3, 4, 5, 6)) | 1544 self.mock_now(datetime.datetime(2009, 1, 2, 3, 4, 5, 6)) |
| 1429 bot_management.bot_event( | 1545 bot_management.bot_event( |
| 1430 event_type='bot_connected', bot_id='id3', | 1546 event_type='bot_connected', bot_id='id3', |
| 1431 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', | 1547 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', |
| 1432 dimensions={'foo': ['bar'], 'id': ['id3']}, state={'ram': 65}, | 1548 dimensions={'foo': ['bar'], 'id': ['id3']}, state={'ram': 65}, |
| 1433 version='123456789', quarantined=True, task_id=None, task_name=None) | 1549 version='123456789', quarantined=True, task_id=None, task_name=None) |
| 1434 now = datetime.datetime(2010, 1, 2, 3, 4, 5, 6) | 1550 now = datetime.datetime(2010, 1, 2, 3, 4, 5, 6) |
| 1435 self.mock_now(now) | 1551 self.mock_now(now) |
| 1436 bot_management.bot_event( | 1552 bot_management.bot_event( |
| 1437 event_type='bot_connected', bot_id='id1', | 1553 event_type='bot_connected', bot_id='id1', |
| 1438 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', | 1554 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', |
| 1439 dimensions={'foo': ['bar'], 'id': ['id1']}, state={'ram': 65}, | 1555 dimensions={'foo': ['bar'], 'id': ['id1']}, state={'ram': 65}, |
| 1440 version='123456789', quarantined=False, task_id=None, task_name=None) | 1556 version='123456789', quarantined=False, task_id='987', task_name=None) |
| 1441 bot_management.bot_event( | 1557 bot_management.bot_event( |
| 1442 event_type='bot_connected', bot_id='id2', | 1558 event_type='bot_connected', bot_id='id2', |
| 1443 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', | 1559 external_ip='8.8.4.4', authenticated_as='bot:whitelisted-ip', |
| 1444 dimensions={'foo': ['bar'], 'id': ['id2']}, state={'ram': 65}, | 1560 dimensions={'foo': ['bar'], 'id': ['id2']}, state={'ram': 65}, |
| 1445 version='123456789', quarantined=True, task_id='987', task_name=None) | 1561 version='123456789', quarantined=True, task_id=None, task_name=None) |
| 1446 expected = { | 1562 expected = { |
| 1447 u'count': u'3', | 1563 u'count': u'3', |
| 1448 u'quarantined': u'2', | 1564 u'quarantined': u'2', |
| 1449 u'dead': u'1', | 1565 u'dead': u'1', |
| 1450 u'busy': u'1', | 1566 u'busy': u'1', |
| 1451 u'now': unicode(now.strftime(self.DATETIME_FORMAT)), | 1567 u'now': unicode(now.strftime(self.DATETIME_FORMAT)), |
| 1452 } | 1568 } |
| 1453 request = swarming_rpcs.BotsRequest() | 1569 request = swarming_rpcs.BotsRequest() |
| 1454 response = self.call_api('count', body=message_to_dict(request)) | 1570 response = self.call_api('count', body=message_to_dict(request)) |
| 1455 self.assertEqual(expected, response.json) | 1571 self.assertEqual(expected, response.json) |
| 1456 | 1572 |
| 1457 expected = { | 1573 expected = { |
| 1458 u'count': u'1', | 1574 u'count': u'1', |
| 1459 u'quarantined': u'0', | 1575 u'quarantined': u'0', |
| 1460 u'dead': u'0', | 1576 u'dead': u'0', |
| 1461 u'busy': u'0', | 1577 u'busy': u'1', |
| 1462 u'now': unicode(now.strftime(self.DATETIME_FORMAT)), | 1578 u'now': unicode(now.strftime(self.DATETIME_FORMAT)), |
| 1463 } | 1579 } |
| 1464 request = swarming_rpcs.BotsRequest(dimensions=['foo:bar', 'id:id1']) | 1580 request = swarming_rpcs.BotsCountRequest(dimensions=['foo:bar', 'id:id1']) |
| 1465 response = self.call_api('count', body=message_to_dict(request)) | 1581 response = self.call_api('count', body=message_to_dict(request)) |
| 1466 self.assertEqual(expected, response.json) | 1582 self.assertEqual(expected, response.json) |
| 1467 | 1583 |
| 1468 expected[u'quarantined'] = u'1' | 1584 expected[u'quarantined'] = u'1' |
| 1469 expected[u'busy'] = u'1' | 1585 expected[u'busy'] = u'0' |
| 1470 request = swarming_rpcs.BotsRequest(dimensions=['foo:bar', 'id:id2']) | 1586 request = swarming_rpcs.BotsCountRequest(dimensions=['foo:bar', 'id:id2']) |
| 1471 response = self.call_api('count', body=message_to_dict(request)) | 1587 response = self.call_api('count', body=message_to_dict(request)) |
| 1472 self.assertEqual(expected, response.json) | 1588 self.assertEqual(expected, response.json) |
| 1473 | 1589 |
| 1474 expected[u'dead'] = u'1' | 1590 expected[u'dead'] = u'1' |
| 1475 expected[u'busy'] = u'0' | 1591 request = swarming_rpcs.BotsCountRequest(dimensions=['foo:bar', 'id:id3']) |
| 1476 request = swarming_rpcs.BotsRequest(dimensions=['foo:bar', 'id:id3']) | |
| 1477 response = self.call_api('count', body=message_to_dict(request)) | 1592 response = self.call_api('count', body=message_to_dict(request)) |
| 1478 self.assertEqual(expected, response.json) | 1593 self.assertEqual(expected, response.json) |
| 1479 | 1594 |
| 1480 request = swarming_rpcs.BotsRequest(dimensions=['not:existing']) | 1595 request = swarming_rpcs.BotsCountRequest(dimensions=['not:existing']) |
| 1481 response = self.call_api('count', body=message_to_dict(request)) | 1596 response = self.call_api('count', body=message_to_dict(request)) |
| 1482 expected = { | 1597 expected = { |
| 1483 u'count': u'0', | 1598 u'count': u'0', |
| 1484 u'quarantined': u'0', | 1599 u'quarantined': u'0', |
| 1485 u'dead': u'0', | 1600 u'dead': u'0', |
| 1486 u'busy': u'0', | 1601 u'busy': u'0', |
| 1487 u'now': unicode(now.strftime(self.DATETIME_FORMAT)), | 1602 u'now': unicode(now.strftime(self.DATETIME_FORMAT)), |
| 1488 } | 1603 } |
| 1489 self.assertEqual(expected, response.json) | 1604 self.assertEqual(expected, response.json) |
| 1490 | 1605 |
| 1491 request = swarming_rpcs.BotsRequest(dimensions=['bad']) | 1606 request = swarming_rpcs.BotsCountRequest(dimensions=['bad']) |
| 1492 self.call_api('count', body=message_to_dict(request), status=400) | 1607 self.call_api('count', body=message_to_dict(request), status=400) |
| 1493 | 1608 |
| 1494 def test_dimensions_ok(self): | 1609 def test_dimensions_ok(self): |
| 1495 """Asserts that BotsDimensions is returned with the right data.""" | 1610 """Asserts that BotsDimensions is returned with the right data.""" |
| 1496 self.set_as_privileged_user() | 1611 self.set_as_privileged_user() |
| 1497 now = datetime.datetime(2009, 1, 2, 3, 4, 5, 6) | 1612 now = datetime.datetime(2009, 1, 2, 3, 4, 5, 6) |
| 1498 self.mock_now(now) | 1613 self.mock_now(now) |
| 1499 | 1614 |
| 1500 bot_management.DimensionAggregation( | 1615 bot_management.DimensionAggregation( |
| 1501 key=bot_management.DimensionAggregation.KEY, | 1616 key=bot_management.DimensionAggregation.KEY, |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1773 self.assertEqual(expected, response.json) | 1888 self.assertEqual(expected, response.json) |
| 1774 | 1889 |
| 1775 | 1890 |
| 1776 if __name__ == '__main__': | 1891 if __name__ == '__main__': |
| 1777 if '-v' in sys.argv: | 1892 if '-v' in sys.argv: |
| 1778 unittest.TestCase.maxDiff = None | 1893 unittest.TestCase.maxDiff = None |
| 1779 logging.basicConfig(level=logging.DEBUG) | 1894 logging.basicConfig(level=logging.DEBUG) |
| 1780 else: | 1895 else: |
| 1781 logging.basicConfig(level=logging.CRITICAL) | 1896 logging.basicConfig(level=logging.CRITICAL) |
| 1782 unittest.main() | 1897 unittest.main() |
| OLD | NEW |