Skip to content
This repository has been archived by the owner on Dec 15, 2018. It is now read-only.

Commit

Permalink
allow additional bazel test flags to be passed in from project config
Browse files Browse the repository at this point in the history
Summary: This uses the config value `bazel.additional-test-flags`.

Test Plan: unit tests

Reviewers: anupc

Reviewed By: anupc

Subscribers: changesbot, kylec, wwu

Differential Revision: https://tails.corp.dropbox.com/D231482
  • Loading branch information
Naphat Sanguansin committed Sep 23, 2016
1 parent 728f99a commit 2058ada
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 3 deletions.
6 changes: 6 additions & 0 deletions changes/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,12 @@ def create_app(_read_config=True, **config):
'--keep_going',
]

app.config['BAZEL_ADDITIONAL_TEST_FLAGS_WHITELIST_REGEX'] = [
r'^--test_env=[A-Za-z0-9=]+',
r'^--test_arg=[A-Za-z0-9=]+',
r'^--define=[A-Za-z0-9=]+',
]

# Jobsteps go from 'pending_allocation' to 'allocated' once an external scheduler claims them, and
# once they begin running they're updated to 'in_progress'. If the scheduler somehow fails or drops
# the task, this value is used to time out the 'allocated' status and revert back to 'pending_allocation'.
Expand Down
13 changes: 10 additions & 3 deletions changes/models/jobplan.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

import logging
import os
import re
import uuid

from collections import defaultdict
from collections import defaultdict, OrderedDict
from copy import deepcopy
from datetime import datetime
from flask import current_app
Expand Down Expand Up @@ -222,8 +223,14 @@ def get_build_step_for_job(cls, job_id):
logging.error('Project config for project %s requests invalid number of executors: constraint 1 <= %d <= %d', job.project.slug, bazel_max_executors, current_app.config['MAX_EXECUTORS'])
return jobplan, None

bazel_test_flags = current_app.config['BAZEL_MANDATORY_TEST_FLAGS']
# TODO(anupc): Allow additional flags to be passed in via project config.
additional_test_flags = project_config['bazel.additional-test-flags']
for f in additional_test_flags:
patterns = current_app.config['BAZEL_ADDITIONAL_TEST_FLAGS_WHITELIST_REGEX']
if not any([re.match(p, f) for p in patterns]):
logging.error('Project config for project %s contains invalid additional-test-flags %s. Allowed patterns are %s.', job.project.slug, f, patterns)
return jobplan, None
bazel_test_flags = current_app.config['BAZEL_MANDATORY_TEST_FLAGS'] + additional_test_flags
bazel_test_flags = list(OrderedDict([(b, None) for b in bazel_test_flags])) # ensure uniqueness, preserve order

