Example #1
0
def is_repo_allowed(repo):
    """
    Check if repo is allowed.

    A repository name is checked against a list of denied and allowed repos.
    The 'denied_repo' check takes precendence over 'allowed_repo' check.
    The list of denied/allowed repos is defined with settings 'denied_repo'
    and 'allowed_repo'.
    If the settings are not defined,
    the repo is not checked against the denied/allowed lists.
    Both 'denied_repo' and 'allowed_repo' can have multiple values,
    if any of them matches a substring of the repo, the repo is denied/allowed.

    Parameters:
    -repo : repository name
    """
    if repo is None:
        logger.warning("Repo is not defined")
        return False

    denied_message = "Project '%s' is not allowed."
    denied_repo = Settings().get_setting("denied_repo")
    allowed_repo = Settings().get_setting("allowed_repo")

    if denied_repo is not None and \
            any(x in repo for x in denied_repo) or \
            allowed_repo is not None and \
            not any(x in repo for x in allowed_repo):
        logger.warning(denied_message, repo)
        return False

    return True
Example #2
0
def is_worker_enabled():
    """Check if a task queue is configured."""
    task_queue = Settings().get_setting("task_queue")
    # use double not to force boolean evaluation
    return check_dict(task_queue, key_list=["broker_url", "backend"]) and \
        not not task_queue["broker_url"] and \
        not not task_queue["backend"]
Example #3
0
def create_worker_app():
    """Create worker app."""
    # load settings
    settings = Settings()
    settings.load_settings(config_file=constants.CONFIG_FILE)
    settings.set_client(constants.CLIENT_NAME, constants.CLIENT_VERSION)

    if is_worker_enabled():
        task_queue = settings.get_setting("task_queue")
        worker_app = Celery(
            'tasks',
            backend=task_queue["backend"],
            broker=task_queue["broker_url"]
        )

        # configure worker
        worker_app.conf.update(
            CELERY_TASK_SERIALIZER='json',
            CELERY_ACCEPT_CONTENT=['json']
        )

        if worker_app is None:
            logger.error("Error connection to task queue")
        else:
            logger.info(
                "Connected to task queue : %s", task_queue["broker_url"]
            )
    else:
        worker_app = Celery()
        logger.warning(
            "Task queue is not defined,"
            " check README.md to configure task queue"
        )

    return worker_app
Example #4
0
def send_build_data(buildjob, detail=None):
    """
    Send build data generated by client to keen.io.

    Parameters:
    - buildjob : BuildJob instance
    - detail : Data storage detail level :
               'minimal', 'basic', 'full', 'extended'
    """
    if not isinstance(buildjob, BuildJob):
        raise TypeError("param buildjob should be a BuildJob instance")

    data_detail = Settings().get_value_or_setting("data_detail", detail)

    if is_writable():
        logger.info(
            "Sending client build job data to Keen.io (data detail: %s)",
            data_detail
        )
        # store build job data
        add_event("build_jobs", {"job": buildjob.to_dict()})

        # store build stages
        if data_detail in ("full", "extended"):
            add_events("build_stages", buildjob.stages_to_list())
Example #5
0
def add_project_info_dict(payload):
    """
    Add project info to a dictonary.

    Param payload: dictonary payload
    """
    # check if payload is a dictionary, throws an exception if it isn't
    check_dict(payload, "payload")

    payload_as_dict = copy.deepcopy(payload)

    payload_as_dict[KEEN_PROJECT_INFO_NAME] = Settings().get_project_info()

    if "job" in payload:
        # override project_name, set to build_job repo
        if "repo" in payload["job"]:
            payload_as_dict[KEEN_PROJECT_INFO_NAME]["project_name"] = \
                payload["job"]["repo"]

        # override timestamp, set to finished_at timestamp
        if "finished_at" in payload["job"]:
            payload_as_dict["keen"] = {
                "timestamp": payload["job"]["finished_at"]["isotimestamp"]
            }

    return payload_as_dict
