Exemplo n.º 1
0
    def run(self):
        """
        The main application execution method
        """
        logger.info("Running Containers Testing Framework cli")

        try:
            check_call("git submodule update --init", shell=True)
        except:
            pass

        # TODO: Remove this or rework, once more types are implemented
        if self._cli_conf.get(
                CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_EXEC_TYPE) != 'ansible':
            raise CTFCliError("Wrong ExecType configured. Currently only 'ansible' is supported!")

        self._working_dir = BehaveWorkingDirectory(self._working_dir_path, self._cli_conf)

        # Setup Behave structure inside working directory
        # Clone common Features and steps into the working dir
        # Add the project specific Features and steps
        # Prepare the steps.py in the Steps dir that combines all the other
        self._working_dir.setup()

        # Execute Behave
        self._behave_runner = BehaveRunner(self._working_dir, self._cli_conf)
        sys.exit(self._behave_runner.run())
Exemplo n.º 2
0
class Application(object):
    def __init__(self, cli_args=None):
        """
        The Application implementation.
        """
        self._execution_dir_path = os.getcwd()
        self._working_dir_path = os.path.join(
            self._execution_dir_path, '{0}-behave-working-dir'.format(
                os.path.basename(self._execution_dir_path)))
        self._working_dir = None
        self._behave_runner = None

        if not cli_args.cli_config_path:
            cli_args.cli_config_path = CTFCliConfig.find_cli_config(
                self._execution_dir_path)
        self._cli_conf = CTFCliConfig(cli_args)

        # If no Dockerfile passed on the cli, try to use one from the execution directory
        if not self._cli_conf.get(CTFCliConfig.GLOBAL_SECTION_NAME,
                                  CTFCliConfig.CONFIG_DOCKERFILE):
            local_file = os.path.join(self._execution_dir_path, 'Dockerfile')
            if not os.path.isfile(local_file):
                raise CTFCliError(
                    "No Dockerfile passed on the cli and no Dockerfile "
                    "is present in the current directory!")
            logger.debug("Using Dockerfile from the current directory.")
            self._cli_conf.set(CTFCliConfig.GLOBAL_SECTION_NAME,
                               CTFCliConfig.CONFIG_DOCKERFILE, local_file)

        # TODO: Remove this or rework, once more types are implemented
        if self._cli_conf.get(CTFCliConfig.GLOBAL_SECTION_NAME,
                              CTFCliConfig.CONFIG_EXEC_TYPE) != 'ansible':
            raise CTFCliError(
                "Wrong ExecType configured. Currently only 'ansible' is supported!"
            )

    def run(self):
        """
        The main application execution method
        """
        logger.info("Running Containers Testing Framework cli")

        self._working_dir = BehaveWorkingDirectory(self._working_dir_path,
                                                   self._cli_conf)

        # Setup Behave structure inside working directory
        # Clone common Features and steps into the working dir
        # Add the project specific Features and steps
        # Prepare the steps.py in the Steps dir that combines all the other
        self._working_dir.setup()

        # Execute Behave
        self._behave_runner = BehaveRunner(self._working_dir, self._cli_conf)
        return self._behave_runner.run()
Exemplo n.º 3
0
    def run(self):
        """
        The main application execution method
        """
        logger.info("Running Containers Testing Framework cli")

        # If no Dockerfile passed on the cli, try to use one from the execution directory
        if not self._cli_conf.get(CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_DOCKERFILE):
            local_file = os.path.join(self._execution_dir_path, 'Dockerfile')
            if not os.path.isfile(local_file):
                raise CTFCliError("No Dockerfile passed on the cli and no Dockerfile "
                                  "is present in the current directory!")
            logger.debug("Using Dockerfile from the current directory.")
            self._cli_conf.set(CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_DOCKERFILE, local_file)

        # TODO: Remove this or rework, once more types are implemented
        if self._cli_conf.get(CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_EXEC_TYPE) != 'ansible':
            raise CTFCliError("Wrong ExecType configured. Currently only 'ansible' is supported!")

        self._working_dir = BehaveWorkingDirectory(self._working_dir_path, self._cli_conf)

        # Setup Behave structure inside working directory
        # Clone common Features and steps into the working dir
        # Add the project specific Features and steps
        # Prepare the steps.py in the Steps dir that combines all the other
        self._working_dir.setup()

        # Execute Behave
        self._behave_runner = BehaveRunner(self._working_dir, self._cli_conf)
        return self._behave_runner.run()