vcs = job.project.repository.get_vcs()
implementation = LXCBuildStep(
Expand Down
1 change: 1 addition & 0 deletions changes/models/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def get(cls, id):

_default_config = {
'build.file-blacklist': [],
'bazel.additional-test-flags': [],
'bazel.exclude-tags': ['manual'], # Ignore tests with manual tag
'bazel.cpus': DEFAULT_CPUS,
'bazel.mem': DEFAULT_MEMORY_MB,
Expand Down
73 changes: 73 additions & 0 deletions tests/changes/models/test_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def _create_job_and_jobplan(self):
@mock.patch('changes.models.project.Project.get_config')
def test_autogenerated_commands(self, get_config):
get_config.return_value = {
'bazel.additional-test-flags': [],
'bazel.targets': [
'//aa/bb/cc/...',
'//aa/abc/...',
Expand Down Expand Up @@ -111,6 +112,7 @@ def test_autogenerated_commands(self, get_config):
@mock.patch('changes.models.project.Project.get_config')
def test_autogenerated_commands_with_exclusions(self, get_config):
get_config.return_value = {
'bazel.additional-test-flags': [],
'bazel.targets': [
'//foo/bar/baz/...',
'//bar/bax/...',
Expand Down Expand Up @@ -161,9 +163,78 @@ def test_autogenerated_commands_with_exclusions(self, get_config):
assert implementation.commands[2].type == CommandType.collect_bazel_targets
assert implementation.commands[2].script == collect_tests_expected

@mock.patch('changes.models.project.Project.get_config')
def test_autogenerated_commands_with_additional_test_flags(self, get_config):
get_config.return_value = {
'bazel.additional-test-flags': ['--test_env=testing=123', '--test_env=testing=123'],
'bazel.targets': [
'//foo/bar/baz/...',
'//bar/bax/...',
],
'bazel.exclude-tags': [],
'bazel.cpus': 2,
'bazel.mem': 1234,
'bazel.max-executors': 3,
}

collect_tests_expected = """#!/bin/bash -eu
# Clean up any existing apt sources
sudo rm -rf /etc/apt/sources.list.d >/dev/null 2>&1
# Overwrite apt sources
(echo "deb http://example.com/debian distribution component1" | sudo tee /etc/apt/sources.list) >/dev/null 2>&1
# apt-get update, and try again if it fails first time
(sudo apt-get -y update || sudo apt-get -y update) >/dev/null 2>&1
sudo apt-get install -y --force-yes bazel python >/dev/null 2>&1
"/var/changes/input/collect-targets" --output-user-root="/bazel/root/path" --target-patterns=//foo/bar/baz/... --target-patterns=//bar/bax/... --test-flags=--spawn_strategy=sandboxed --test-flags=--genrule_strategy=sandboxed --test-flags=--keep_going --test-flags=--test_env=testing=123 --jobs="4" 2> /dev/null
""".strip()

mock_vcs = mock.Mock(spec=Vcs)
mock_vcs.get_buildstep_checkout_revision.return_value = 'git checkout master'
mock_vcs.get_buildstep_checkout_parent_revision.return_value = 'git checkout master^'
mock_vcs.get_buildstep_changed_files.return_value = 'git diff --name-only master^..master'
job = self._create_job_and_jobplan()
with mock.patch.object(job.project.repository, "get_vcs") as mock_get_vcs:
mock_get_vcs.return_value = mock_vcs
_, implementation = JobPlan.get_build_step_for_job(job.id)

assert implementation.max_executors == 3

assert implementation.artifacts == []
assert implementation.artifact_suffix == '.bazel'

assert implementation.resources['cpus'] == 2
assert implementation.resources['mem'] == 1234

assert len(implementation.commands) == 3

assert implementation.commands[0].type == CommandType.setup
assert implementation.commands[1].type == CommandType.setup
assert implementation.commands[2].type == CommandType.collect_bazel_targets
assert implementation.commands[2].script == collect_tests_expected

@mock.patch('changes.models.project.Project.get_config')
def test_autogenerated_commands_with_additional_test_flags_invalid(self, get_config):
get_config.return_value = {
'bazel.additional-test-flags': ['--keep_going'], # not in whitelist
'bazel.targets': [
'//foo/bar/baz/...',
'//bar/bax/...',
],
'bazel.exclude-tags': [],
'bazel.cpus': 2,
'bazel.mem': 1234,
'bazel.max-executors': 3,
}

_, implementation = JobPlan.get_build_step_for_job(self._create_job_and_jobplan().id)
assert implementation is None

@mock.patch('changes.models.project.Project.get_config')
def test_invalid_cpus(self, get_config):
get_config.return_value = {
'bazel.additional-test-flags': [],
'bazel.targets': [
'//aa/bb/cc/...',
'//aa/abc/...',
Expand Down Expand Up @@ -195,6 +266,7 @@ def test_invalid_cpus(self, get_config):
@mock.patch('changes.models.project.Project.get_config')
def test_invalid_mems(self, get_config):
get_config.return_value = {
'bazel.additional-test-flags': [],
'bazel.targets': [
'//aa/bb/cc/...',
'//aa/abc/...',
Expand Down Expand Up @@ -231,6 +303,7 @@ def test_invalid_mems(self, get_config):
@mock.patch('changes.models.project.Project.get_config')
def test_invalid_num_executors(self, get_config):
get_config.return_value = {
'bazel.additional-test-flags': [],
'bazel.targets': [
'//aa/bb/cc/...',
'//aa/abc/...',
Expand Down

0 comments on commit 2058ada

Please sign in to comment.