Example #6
0
    def __init__(self):
        """Constructor."""
        self.settings = Settings()
        self.logger = logger

        self.file_stats = os.path.join(DASHBOARD_DIR, "stats.html")
        self.file_stats_service = os.path.join(DASHBOARD_DIR,
                                               "stats_service.html")
Example #7
0
    def test_generate_config_file_ioerror(self):
        """
        Test dashboard.generate_config_file()
        if creation fails because of unexisting path.
        """
        # set config file path
        Settings().add_setting("dashboard_configfile",
                               "build/unexisting_path/config_test.js")

        # generation should return false
        self.assertFalse(dashboard.generate_config_file("test/repo4"))
Example #8
0
 def load_properties_from_settings(self):
     """Load build properties from settings."""
     self.load_property_from_settings("build")
     self.load_property_from_settings("job")
     self.load_property_from_settings("branch")
     self.load_property_from_settings("ci_platform")
     self.load_property_from_settings("build_trigger")
     self.load_property_from_settings("pull_request")
     self.load_property_from_settings("result")
     self.load_property_from_settings("build_matrix")
     self.add_property("repo", Settings().get_project_name())
Example #9
0
def process_notification_payload(payload):
    """
    Extract repo slug and build number from Travis notification payload.

    Returns a dictionary with "repo" and "build" information,
    or an empty dictionary if the payload could not be processed.

    Deprecated behaviour : Currently the repo and build information are
    also stored in the "settings" object,
    but this will be removed in the near future.

    Parameters:
    - payload : Travis CI notification payload
    """
    settings = Settings()
    parameters = {}

    if payload is None:
        logger.warning("Travis notification payload is not set")
        return parameters

    if not is_string(payload):
        logger.warning(
            "Travis notification payload is incorrect :"
            " string expected, got %s", type(payload))
        return parameters

    json_payload = json.loads(payload)
    logger.info("Travis Payload : %r.", json_payload)

    # get repo name from payload
    if ("repository" in json_payload
            and "owner_name" in json_payload["repository"]
            and "name" in json_payload["repository"]):

        repo = get_repo_slug(json_payload["repository"]["owner_name"],
                             json_payload["repository"]["name"])

        logger.info("Build repo : %s", repo)
        settings.set_project_name(repo)
        parameters["repo"] = repo

    # get build number from payload
    if "number" in json_payload:
        logger.info("Build number : %s", str(json_payload["number"]))
        settings.add_setting('build', json_payload['number'])
        parameters["build"] = json_payload['number']

    return parameters
Example #10
0
    def multi_build(self, repo, first_build, last_build):
        """
        Schedule processing multiple consecutive builds.

        All builds from first_build until last_build
        will be retrieved and processed.

        The total number of builds to be scheduled is limited by the
        `multi_import.max_builds` config parameter.

        Every next scheduled build will be delayed by the
        `multi_import.delay` config parameter.

        Parameters:
        - repo : repo name (fe. buildtimetrend/service)
        - first_build : first build number to process (int)
        - last_build : last build number to process (int)
        """
        first_build = int(first_build)
        last_build = int(last_build)
        message = ""
        multi_import = Settings().get_setting("multi_import")
        max_multi_builds = int(multi_import["max_builds"])

        if last_build < first_build:
            tmp_msg = "Warning : last_build should be equal" \
                " or larger than first_build"
            self.logger.warning(tmp_msg)
            message += tmp_msg + "\n"
            last_build = first_build

        if (last_build - first_build) > max_multi_builds:
            tmp_msg = "Warning : number of multiple builds is limited to {:d}"
            self.logger.warning(tmp_msg.format(max_multi_builds))
            message += tmp_msg.format(max_multi_builds) + "\n"
            last_build = first_build + max_multi_builds

        message += "Request to process build(s) #{first_build:d} to" \
            " #{last_build:d} of repo {repo}:\n".format(**locals())

        build = first_build
        delay = 0

        while build <= last_build:
            message += self.schedule_task(repo, build, delay) + "\n"
            delay += multi_import["delay"]
            build += 1

        return message