Exemplo n.º 4
0
 def test_find_tests_config_none(self):
     """
     Test that if no configuration file is present, None is returned
     :return:
     """
     assert BehaveWorkingDirectory.find_tests_config(
         self.WORKING_DIR) is None
Exemplo n.º 5
0
    def run(self):
        """
        The main application execution method
        """
        logger.info("Running Containers Testing Framework cli")

        self._working_dir = BehaveWorkingDirectory(self._working_dir_path,
                                                   self._cli_conf)

        # Setup Behave structure inside working directory
        # Clone common Features and steps into the working dir
        # Add the project specific Features and steps
        # Prepare the steps.py in the Steps dir that combines all the other
        self._working_dir.setup()

        # Execute Behave
        self._behave_runner = BehaveRunner(self._working_dir, self._cli_conf)
        return self._behave_runner.run()
Exemplo n.º 6
0
    def test_check_and_add_init_py(self):
        """
        Test that __init__.py is created in all directories in which it was missing
        :return:
        """
        dirs = [
            'myproj/common',
            'myproj/specific',
            'yourproj',
            'theirproj/common',
            'theirproj/common/steps',
            'theirproj/specific',
            'theirproj/.git',
            'theirproj/.git/dir',
        ]

        files = [
            # 'myproj/__init__.py'
            'myproj/common/__init__.py',
            # 'myproj/specific/__init__.py',
            'yourproj/__init__.py',
            'theirproj/__init__.py',
            # 'theirproj/common/__init__.py',
            'theirproj/common/steps/__init__.py',
            # 'theirproj/specific/__init__.py',
        ]

        f = [
            'myproj/__init__.py',
            'myproj/specific/__init__.py',
            'theirproj/common/__init__.py',
            'theirproj/specific/__init__.py',
        ]

        files_to_check = [os.path.join(self.WORKING_DIR, x) for x in f]

        # create dirs
        for d in dirs:
            os.makedirs(d)

        # create files
        for f in files:
            with open(f, 'w') as fw:
                fw.write(f)

        output = BehaveWorkingDirectory.check_and_add_init_py(os.getcwd())
        print(output)
        assert len(
            set(files_to_check).intersection(output)) == len(files_to_check)

        for f in files_to_check:
            assert os.path.exists(f)
Exemplo n.º 7
0
    def test_check_and_add_init_py(self):
        """
        Test that __init__.py is created in all directories in which it was missing
        :return:
        """
        dirs = [
            'myproj/common',
            'myproj/specific',
            'yourproj',
            'theirproj/common',
            'theirproj/common/steps',
            'theirproj/specific',
            'theirproj/.git',
            'theirproj/.git/dir',
        ]

        files = [
            # 'myproj/__init__.py'
            'myproj/common/__init__.py',
            # 'myproj/specific/__init__.py',
            'yourproj/__init__.py',
            'theirproj/__init__.py',
            # 'theirproj/common/__init__.py',
            'theirproj/common/steps/__init__.py',
            # 'theirproj/specific/__init__.py',
        ]

        f = [
            'myproj/__init__.py',
            'myproj/specific/__init__.py',
            'theirproj/common/__init__.py',
            'theirproj/specific/__init__.py',
        ]

        files_to_check = [os.path.join(self.WORKING_DIR, x) for x in f]

        # create dirs
        for d in dirs:
            os.makedirs(d)

        # create files
        for f in files:
            with open(f, 'w') as fw:
                fw.write(f)

        output = BehaveWorkingDirectory.check_and_add_init_py(os.getcwd())
        print(output)
        assert len(set(files_to_check).intersection(output)) == len(files_to_check)

        for f in files_to_check:
            assert os.path.exists(f)
