blob: 231781dfcc5a2c6d689a8b133eccfb502a7f1663 [file] [log] [blame]
# Copyright 2017 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import base64
import json
import logging
import mock
import os
import sys
import time
import unittest
import google
from common import rpc_util
from common.findit_http_client import FinditHttpClient
from infra_api_clients import logdog_util
from waterfall.test import wf_testcase
third_party = os.path.join(
os.path.dirname(__file__), os.path.pardir, os.path.pardir, 'third_party')
sys.path.insert(0, third_party)
google.__path__.append(os.path.join(third_party, 'google'))
from logdog import annotations_pb2
def _GenerateGetResJson(value):
data = {'logs': [{'text': {'lines': [{'value': value}, {'other': '\n'}]}}]}
return json.dumps(data)
_SAMPLE_GET_RESPONSE = _GenerateGetResJson(
json.dumps(wf_testcase.SAMPLE_STEP_METADATA))
def _CreateProtobufMessage(step_name,
stdout_stream,
step_metadata_stream,
label='step_metadata'):
step = annotations_pb2.Step()
message = step.substep.add().step
message.name = step_name
message.stdout_stream.name = stdout_stream
link = message.other_links.add(label=label)
link.logdog_stream.name = step_metadata_stream
return step
class LogDogUtilTest(unittest.TestCase):
def setUp(self):
super(LogDogUtilTest, self).setUp()
self.http_client = FinditHttpClient()
self.master_name = 'tryserver.m'
self.builder_name = 'b'
self.build_number = 123
self.step_name = 'browser_tests on platform'
self.build_data = {
'result_details_json':
json.dumps({
'properties': {
'log_location': 'logdog://h/p/path'
}
})
}
self.stdout_stream = 'stdout_stream'
self.step_metadata_stream = 'step_metadata_stream'
def _GenerateTailRes(self):
step_proto = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream)
step_log = step_proto.SerializeToString()
step_b64 = base64.b64encode(step_log)
tail_res_json = {'logs': [{'datagram': {'data': step_b64}}]}
return json.dumps(tail_res_json)
def testProcessStringForLogDog(self):
builder_name = 'Mac 10.10 Release (Intel)'
expected_builder_name = 'Mac_10.10_Release__Intel_'
self.assertEqual(expected_builder_name,
logdog_util._ProcessStringForLogDog(builder_name))
def testProcessAnnotationsToGetStreamForStepMetadata(self):
step_proto = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream)
log_stream = logdog_util._GetStreamForStep(self.step_name, step_proto,
'step_metadata')
self.assertEqual(log_stream, self.step_metadata_stream)
def testProcessAnnotationsToGetStreamForStdout(self):
step_proto = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream)
log_stream = logdog_util._GetStreamForStep(self.step_name, step_proto)
self.assertEqual(log_stream, self.stdout_stream)
def testProcessAnnotationsToGetStreamNoStep(self):
step = _CreateProtobufMessage('step', self.stdout_stream,
self.step_metadata_stream)
log_stream = logdog_util._GetStreamForStep(self.step_name, step,
'step_metadata')
self.assertIsNone(log_stream)
def testProcessAnnotationsToGetStreamNoStepMetadta(self):
step = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream, 'step')
log_stream = logdog_util._GetStreamForStep(self.step_name, step,
'step_metadata')
self.assertIsNone(log_stream)
@mock.patch.object(rpc_util, 'DownloadJsonData')
def testGetAnnotationsProto(self, mock_fn):
mock_fn.return_value = (200, self._GenerateTailRes())
step = logdog_util._GetAnnotationsProtoForPath('host', 'project', 'path',
self.http_client)
self.assertIsNotNone(step)
@mock.patch.object(rpc_util, 'DownloadJsonData', return_value=(500, None))
def testGetAnnotationsProtoNoResponse(self, _):
step = logdog_util._GetAnnotationsProtoForPath('host', 'project', 'path',
self.http_client)
self.assertIsNone(step)
@mock.patch.object(
rpc_util, 'DownloadJsonData', return_value=(200, json.dumps({
'a': 'a'
})))
def testGetAnnotationsProtoNoLogs(self, _):
step = logdog_util._GetAnnotationsProtoForPath('host', 'project', 'path',
self.http_client)
self.assertIsNone(step)
@mock.patch.object(rpc_util, 'DownloadJsonData')
def testGetAnnotationsProtoNoAnnotationsB64(self, mock_fn):
data = {'logs': [{'data': 'data'}]}
mock_fn.return_value = (200, json.dumps(data))
step = logdog_util._GetAnnotationsProtoForPath('host', 'project', 'path',
self.http_client)
self.assertIsNone(step)
@mock.patch.object(rpc_util, 'DownloadJsonData')
def testGetAnnotationsProtoNoB64decodable(self, mock_fn):
data = {'logs': [{'datagram': {'data': 'data'}}]}
mock_fn.return_value = (200, json.dumps(data))
step = logdog_util._GetAnnotationsProtoForPath('host', 'project', 'path',
self.http_client)
self.assertIsNone(step)
@mock.patch.object(rpc_util, 'DownloadJsonData')
def testGetAnnotationsProtoUseGet(self, mock_fn):
step_proto = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream)
step_log = step_proto.SerializeToString()
step_log_p1 = step_log[:len(step_log) / 2]
step_log_p2 = step_log[len(step_log) / 2:]
data1 = {
'logs': [{
'streamIndex': 1,
'datagram': {
'data': base64.b64encode(step_log_p2),
'partial': {
'index': 1,
'size': 1234
}
}
}]
}
data2 = {
'logs': [{
'streamIndex': 0,
'datagram': {
'data': base64.b64encode(step_log_p1),
'partial': {
'size': 1234
}
}
},
{
'streamIndex': 1,
'datagram': {
'data': base64.b64encode(step_log_p2),
'partial': {
'index': 1,
'size': 1234
}
}
}]
}
mock_fn.side_effect = [(200, json.dumps(data1)), (200, json.dumps(data2))]
step = logdog_util._GetAnnotationsProtoForPath('host', 'project', 'path',
self.http_client)
self.assertIsNotNone(step)
@mock.patch.object(rpc_util, 'DownloadJsonData')
def testGetAnnotationsProtoGetReturnsNone(self, mock_fn):
step_proto = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream)
step_log = step_proto.SerializeToString()
step_log_p2 = step_log[len(step_log) / 2:]
data1 = {
'logs': [{
'streamIndex': 1,
'datagram': {
'data': base64.b64encode(step_log_p2),
'partial': {
'index': 1,
'size': 1234
}
}
}]
}
mock_fn.side_effect = [(200, json.dumps(data1)), (200, None)]
step = logdog_util._GetAnnotationsProtoForPath('host', 'project', 'path',
self.http_client)
self.assertIsNone(step)
def testGetQueryParametersForAnnotationForBuildbotBuild(self):
log_location = ('logdog://logs.chromium.org/chromium/bb/m/b/1/+/recipes/'
'annotations')
host, project, path = logdog_util._GetQueryParametersForAnnotation(
log_location)
self.assertEqual('logs.chromium.org', host)
self.assertEqual('chromium', project)
self.assertEqual('bb/m/b/1/+/recipes/annotations', path)
def testGetQueryParametersForAnnotationForLUCIBuild(self):
log_location = ('logdog://logs.chromium.org/chromium/buildbucket/cr-bui'
'ldbucket.appspot.com/8948240770002521488/+/annotations')
host, project, path = logdog_util._GetQueryParametersForAnnotation(
log_location)
self.assertEqual('logs.chromium.org', host)
self.assertEqual('chromium', project)
self.assertEqual(
'buildbucket/cr-buildbucket.appspot.com/8948240'
'770002521488/+/annotations', path)
def testGetQueryParametersForAnnotationNone(self):
host, project, path = logdog_util._GetQueryParametersForAnnotation(None)
self.assertIsNone(host)
self.assertIsNone(project)
self.assertIsNone(path)
@mock.patch.object(rpc_util, 'DownloadJsonData')
@mock.patch.object(logdog_util, '_GetLog')
def testGetStepLogLegacy(self, mock_log, mock_data):
mock_data.return_value = (200, self._GenerateTailRes())
logdog_util.GetStepLogLegacy('logdog://logdog.com/project/path', 'step',
'stdout', self.http_client)
self.assertTrue(mock_log.called)
def testGetStepLogLegacyNoLogLocation(self):
self.assertIsNone(
logdog_util.GetStepLogLegacy(None, 'step', 'stdout', self.http_client))
def testGetLogNoAnnotations(self):
self.assertIsNone(
logdog_util._GetLog(None, self.step_name, 'stdout', self.http_client))
def testGetLogNoStream(self):
annotations = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream)
self.assertIsNone(
logdog_util._GetLog(annotations, 'NOT' + self.step_name, 'stdout',
self.http_client))
def testGetLogNoHost(self):
annotations = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream)
env = annotations.command.environ
env['LOGDOG_STREAM_PREFIX'] = 'path'
env['LOGDOG_STREAM_PROJECT'] = 'project'
self.assertIsNone(
logdog_util._GetLog(annotations, self.step_name, 'stdout',
self.http_client))
@mock.patch.object(
FinditHttpClient, 'Get', return_value=(404, None, 'header'))
@mock.patch.object(logging, 'error')
def testGetLogRequestFail(self, mock_log, _):
annotations = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream)
env = annotations.command.environ
env['LOGDOG_STREAM_PREFIX'] = 'path'
env['LOGDOG_COORDINATOR_HOST'] = 'logdog.com'
env['LOGDOG_STREAM_PROJECT'] = 'project'
self.assertIsNone(
logdog_util._GetLog(annotations, self.step_name, 'stdout',
self.http_client))
url = ('https://logdog.com/logs/project/path/+/%s?format=raw' %
self.stdout_stream)
mock_log.assert_called_once_with(
'Failed to get the log from %s: status_code-%d, log-%s', url, 404, None)
@mock.patch.object(FinditHttpClient, 'Get')
def testGetLog(self, mock_get):
annotations = _CreateProtobufMessage(self.step_name, self.stdout_stream,
self.step_metadata_stream)
env = annotations.command.environ
env['LOGDOG_STREAM_PREFIX'] = 'path'
env['LOGDOG_COORDINATOR_HOST'] = 'logdog.com'
env['LOGDOG_STREAM_PROJECT'] = 'project'
dummy_result = {"a": "b"}
mock_get.return_value = (200, dummy_result, 'header')
self.assertEqual(
dummy_result,
logdog_util._GetLog(annotations, self.step_name, 'step_metadata',
self.http_client))
mock_get.assert_called_once_with(
'https://logdog.com/logs/project/path/+/%s?format=raw' %
self.step_metadata_stream)