Example #11
0
    def load_property_from_settings(self, property_name, setting_name=None):
        """
        Load the value of a setting and set it as a build property.

        Parameters
        - property_name : name of the build property
        - setting_name : name of the setting (takes property_name if not set)
        """
        if setting_name is None:
            setting_name = property_name

        value = Settings().get_setting(setting_name)

        if value is not None:
            self.add_property(property_name, value)
    def setUpClass(cls):
        """Set up test fixture."""
        # show full diff in case of assert mismatch
        cls.maxDiff = None

        cls.settings = Settings()

        cls.project_name = buildtimetrend.NAME

        cls.project_info = {
            "lib_version": buildtimetrend.VERSION,
            "schema_version": buildtimetrend.SCHEMA_VERSION,
            "client": 'None',
            "client_version": 'None',
            "project_name": cls.project_name
        }
Example #13
0
    def setUpClass(cls):
        """Set up test fixture."""
        cls.settings = Settings()
        cls.project_info = cls.settings.get_project_info()
        cls.maxDiff = None
        cls.test_api_error = {"message": "test message", "error_code": "123"}

        # copy Keen.io environment variables
        if "KEEN_PROJECT_ID" in os.environ:
            cls.copy_keen_project_id = os.environ["KEEN_PROJECT_ID"]
        if "KEEN_WRITE_KEY" in os.environ:
            cls.copy_keen_write_key = os.environ["KEEN_WRITE_KEY"]
        if "KEEN_READ_KEY" in os.environ:
            cls.copy_keen_read_key = os.environ["KEEN_READ_KEY"]
        if "KEEN_MASTER_KEY" in os.environ:
            cls.copy_keen_master_key = os.environ["KEEN_MASTER_KEY"]
Example #14
0
def load_all(settings=None):
    """
    Load all Travis CI environment variables.

    Load Travis CI environment variables and assign their values to
    the corresponding setting value :
    - general
    - build matrix
    - pull request
    """
    if not isinstance(settings, Settings):
        settings = Settings()

    load_general_env_vars(settings)
    load_build_matrix_env_vars(settings)
    load_travis_pr_env_vars(settings)
Example #15
0
    def __init__(self):
        """
        Initialise class.

        Load config file and set loglevel, define error page handler
        """
        self.settings = Settings()
        self.settings.load_settings(config_file=constants.CONFIG_FILE)
        self.settings.set_client(constants.CLIENT_NAME,
                                 constants.CLIENT_VERSION)

        self.file_index = os.path.join(STATIC_DIR, "index.html")

        cherrypy.config.update({'error_page.404': self.error_page_404})

        # get logger
        self.logger = logger
Example #16
0
def check_authorization(repo, auth_header):
    """
    Check if Travis CI notification has a correct Authorization header.

    This check is enabled if travis_account_token is defined in settings.

    More information on the Authorization header :
    http://docs.travis-ci.com/user/notifications/#Authorization-for-Webhooks

    Returns true if Authorization header is valid, but also if
    travis_account_token is not defined.

    Parameters:
    - repo : git repo name
    - auth_header : Travis CI notification Authorization header
    """
    # get Travis account token from Settings
    token = Settings().get_setting("travis_account_token")

    # return True if token is not set
    if token is None:
        logger.info("Setting travis_account_token is not defined,"
                    " Travis CI notification Authorization header"
                    " is not checked.")
        return True

    # check if parameters are strings
    if is_string(repo) and is_string(auth_header) and is_string(token):
        # generate hash (encode string to bytes first)
        auth_hash = sha256((repo + token).encode('utf-8')).hexdigest()

        # compare hash with Authorization header
        if auth_hash == auth_header:
            logger.info("Travis CI notification Authorization header"
                        " is correct.")
            return True
        else:
            logger.error("Travis CI notification Authorization header"
                         " is incorrect.")
            return False
    else:
        logger.debug("repo, auth_header and travis_auth_token"
                     " should be strings.")
        return False
    def test_load_properties(self):
        """Test loading properties"""
        self.build.load_properties_from_settings()

        self.assertDictEqual({
            'duration': 0,
            "repo": buildtimetrend.NAME
        }, self.build.get_properties())

        settings = Settings()
        settings.add_setting("ci_platform", "travis")
        settings.add_setting("build", "123")
        settings.add_setting("job", "123.1")
        settings.add_setting("branch", "branch1")
        settings.add_setting("result", "passed")
        settings.add_setting("build_trigger", "push")
        settings.add_setting("pull_request", {
            "is_pull_request": False,
            "title": None,
            "number": None
        })
        settings.set_project_name("test/project")

        self.build.load_properties_from_settings()
        self.assertDictEqual(
            {
                'duration': 0,
                'ci_platform': "travis",
                'build': "123",
                'job': "123.1",
                'branch': "branch1",
                'result': "passed",
                'build_trigger': "push",
                'pull_request': {
                    "is_pull_request": False,
                    "title": None,
                    "number": None
                },
                'repo': "test/project"
            }, self.build.get_properties())