Exemplo n.º 8
0
    def test_get_import_statements(self):
        """
        Test that import statements are generated correctly
        :return:
        """
        dirs = [
            'myproj/common',
            'myproj/specific',
            'yourproj',
            'theirproj/common',
            'theirproj/common/steps',
            'theirproj/specific',
            'theirproj/.git',
            'theirproj/.git/dir',
        ]

        files = [
            'myproj/common/file1.py',
            'myproj/common/file2.py',
            'myproj/specific/your.py',
            'yourproj/step.py',
            'theirproj/common/file3.py',
            'theirproj/common/file4.py',
            'theirproj/common/steps/file5.py',
            'theirproj/common/steps/file6.py',
            'theirproj/common/steps/file7.py',
        ]

        expected_out = [
            'from myproj.common.file1 import *',
            'from myproj.common.file2 import *',
            'from myproj.specific.your import *',
            'from yourproj.step import *',
            'from theirproj.common.file3 import *',
            'from theirproj.common.file4 import *',
            'from theirproj.common.steps.file5 import *',
            'from theirproj.common.steps.file6 import *',
            'from theirproj.common.steps.file7 import *',
        ]

        # create dirs
        for d in dirs:
            os.makedirs(d)

        # create files
        for f in files:
            with open(f, 'w') as fw:
                fw.write(f)

        output = BehaveWorkingDirectory.get_import_statements(os.getcwd())
        assert len(set(expected_out).intersection(output)) == len(expected_out)
Exemplo n.º 9
0
    def test_get_import_statements(self):
        """
        Test that import statements are generated correctly
        :return:
        """
        dirs = [
            'myproj/common',
            'myproj/specific',
            'yourproj',
            'theirproj/common',
            'theirproj/common/steps',
            'theirproj/specific',
            'theirproj/.git',
            'theirproj/.git/dir',
        ]

        files = [
            'myproj/common/file1.py',
            'myproj/common/file2.py',
            'myproj/specific/your.py',
            'yourproj/step.py',
            'theirproj/common/file3.py',
            'theirproj/common/file4.py',
            'theirproj/common/steps/file5.py',
            'theirproj/common/steps/file6.py',
            'theirproj/common/steps/file7.py',
        ]

        expected_out = [
            'from myproj.common.file1 import *',
            'from myproj.common.file2 import *',
            'from myproj.specific.your import *',
            'from yourproj.step import *',
            'from theirproj.common.file3 import *',
            'from theirproj.common.file4 import *',
            'from theirproj.common.steps.file5 import *',
            'from theirproj.common.steps.file6 import *',
            'from theirproj.common.steps.file7 import *',
        ]

        # create dirs
        for d in dirs:
            os.makedirs(d)

        # create files
        for f in files:
            with open(f, 'w') as fw:
                fw.write(f)

        output = BehaveWorkingDirectory.get_import_statements(os.getcwd())
        assert len(set(expected_out).intersection(output)) == len(expected_out)
Exemplo n.º 10
0
    def test_find_tests_config_multiple(self):
        """
        Test that configuration files are found and that .ini has preference
        :return:
        """
        files = [
            'test.ini',
            'tests.conf',
        ]

        for f in files:
            with open(f, 'w') as fw:
                fw.write('xyz')

        assert BehaveWorkingDirectory.find_tests_config(self.WORKING_DIR) == os.path.join(self.WORKING_DIR, files[0])
Exemplo n.º 11
0
    def test_find_tests_config_multiple(self):
        """
        Test that configuration files are found and that .ini has preference
        :return:
        """
        files = [
            'test.ini',
            'tests.conf',
        ]

        for f in files:
            with open(f, 'w') as fw:
                fw.write('xyz')

        assert BehaveWorkingDirectory.find_tests_config(
            self.WORKING_DIR) == os.path.join(self.WORKING_DIR, files[0])
Exemplo n.º 12
0
    def test_find_tests_config_existing(self):
        """
        Test that configuration files are successfully found
        :return:
        """

        files = [
            'test.ini',
            'tests.ini',
            'test.conf',
            'tests.conf',
        ]

        for f in files:
            with open(f, 'w') as fw:
                fw.write('xyz')
            assert BehaveWorkingDirectory.find_tests_config(self.WORKING_DIR) == os.path.join(self.WORKING_DIR, f)
            os.remove(f)
            assert not os.path.exists(f)
