blob: abb554443c52c87c0467ef764b014016857dcb64 [file] [log] [blame] [edit]
# Copyright 2019 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unittests for goma_lib.py"""
import datetime
import getpass
import gzip
import json
import os
from pathlib import Path
import time
from chromite.lib import cros_build_lib
from chromite.lib import cros_test_lib
from chromite.lib import goma_lib
from chromite.lib import osutils
class GomaTest(cros_test_lib.TempDirTestCase, cros_test_lib.RunCommandTestCase):
"""Tests for the Goma object."""
def setUp(self):
self.goma_dir = self.tempdir / 'goma'
self.goma_client_json = self.tempdir / 'goma_client.json'
self.chroot_dir = self.tempdir / 'chroot'
self.chroot_tmp = self.chroot_dir / 'tmp'
self.log_dir = self.chroot_tmp / 'log_dir'
self.goma_client_json.touch()
osutils.SafeMakedirs(self.goma_dir)
osutils.SafeMakedirs(self.chroot_tmp)
def testExtraEnvCustomChroot(self):
"""Test the chroot env building with a custom chroot location."""
stats_filename = 'stats_filename'
counterz_filename = 'counterz_filename'
goma = goma_lib.Goma(
self.goma_dir,
self.goma_client_json,
chroot_dir=self.chroot_dir,
log_dir=self.log_dir,
stats_filename=stats_filename,
counterz_filename=counterz_filename)
env = goma.GetExtraEnv()
chroot_env = goma.GetChrootExtraEnv()
# Make sure the chroot paths got translated.
self.assertStartsWith(chroot_env['GOMA_TMP_DIR'], '/tmp')
self.assertStartsWith(chroot_env['GLOG_log_dir'], '/tmp/log_dir')
# Make sure the non-chroot paths didn't get translated.
self.assertStartsWith(env['GOMA_TMP_DIR'], str(self.chroot_tmp))
self.assertStartsWith(env['GLOG_log_dir'], str(self.log_dir))
# Make sure they're based on the same path.
self.assertEndsWith(env['GOMA_TMP_DIR'], chroot_env['GOMA_TMP_DIR'])
self.assertEndsWith(env['GLOG_log_dir'], chroot_env['GLOG_log_dir'])
# Make sure the stats file gets set correctly.
self.assertStartsWith(env['GOMA_DUMP_STATS_FILE'], str(self.log_dir))
self.assertEndsWith(env['GOMA_DUMP_STATS_FILE'], stats_filename)
self.assertStartsWith(chroot_env['GOMA_DUMP_STATS_FILE'], '/tmp/log_dir')
self.assertEndsWith(chroot_env['GOMA_DUMP_STATS_FILE'], stats_filename)
self.assertEndsWith(env['GOMA_DUMP_STATS_FILE'],
chroot_env['GOMA_DUMP_STATS_FILE'])
# Make sure the counterz file gets set correctly.
self.assertStartsWith(env['GOMA_DUMP_COUNTERZ_FILE'], str(self.log_dir))
self.assertEndsWith(env['GOMA_DUMP_COUNTERZ_FILE'], counterz_filename)
self.assertStartsWith(chroot_env['GOMA_DUMP_COUNTERZ_FILE'], '/tmp/log_dir')
self.assertEndsWith(chroot_env['GOMA_DUMP_COUNTERZ_FILE'],
counterz_filename)
self.assertEndsWith(env['GOMA_DUMP_COUNTERZ_FILE'],
chroot_env['GOMA_DUMP_COUNTERZ_FILE'])
def testExtraEnvGomaApproach(self):
"""Test the chroot env building with a goma approach."""
goma_approach = goma_lib.GomaApproach('foo', 'bar', True)
goma = goma_lib.Goma(
self.goma_dir,
self.goma_client_json,
chroot_dir=self.chroot_dir,
goma_approach=goma_approach)
env = goma.GetExtraEnv()
# Make sure the extra environment specified by goma_approach is present.
self.assertEqual(env['GOMA_RPC_EXTRA_PARAMS'], 'foo')
self.assertEqual(env['GOMA_SERVER_HOST'], 'bar')
self.assertEqual(env['GOMA_ARBITRARY_TOOLCHAIN_SUPPORT'], 'true')
def testInvalidArg(self):
"""Test invalid Goma input arguments."""
with self.assertRaises(ValueError):
goma_lib.Goma(Path('some/path'), self.goma_client_json)
with self.assertRaises(ValueError):
goma_lib.Goma(self.goma_dir, Path('some/path/goma_client.json'))
def testCommand(self):
"""Test Goma instance command interface."""
goma_ctl = self.goma_dir / 'goma_ctl.py'
goma = goma_lib.Goma(self.goma_dir, None)
goma.Start()
self.assertCommandContains([goma_ctl, 'start'])
goma.Restart()
self.assertCommandContains([goma_ctl, 'restart'])
goma.Stop()
self.assertCommandContains([goma_ctl, 'stop'])
class TestLogsArchiver(cros_test_lib.MockTempDirTestCase):
"""Tests for goma_lib.LogsArchiver."""
def setUp(self):
self.goma_log_dir = os.path.join(self.tempdir, 'goma_log_dir')
osutils.SafeMakedirs(self.goma_log_dir)
self.dest_dir = os.path.join(self.tempdir, 'destination_dir')
osutils.SafeMakedirs(self.dest_dir)
def _CreateFile(self, name: str):
"""Creates a basic file, such as a stats or counterz file.
Args:
name: Filename
"""
osutils.WriteFile(os.path.join(self.goma_log_dir, name), 'File: ' + name)
def _CreateLogFile(self, name: str, timestamp: datetime.datetime):
"""Creates a log file for testing.
Args:
name: Log file name.
timestamp: timestamp that is written to the file.
"""
path = os.path.join(
self.goma_log_dir,
'%s.host.log.INFO.%s' % (name, timestamp.strftime('%Y%m%d-%H%M%S.%f')))
osutils.WriteFile(
path,
timestamp.strftime('Log file created at: %Y/%m/%d %H:%M:%S'))
def testArchive(self):
"""Test successful archive of goma logs without stats/counterz specified."""
self._CreateLogFile(
'compiler_proxy', datetime.datetime(2017, 4, 26, 12, 0, 0))
self._CreateLogFile(
'compiler_proxy-subproc', datetime.datetime(2017, 4, 26, 12, 0, 0))
self._CreateLogFile(
'gomacc', datetime.datetime(2017, 4, 26, 12, 1, 0))
self._CreateLogFile(
'gomacc', datetime.datetime(2017, 4, 26, 12, 2, 0))
archiver = goma_lib.LogsArchiver(self.goma_log_dir, dest_dir=self.dest_dir)
archiver_tuple = archiver.Archive()
# Verify that no stats/counterz was returned in the tuple.
self.assertFalse(archiver_tuple.counterz_file)
self.assertFalse(archiver_tuple.stats_file)
archived_files = os.listdir(self.dest_dir)
# Verify that the list of files returned matched what we find in the
# dest_dir.
self.assertCountEqual(archiver_tuple.log_files, archived_files)
self.assertCountEqual(
archived_files,
['compiler_proxy.host.log.INFO.20170426-120000.000000.gz',
'gomacc.host.log.INFO.20170426-120100.000000.tar.gz',
'compiler_proxy-subproc.host.log.INFO.20170426-120000.000000.gz'])
def testArchiveWithStatsAndCounterz(self):
"""Test successful archive of goma logs with stats and counterz."""
self._CreateLogFile(
'compiler_proxy', datetime.datetime(2017, 4, 26, 12, 0, 0))
self._CreateLogFile(
'compiler_proxy-subproc', datetime.datetime(2017, 4, 26, 12, 0, 0))
self._CreateLogFile(
'gomacc', datetime.datetime(2017, 4, 26, 12, 1, 0))
self._CreateLogFile(
'gomacc', datetime.datetime(2017, 4, 26, 12, 2, 0))
self._CreateFile('stats.binaryproto')
self._CreateFile('counterz.binaryproto')
archiver = goma_lib.LogsArchiver(self.goma_log_dir, dest_dir=self.dest_dir,
stats_file='stats.binaryproto',
counterz_file='counterz.binaryproto')
archiver_tuple = archiver.Archive()
self.assertCountEqual(
archiver_tuple.log_files,
['compiler_proxy.host.log.INFO.20170426-120000.000000.gz',
'gomacc.host.log.INFO.20170426-120100.000000.tar.gz',
'compiler_proxy-subproc.host.log.INFO.20170426-120000.000000.gz'])
self.assertEqual(archiver_tuple.stats_file, 'stats.binaryproto')
self.assertEqual(archiver_tuple.counterz_file, 'counterz.binaryproto')
def testArchiveWithStatsAndMissingCounterz(self):
"""Test successful archive of goma logs with stats and counterz."""
self._CreateLogFile(
'compiler_proxy', datetime.datetime(2017, 4, 26, 12, 0, 0))
self._CreateLogFile(
'compiler_proxy-subproc', datetime.datetime(2017, 4, 26, 12, 0, 0))
self._CreateLogFile(
'gomacc', datetime.datetime(2017, 4, 26, 12, 1, 0))
self._CreateLogFile(
'gomacc', datetime.datetime(2017, 4, 26, 12, 2, 0))
self._CreateFile('stats.binaryproto')
archiver = goma_lib.LogsArchiver(self.goma_log_dir, dest_dir=self.dest_dir,
stats_file='stats.binaryproto',
counterz_file='counterz.binaryproto')
# Because counterz.binaryproto does not exist, verify it is not returned
# as one of the files archived.
archiver_tuple = archiver.Archive()
self.assertFalse(archiver_tuple.counterz_file)
self.assertEqual(archiver_tuple.stats_file, 'stats.binaryproto')
self.assertCountEqual(
archiver_tuple.log_files,
['compiler_proxy.host.log.INFO.20170426-120000.000000.gz',
'gomacc.host.log.INFO.20170426-120100.000000.tar.gz',
'compiler_proxy-subproc.host.log.INFO.20170426-120000.000000.gz'])
def testNinjaLogArchive(self):
"""Test successful archive of ninja logs."""
self._CreateLogFile(
'compiler_proxy', datetime.datetime(2017, 8, 21, 12, 0, 0))
self._CreateLogFile(
'compiler_proxy-subproc', datetime.datetime(2017, 8, 21, 12, 0, 0))
ninja_log_path = os.path.join(self.goma_log_dir, 'ninja_log')
osutils.WriteFile(ninja_log_path, 'Ninja Log Content\n')
timestamp = datetime.datetime(2017, 8, 21, 12, 0, 0)
mtime = time.mktime(timestamp.timetuple())
os.utime(ninja_log_path, ((time.time(), mtime)))
osutils.WriteFile(
os.path.join(self.goma_log_dir, 'ninja_command'), 'ninja_command')
osutils.WriteFile(
os.path.join(self.goma_log_dir, 'ninja_cwd'), 'ninja_cwd')
osutils.WriteFile(
os.path.join(self.goma_log_dir, 'ninja_env'),
'key1=value1\0key2=value2\0')
osutils.WriteFile(
os.path.join(self.goma_log_dir, 'ninja_exit'), '0')
archiver = goma_lib.LogsArchiver(self.goma_log_dir, dest_dir=self.dest_dir)
archived_tuple = archiver.Archive()
username = getpass.getuser()
pid = os.getpid()
hostname = cros_build_lib.GetHostName()
ninjalog_filename = 'ninja_log.%s.%s.20170821-120000.%d.gz' % (
username, hostname, pid)
# Verify the archived files in the dest_dir
archived_files = os.listdir(self.dest_dir)
self.assertCountEqual(
archived_files,
[ninjalog_filename,
'compiler_proxy-subproc.host.log.INFO.20170821-120000.000000.gz',
'compiler_proxy.host.log.INFO.20170821-120000.000000.gz'])
# Verify the archived_tuple result.
self.assertFalse(archived_tuple.counterz_file)
self.assertFalse(archived_tuple.stats_file)
self.assertCountEqual(
archived_tuple.log_files,
['compiler_proxy.host.log.INFO.20170821-120000.000000.gz',
'compiler_proxy-subproc.host.log.INFO.20170821-120000.000000.gz',
ninjalog_filename])
# Verify content of ninja_log file.
ninjalog_path = os.path.join(self.dest_dir, ninjalog_filename)
with gzip.open(ninjalog_path, 'rt') as gzip_file:
ninja_log_content = gzip_file.read()
content, eof, metadata_json = ninja_log_content.split('\n', 3)
self.assertEqual('Ninja Log Content', content)
self.assertEqual('# end of ninja log', eof)
metadata = json.loads(metadata_json)
self.assertEqual(
metadata,
{
'platform': 'chromeos',
'cmdline': ['ninja_command'],
'cwd': 'ninja_cwd',
'exit': 0,
'env': {'key1': 'value1', 'key2': 'value2'},
'compiler_proxy_info':
'compiler_proxy.host.log.INFO.20170821-120000.000000'
})