Example #18
0
    def test_generate_config_file(self, get_cfg_str_func):
        """Test dashboard.generate_config_file()"""
        # set config file path
        Settings().add_setting("dashboard_configfile",
                               constants.DASHBOARD_TEST_CONFIG_FILE)

        # check if configfile exists
        self.assertFalse(check_file(constants.DASHBOARD_TEST_CONFIG_FILE))

        # generate config file with empty repo name
        self.assertRaises(TypeError, dashboard.generate_config_file)

        # generate config file with empty repo name
        self.assertTrue(dashboard.generate_config_file(None))

        self.assertTrue(check_file(constants.DASHBOARD_TEST_CONFIG_FILE))

        # check if mock was called with correct parameters
        args, kwargs = get_cfg_str_func.call_args
        self.assertEqual(args, (None, ))
        self.assertDictEqual(kwargs, {})

        # generate config file
        self.assertTrue(dashboard.generate_config_file("test/repo3"))

        self.assertTrue(check_file(constants.DASHBOARD_TEST_CONFIG_FILE))

        # check if mock was called with correct parameters
        args, kwargs = get_cfg_str_func.call_args
        self.assertEqual(args, ("test/repo3", ))
        self.assertDictEqual(kwargs, {})

        # test generated config file contents
        with open(constants.DASHBOARD_TEST_CONFIG_FILE, 'r') as config_file:
            self.assertEqual("var config = {'projectName': 'test/repo3'};\n",
                             next(config_file))
            self.assertEqual("var keenConfig = {'projectId': '1234abcd'};",
                             next(config_file))
Example #19
0
    def test_generate_config_file_fails(self):
        """Test dashboard.generate_config_file() if creation fails"""
        # set config file path
        Settings().add_setting("dashboard_configfile",
                               constants.DASHBOARD_TEST_CONFIG_FILE)

        # check if configfile exists
        self.assertFalse(check_file(constants.DASHBOARD_TEST_CONFIG_FILE))

        # init mock
        patcher = mock.patch('buildtimetrend.tools.check_file',
                             return_value=False)
        check_file_func = patcher.start()

        # generation should return false
        self.assertFalse(dashboard.generate_config_file("test/repo4"))

        # check if mock was called with correct parameters
        args, kwargs = check_file_func.call_args
        self.assertEqual(args, (constants.DASHBOARD_TEST_CONFIG_FILE, ))
        self.assertDictEqual(kwargs, {})

        patcher.stop()
Example #20
0
def get_repo_data_detail(repo):
    """
    Get level of data detail storage of a repo.

    A repository name is checked against a list of repository names.
    If a match is found, the corresponding data detail level is used.
    Else, the default global setting is returned.

    Parameters:
    -repo : repository name
    """
    settings = Settings()

    if repo is None:
        logger.warning("Repo is not defined")
    else:
        repo_settings = settings.get_setting("repo_data_detail")
        for repo_substring, setting in repo_settings.items():
            if repo_substring in repo:
                return setting

    # return default global data_detail setting
    return settings.get_setting("data_detail")