Exemplo n.º 13
0
    def test_find_tests_config_existing(self):
        """
        Test that configuration files are successfully found
        :return:
        """

        files = [
            'test.ini',
            'tests.ini',
            'test.conf',
            'tests.conf',
        ]

        for f in files:
            with open(f, 'w') as fw:
                fw.write('xyz')
            assert BehaveWorkingDirectory.find_tests_config(
                self.WORKING_DIR) == os.path.join(self.WORKING_DIR, f)
            os.remove(f)
            assert not os.path.exists(f)
Exemplo n.º 14
0
 def test_find_tests_config_none(self):
     """
     Test that if no configuration file is present, None is returned
     :return:
     """
     assert BehaveWorkingDirectory.find_tests_config(self.WORKING_DIR) is None
Exemplo n.º 15
0
class Application(object):

    def __init__(self, cli_args=None):
        """
        The Application implementation.
        """
        self._execution_dir_path = os.getcwd()
        self._working_dir_path = os.path.join(self._execution_dir_path,
                                              'workdir')

        self._working_dir = None
        self._behave_runner = None

        if not cli_args.cli_config_path:
            cli_args.cli_config_path = CTFCliConfig.find_cli_config(self._execution_dir_path)
        self._cli_conf = CTFCliConfig(cli_args)

    def init(self):
        """
        Initialize default app test structure
        """
        logger.info("Initialize default directory structure")

        # Make sure we're in a directory under git control
        try:
            check_call('git rev-parse &> /dev/null', shell=True)
        except CalledProcessError:
            logger.info("Directory is not under git control, running git init")
            check_call("git init &> /dev/null", shell=True)

        # Create test dir if it is missing
        tests_dir = os.path.join(self._execution_dir_path, "tests")
        if os.path.exists(tests_dir):
            logger.info("Directory tests already exists")
        else:
            logger.info("Creating tests directory")
            os.mkdir(tests_dir)
            check_call("git add %s" % tests_dir, shell=True)

        features_dir = os.path.join(tests_dir, "features")
        if os.path.exists(features_dir):
            logger.info("Directory tests/features already exists")
        else:
            logger.info("Creating tests/features directory")
            os.mkdir(features_dir)
            check_call("git add %s" % features_dir, shell=True)

        steps_dir = os.path.join(tests_dir, "steps")
        if os.path.exists(steps_dir):
            logger.info("Directory tests/steps already exists")
        else:
            logger.info("Creating tests/steps directory")
            os.mkdir(steps_dir)
            check_call("git add %s" % steps_dir, shell=True)

        # TODO: check that this file is actually necessary
        steps_init_file = os.path.join(steps_dir, "__init__.py")
        if os.path.exists(steps_init_file):
            logger.info("File tests/steps/__init__.py already exists")
        else:
            logger.info("Creating tests/steps/__init__.py file")
            open(steps_init_file, "a").close()
            check_call("git add %s" % steps_init_file, shell=True)

        steps_py_file = os.path.join(steps_dir, "steps.py")
        if os.path.exists(steps_py_file):
            logger.info("File tests/steps/steps.py already exists")
        else:
            logger.info("Creating tests/steps/steps.py file")
            with open(steps_py_file, "w") as f:
                f.write(common_steps_py_content)
            check_call("git add %s" % steps_py_file, shell=True)

        # Copy sample configuration
        ctf_conf_file = os.path.join(self._execution_dir_path, "ctf.conf")
        if os.path.exists(ctf_conf_file):
            logger.info("File ctf.conf already exists")
        else:
            logger.info("Creating ctf.conf file")
            # Create environment.py
            with open(ctf_conf_file, "w") as f:
                f.write(sample_ctl_ctf_config)
            check_call("git add %s" % ctf_conf_file, shell=True)

    def add_remote(self):
        if 'feature' in self._cli_conf.get(
                CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_REMOTE_TYPE):
            self.add_remote_feature()
        else:
            self.add_remote_step()

    def add_remote_feature(self):
        path = "tests/features/"
        try:
            project = self._cli_conf.get(
                CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_REMOTE_PROJECT)
            assert project
            path = "tests/features/" + project
        except Exception:
            pass
        self.add_submodule(path)

    def add_remote_step(self):
        path = "tests/steps/"
        try:
            project = self._cli_conf.get(
                CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_REMOTE_PROJECT)
            assert project
            path = "tests/steps/" + project
        except Exception:
            pass
        self.add_submodule(path)

    def list_remotes(self):
        check_call("git submodule -q foreach 'git config --get remote.origin.url'", shell=True)

    def add_submodule(self, path):
        url = self._cli_conf.get(CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_REMOTE_URL)
        dirname = os.path.splitext(os.path.basename(url))[0].replace('-', '_')
        check_call('git submodule add %s %s' % (url, path + "/" + dirname), shell=True)

    def remove_remote(self):
        name = self._cli_conf.get(CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_REMOTE_NAME)
        check_call('git submodule deinit -f %s' % name, shell=True)
        check_call('git config -f .gitmodules --remove-section "submodule.%s"' % name, shell=True)
        gitmodules_dir = os.path.join(os.path.abspath(".git/modules"), name)
        shutil.rmtree(gitmodules_dir)
        shutil.rmtree(name)

    def run(self):
        """
        The main application execution method
        """
        logger.info("Running Containers Testing Framework cli")

        try:
            check_call("git submodule update --init", shell=True)
        except:
            pass

        # TODO: Remove this or rework, once more types are implemented
        if self._cli_conf.get(
                CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_EXEC_TYPE) != 'ansible':
            raise CTFCliError("Wrong ExecType configured. Currently only 'ansible' is supported!")

        self._working_dir = BehaveWorkingDirectory(self._working_dir_path, self._cli_conf)

        # Setup Behave structure inside working directory
        # Clone common Features and steps into the working dir
        # Add the project specific Features and steps
        # Prepare the steps.py in the Steps dir that combines all the other
        self._working_dir.setup()

        # Execute Behave
        self._behave_runner = BehaveRunner(self._working_dir, self._cli_conf)
        sys.exit(self._behave_runner.run())

    def update(self):
        """
        Update app submodules
        """
        logger.info("Updating remote test and features")

        check_call("git submodule foreach git pull --rebase origin master", shell=True)