Example #21
0
 def setUp():
     """Initialise test environment before each test."""
     # reinit settings singleton
     Settings().__init__()
Example #22
0
    def test_load_build_matrix_env_vars_parameters(self):
        """Test load_travis_env_vars, optional parameters"""
        # setup Travis env vars
        if "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true":
            reset_travis_vars = False
            copy_os = os.environ["TRAVIS_OS_NAME"]
        else:
            reset_travis_vars = True
            os.environ["TRAVIS"] = "true"

        # temporarily remove OS VERSION
        if "TRAVIS_OS_NAME" in os.environ:
            reset_os = True
            copy_os = os.environ["TRAVIS_OS_NAME"]
            del os.environ["TRAVIS_OS_NAME"]
        else:
            reset_os = False

        # temporarily remove PYTHON VERSION
        if "TRAVIS_PYTHON_VERSION" in os.environ:
            reset_python_version = True
            copy_python = os.environ["TRAVIS_PYTHON_VERSION"]
            del os.environ["TRAVIS_PYTHON_VERSION"]
        else:
            reset_python_version = False

        # test optional build matrix parameters
        test_parameters = [{
            'env_var': 'TRAVIS_XCODE_SDK',
            'parameter': 'xcode_sdk',
            'test_value': "test_x_sdk"
        }, {
            'env_var': 'TRAVIS_XCODE_SCHEME',
            'parameter': 'xcode_scheme',
            'test_value': "test_x_scheme"
        }, {
            'env_var': 'TRAVIS_XCODE_PROJECT',
            'parameter': 'xcode_project',
            'test_value': "test_x_project"
        }, {
            'env_var': 'TRAVIS_XCODE_WORKSPACE',
            'parameter': 'xcode_workspace',
            'test_value': "test_x_workspace"
        }, {
            'env_var': 'CC',
            'parameter': 'compiler',
            'test_value': "test_gcc"
        }, {
            'env_var': 'ENV',
            'parameter': 'parameters',
            'test_value': "test_env"
        }]

        # test parameters
        for parameter in test_parameters:
            Settings().__init__()
            settings = Settings()

            if parameter['env_var'] in os.environ:
                reset_travis_parameter = False
                expected_param_value = os.environ[parameter['env_var']]
            else:
                reset_travis_parameter = True
                expected_param_value = os.environ[parameter['env_var']] = \
                    parameter['test_value']

            env_var.load_build_matrix_env_vars(settings)

            self.assertDictEqual(
                {
                    parameter["parameter"]: expected_param_value,
                    'summary': expected_param_value
                }, settings.get_setting("build_matrix"))

            # reset Travis parameters
            if reset_travis_parameter:
                del os.environ[parameter['env_var']]

        # reset test Travis vars
        if reset_travis_vars:
            del os.environ["TRAVIS"]

        # reset removed os name
        if reset_os:
            os.environ["TRAVIS_OS_NAME"] = copy_os

        # reset removed python version
        if reset_python_version:
            os.environ["TRAVIS_PYTHON_VERSION"] = copy_python
Example #23
0
 def setUpClass(cls):
     """Set up test fixture."""
     cls.settings = Settings()
 def setUp(self):
     """Initialise test environment before each test."""
     self.build = BuildJob()
     # reinitialise settings
     Settings().__init__()
Example #25
0
 def setUpClass(cls):
     """Set up test fixture."""
     cls.project_info = Settings().get_project_info()
     cls.maxDiff = None
Example #26
0
    def __init__(self):
        """Initialise class."""
        self.settings = Settings()

        # get logger
        self.logger = logger
Example #27
0
    def test_load_travis_env_vars(self):
        """Test load_travis_env_vars"""
        settings = Settings()

        self.assertEqual(None, settings.get_setting("ci_platform"))
        self.assertEqual(None, settings.get_setting("build"))
        self.assertEqual(None, settings.get_setting("job"))
        self.assertEqual(None, settings.get_setting("branch"))
        self.assertEqual(None, settings.get_setting("result"))
        self.assertEqual(None, settings.get_setting("build_trigger"))
        self.assertEqual(None, settings.get_setting("pull_request"))
        self.assertEqual(buildtimetrend.NAME, settings.get_project_name())

        # setup Travis env vars
        if "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true":
            reset_travis_vars = False
            expected_build = os.environ["TRAVIS_BUILD_NUMBER"]
            expected_job = os.environ["TRAVIS_JOB_NUMBER"]
            expected_branch = os.environ["TRAVIS_BRANCH"]
            expected_project_name = os.environ["TRAVIS_REPO_SLUG"]
            copy_pull_request = os.environ["TRAVIS_PULL_REQUEST"]
        else:
            reset_travis_vars = True
            os.environ["TRAVIS"] = "true"
            expected_build = os.environ["TRAVIS_BUILD_NUMBER"] = "123"
            expected_job = os.environ["TRAVIS_JOB_NUMBER"] = "123.1"
            expected_branch = os.environ["TRAVIS_BRANCH"] = "branch1"
            expected_project_name = \
                os.environ["TRAVIS_REPO_SLUG"] = "test/project"

        # setup Travis test result
        if "TRAVIS_TEST_RESULT" in os.environ:
            reset_travis_result = False
            copy_result = os.environ["TRAVIS_TEST_RESULT"]
        else:
            reset_travis_result = True

        os.environ["TRAVIS_TEST_RESULT"] = "0"
        os.environ["TRAVIS_PULL_REQUEST"] = "false"

        env_var.load_all(settings)

        self.assertEqual("travis", settings.get_setting("ci_platform"))
        self.assertEqual(expected_build, settings.get_setting("build"))
        self.assertEqual(expected_job, settings.get_setting("job"))
        self.assertEqual(expected_branch, settings.get_setting("branch"))
        self.assertEqual(expected_project_name, settings.get_project_name())
        self.assertEqual("passed", settings.get_setting("result"))
        self.assertEqual("push", settings.get_setting("build_trigger"))
        self.assertDictEqual(
            {
                'is_pull_request': False,
                'title': None,
                'number': None
            }, settings.get_setting("pull_request"))

        os.environ["TRAVIS_TEST_RESULT"] = "1"
        # build is a pull request
        expected_pull_request = os.environ["TRAVIS_PULL_REQUEST"] = "123"
        env_var.load_all()
        self.assertEqual("failed", settings.get_setting("result"))
        self.assertEqual("pull_request", settings.get_setting("build_trigger"))
        self.assertDictEqual(
            {
                'is_pull_request': True,
                'title': "unknown",
                'number': expected_pull_request
            }, settings.get_setting("pull_request"))

        # build is not a pull request
        os.environ["TRAVIS_PULL_REQUEST"] = "false"
        env_var.load_all(settings)
        self.assertEqual("push", settings.get_setting("build_trigger"))
        self.assertDictEqual(
            {
                'is_pull_request': False,
                'title': None,
                'number': None
            }, settings.get_setting("pull_request"))

        # reset test Travis vars
        if reset_travis_vars:
            del os.environ["TRAVIS"]
            del os.environ["TRAVIS_BUILD_NUMBER"]
            del os.environ["TRAVIS_JOB_NUMBER"]
            del os.environ["TRAVIS_BRANCH"]
            del os.environ["TRAVIS_REPO_SLUG"]
            del os.environ["TRAVIS_PULL_REQUEST"]
        else:
            os.environ["TRAVIS_PULL_REQUEST"] = copy_pull_request

        # reset Travis test result
        if reset_travis_result:
            del os.environ["TRAVIS_TEST_RESULT"]
        else:
            os.environ["TRAVIS_TEST_RESULT"] = copy_result