Exemplo n.º 16
0
class Application(object):

    def __init__(self, cli_args=None):
        """
        The Application implementation.
        """
        self._execution_dir_path = os.getcwd()
        self._working_dir_path = os.path.join(self._execution_dir_path,
                                              'workdir')

        self._working_dir = None
        self._behave_runner = None

        if not cli_args.cli_config_path:
            cli_args.cli_config_path = CTFCliConfig.find_cli_config(self._execution_dir_path)
        self._cli_conf = CTFCliConfig(cli_args)

    def init(self):
        """
        Initialize default app test structure
        """
        logger.info("Initialize default directory structure")

        # Make sure we're in a directory under git control
        try:
            check_call('git rev-parse', shell=True)
        except CalledProcessError:
            logger.info("Directory is not under git control, running git init")
            check_call("git init", shell=True)

        # Create test dir if it is missing
        tests_dir = os.path.join(self._execution_dir_path, "tests")
        if os.path.exists(tests_dir):
            logger.info("Directory tests already exists")
        else:
            logger.info("Creating tests directory")
            os.mkdir(tests_dir)
            check_call("git add %s" % tests_dir, shell=True)

        env_py_path = os.path.join(tests_dir, "environment.py")
        if os.path.exists(env_py_path):
            logger.info("File tests/environment.py already exists")
        else:
            logger.info("Creating environment.py")
            # Create environment.py
            with open(env_py_path, "w") as f:
                f.write(common_environment_py_content)
            check_call("git add %s" % env_py_path, shell=True)

        features_dir = os.path.join(tests_dir, "features")
        if os.path.exists(features_dir):
            logger.info("Directory tests/features already exists")
        else:
            logger.info("Creating tests/features directory")
            os.mkdir(features_dir)
            check_call("git add %s" % features_dir, shell=True)

        steps_dir = os.path.join(tests_dir, "steps")
        if os.path.exists(steps_dir):
            logger.info("Directory tests/steps already exists")
        else:
            logger.info("Creating tests/steps directory")
            os.mkdir(steps_dir)
            check_call("git add %s" % steps_dir, shell=True)

        # TODO: check that this file is actually necessary
        steps_init_file = os.path.join(steps_dir, "__init__.py")
        if os.path.exists(steps_init_file):
            logger.info("File tests/steps/__init__.py already exists")
        else:
            logger.info("Creating tests/steps/__init__.py file")
            open(steps_init_file, "a").close()
            check_call("git add %s" % steps_init_file, shell=True)

        steps_py_file = os.path.join(steps_dir, "steps.py")
        if os.path.exists(steps_py_file):
            logger.info("File tests/steps/steps.py already exists")
        else:
            logger.info("Creating tests/steps/steps.py file")
            with open(steps_py_file, "w") as f:
                f.write(common_steps_py_content)
            check_call("git add %s" % steps_py_file, shell=True)

        # Add common-features and common-steps as submodules
        # TODO:  make this generic when a different type of container is specified
        common_features_dir = os.path.join(features_dir, "common-features")
        if os.path.exists(common_features_dir):
            logger.info("Directory tests/features/common-features already exists")
        else:
            logger.info("Adding tests/features/common-features as a submodule")
            check_call('git submodule add https://github.com/Containers-Testing-Framework/common-features.git tests/features/common-features', shell=True)

        common_steps_dir = os.path.join(steps_dir, "common_steps")
        if os.path.exists(common_steps_dir):
            logger.info("Directory tests/steps/common_steps already exists")
        else:
            logger.info("Adding tests/steps/common_steps as a submodule")
            check_call('git submodule add https://github.com/Containers-Testing-Framework/common-steps.git tests/steps/common_steps', shell=True)

        # Copy sample configuration
        ctf_conf_file = os.path.join(self._execution_dir_path, "ctf.conf")
        if os.path.exists(ctf_conf_file):
            logger.info("File ctf.conf already exists")
        else:
            logger.info("Creating ctf.conf file")
            # Create environment.py
            with open(ctf_conf_file, "w") as f:
                f.write(sample_ctl_ctf_config)
            check_call("git add %s" % ctf_conf_file, shell=True)

    def run(self):
        """
        The main application execution method
        """
        logger.info("Running Containers Testing Framework cli")

        # If no Dockerfile passed on the cli, try to use one from the execution directory
        if not self._cli_conf.get(CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_DOCKERFILE):
            local_file = os.path.join(self._execution_dir_path, 'Dockerfile')
            if not os.path.isfile(local_file):
                raise CTFCliError("No Dockerfile passed on the cli and no Dockerfile "
                                  "is present in the current directory!")
            logger.debug("Using Dockerfile from the current directory.")
            self._cli_conf.set(CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_DOCKERFILE, local_file)

        # TODO: Remove this or rework, once more types are implemented
        if self._cli_conf.get(CTFCliConfig.GLOBAL_SECTION_NAME, CTFCliConfig.CONFIG_EXEC_TYPE) != 'ansible':
            raise CTFCliError("Wrong ExecType configured. Currently only 'ansible' is supported!")

        self._working_dir = BehaveWorkingDirectory(self._working_dir_path, self._cli_conf)

        # Setup Behave structure inside working directory
        # Clone common Features and steps into the working dir
        # Add the project specific Features and steps
        # Prepare the steps.py in the Steps dir that combines all the other
        self._working_dir.setup()

        # Execute Behave
        self._behave_runner = BehaveRunner(self._working_dir, self._cli_conf)
        return self._behave_runner.run()

    def update(self):
        """
        Update app submodules
        """
        logger.info("Updating Containers Testing Framework common steps and features")

        common_steps_dir = os.path.join(self._execution_dir_path, "tests", "steps", "common_steps")
        common_features_dir = os.path.join(self._execution_dir_path, "tests", "features", "common-features")
        for directory in [common_steps_dir, common_features_dir]:
            logger.info("Updating %s" % directory)
            check_call("git fetch origin", shell=True, cwd=directory)
            check_call("git checkout origin/master", shell=True, cwd=directory)

        # Check that steps are not contradicting with each other
        logger.info("Checking project steps sanity")
        check_call("behave tests -d", shell=True)