Example #28
0
    def test_load_build_matrix_env_vars(self):
        """Test load_build_matrix_env_vars"""
        settings = Settings()

        self.assertEqual(None, settings.get_setting("build_matrix"))

        # setup Travis env vars
        if "TRAVIS" in os.environ and os.environ["TRAVIS"] == "true":
            reset_travis_vars = False
            expected_os = os.environ["TRAVIS_OS_NAME"]
            copy_python = os.environ["TRAVIS_PYTHON_VERSION"]
            del os.environ["TRAVIS_PYTHON_VERSION"]
        else:
            reset_travis_vars = True
            os.environ["TRAVIS"] = "true"
            expected_os = os.environ["TRAVIS_OS_NAME"] = "test_os"

        # temporarily remove PYTHON VERSION
        if "TRAVIS_PYTHON_VERSION" in os.environ:
            reset_python_version = True
            copy_python = os.environ["TRAVIS_PYTHON_VERSION"]
            del os.environ["TRAVIS_PYTHON_VERSION"]
        else:
            reset_python_version = False

        # test language and language versions
        test_languages = [{
            'env_var': 'TRAVIS_DART_VERSION',
            'language': 'dart',
            'test_value': "1.1"
        }, {
            'env_var': 'TRAVIS_GO_VERSION',
            'language': 'go',
            'test_value': "1.2"
        }, {
            'env_var': 'TRAVIS_HAXE_VERSION',
            'language': 'haxe',
            'test_value': "1.3"
        }, {
            'env_var': 'TRAVIS_JDK_VERSION',
            'language': 'java',
            'test_value': "1.4"
        }, {
            'env_var': 'TRAVIS_JULIA_VERSION',
            'language': 'julia',
            'test_value': "1.5"
        }, {
            'env_var': 'TRAVIS_NODE_VERSION',
            'language': 'javascript',
            'test_value': "1.6"
        }, {
            'env_var': 'TRAVIS_OTP_RELEASE',
            'language': 'erlang',
            'test_value': "1.7"
        }, {
            'env_var': 'TRAVIS_PERL_VERSION',
            'language': 'perl',
            'test_value': "1.8"
        }, {
            'env_var': 'TRAVIS_PHP_VERSION',
            'language': 'php',
            'test_value': "1.9"
        }, {
            'env_var': 'TRAVIS_PYTHON_VERSION',
            'language': 'python',
            'test_value': "1.10"
        }, {
            'env_var': 'TRAVIS_R_VERSION',
            'language': 'r',
            'test_value': "1.11"
        }, {
            'env_var': 'TRAVIS_RUBY_VERSION',
            'language': 'ruby',
            'test_value': "1.12"
        }, {
            'env_var': 'TRAVIS_RUST_VERSION',
            'language': 'rust',
            'test_value': "1.13"
        }, {
            'env_var': 'TRAVIS_SCALA_VERSION',
            'language': 'scala',
            'test_value': "1.14"
        }]

        # test languages
        for language in test_languages:
            if language['env_var'] in os.environ:
                reset_travis_lang_version = False
                expected_lang_version = os.environ[language['env_var']]
            else:
                reset_travis_lang_version = True
                expected_lang_version = \
                    os.environ[language['env_var']] = language['test_value']

            env_var.load_build_matrix_env_vars(settings)

            self.assertDictEqual(
                {
                    'os':
                    expected_os,
                    'language':
                    language['language'],
                    'language_version':
                    expected_lang_version,
                    'summary':
                    "{0!s} {1!s} {2!s}".format(language['language'],
                                               expected_lang_version,
                                               expected_os)
                }, settings.get_setting("build_matrix"))

            # reset Travis test result
            if reset_travis_lang_version:
                del os.environ[language['env_var']]

        # reset test Travis vars
        if reset_travis_vars:
            del os.environ["TRAVIS"]
            del os.environ["TRAVIS_OS_NAME"]

        # reset removed python version
        if reset_python_version:
            os.environ["TRAVIS_PYTHON_VERSION"] = copy_python