예제 #1
0
    def test_warning_utils(self):
        root_trace = FunctionalTrace(
            parent_trace=None,
            path_mask=self._path_mask).doing("Testing Warning Utils")
        try:
            TEST_SCENARIO = 'test_warning_utils'

            my_trace = root_trace.doing("Testing a fake warning")

            with warnings.catch_warnings(record=True) as w:
                WarningUtils().turn_traceback_on(my_trace, warnings_list=w)

                warnings.warn("Test warning for Warning Utils",
                              DeprecationWarning)

                WarningUtils().handle_warnings(my_trace, warning_list=w)

                # The handling of the warning should raise an exception, so we should not get here
                self.assertTrue(1 == 2)

        except ApodeixiError as ex:
            output_txt = ex.trace_message()
            self._compare_to_expected_txt(parent_trace=my_trace,
                                          output_txt=output_txt,
                                          test_output_name=TEST_SCENARIO,
                                          save_output_txt=True)
예제 #2
0
def apis(kb_session):
    '''
    Gets the list of posting and manifest APIs supported by the KnowledgeBase
    '''
    timer = ApodeixiTimer()
    func_trace = FunctionalTrace(parent_trace=None, path_mask=None)
    root_trace = func_trace.doing("CLI call to get posting APIs",
                                  origination={'signaled_from': __file__})
    try:
        posting_apis_description = CLI_Utils().get_apodeixi_apis(
            root_trace, kb_session)
        click.echo(posting_apis_description)
        output = "Success"
        click.echo(output)
        click.echo(timer.elapsed_time_message())
    except ApodeixiError as ex:
        error_msg = CLI_ErrorReporting(kb_session).report_a6i_error(
            parent_trace=root_trace, a6i_error=ex)
        # GOTCHA
        #       Use print, not click.echo or click exception because they don't correctly display styling
        #       (colors, underlines, etc.). So use vanilla Python print and then exit
        print(error_msg)
        _sys.exit()
    except Exception as ex:
        click.echo("Unrecoverable error: " + str(ex))
        _sys.exit()
예제 #3
0
def products(kb_session, all, environment):
    '''
    Gets the list of valid products for the system.
    '''
    timer = ApodeixiTimer()
    func_trace = FunctionalTrace(parent_trace=None, path_mask=None)
    root_trace = func_trace.doing("CLI call to get products",
                                  origination={'signaled_from': __file__})
    try:
        environment_filter = _get_environment_filter(root_trace, kb_session,
                                                     all, environment)
        products_description = CLI_Utils().get_products(
            root_trace, kb_session, environment_filter)
        click.echo(products_description)
        output = "Success"
        click.echo(output)
        click.echo(timer.elapsed_time_message())
    except ApodeixiError as ex:
        error_msg = CLI_ErrorReporting(kb_session).report_a6i_error(
            parent_trace=root_trace, a6i_error=ex)
        # GOTCHA
        #       Use print, not click.echo or click exception because they don't correctly display styling
        #       (colors, underlines, etc.). So use vanilla Python print and then exit
        print(error_msg)
        _sys.exit()
    except Exception as ex:
        click.echo("Unrecoverable error: " + str(ex))
        _sys.exit()
    def _attach_subtree(self, df_to_attach, intervals, tree_to_attach_to, docking_uid, xlr_config, acronym_schema):
        store           = tree_to_attach_to.uid_store
        
        entity_type     = intervals[0].entity_name
        subtree         = BreakdownTree(uid_store = store, entity_type=entity_type, parent_UID=docking_uid)
         
        rows            = list(df_to_attach.iterrows())
        root_trace      = FunctionalTrace(parent_trace=None, path_mask=self._path_mask).doing("Populating subtree", data={'subtree.entity_type'  : entity_type,
                                                                                    'columns'           : list(df_to_attach.columns)},
                                                                            origination = {
                                                                                    'signaled_from': __file__})
        store.set_acronym_schema(root_trace, acronym_schema)
        for idx in range(len(rows)):
            for interval in intervals:
                my_trace        = root_trace.doing(activity="Processing fragment", data={'row': idx, 'interval': interval})
                subtree.readDataframeFragment(  interval            = interval, 
                                                row                 = rows[idx],    
                                                parent_trace        = my_trace, 
                                                all_rows            = rows, 
                                                xlr_config          = xlr_config,
                                                acronym_schema      = None)

        root_trace      = FunctionalTrace(parent_trace=None, path_mask=self._path_mask).doing("Attaching subtree", data = {"docking UID"   : "'" + subtree.parent_UID + "'",
                                                                                    "entity_type"  : "'" + entity_type + "'"})
        tree_to_attach_to.dock_subtree(entity_type, subtree, root_trace)
    def activateTestConfig(self):
        '''
        Modifies environment variables to ensure that Apodeixi uses a configuration specific for tests.
        This change endures until the dual method self.deactivateTestConfig() is called.
        '''
        # Remember it before we change it to use a test configuration, and then restore it in the tearDown method
        self.original_config_directory              = _os.environ.get(self.CONFIG_DIRECTORY())

        # Here we want the location of this class, not its concrete derived class,
        # since the location of the Apodexei config to be used for tests is globally unique
        # So we use __file__ 
        #
        # MODIFICATION ON APRIL, 2022: As part of adding tests in CI/CD, we made it possible for a CI/CD pipeline
        #       to specify a location for the Apodeixi config directory that should be used for integration tests.
        #       As a result, we only hard-code such config directory if we are not running in an environment where that
        #       has been already set. This enables:
        #       1) Preservation of traditional Apodeixi feature for developers, whereby tests will "auto discover"
        #       the test_db to use even if the environment variable for the Apodeixi CONFIG_DIRECTORY is not set
        #       2) Enablement of new use case for CI/CD: externally injected configuration of which config directory to use
        
        if not self.INJECTED_CONFIG_DIRECTORY in _os.environ.keys():
            # Use case: developer runs tests locally
            _os.environ[self.CONFIG_DIRECTORY()]    = _os.path.join(_os.path.dirname(__file__), '../../../../apodeixi-testdb')
        else: 
            # Use case: CI/CD pipeline runs tests in a Docker container
            _os.environ[self.CONFIG_DIRECTORY()]    = _os.environ[self.INJECTED_CONFIG_DIRECTORY]

        func_trace              = FunctionalTrace(  parent_trace    = None, 
                                                    path_mask       = None) # path_mask has not been set yet as an attribute
        root_trace              = func_trace.doing("Loading Apodeixi configuration",
                                                    origination     = {'signaled_from': __file__})
        self.a6i_config         = ApodeixiConfig(root_trace)
예제 #6
0
    def test_merge_lists(self):
        root_trace = FunctionalTrace(
            parent_trace=None,
            path_mask=self._path_mask).doing("Testing List Merger")
        try:
            INPUT_FOLDER = self.input_data
            OUTPUT_FOLDER = self.output_data
            TEST_SCENARIO = 'test_merge_lists'
            OUTPUT_FILE = TEST_SCENARIO + '_OUTPUT.txt'
            EXPECTED_FILE = TEST_SCENARIO + '_EXPECTED.txt'

            list1 = [1000, 3000, 4000, 5000, 8000, 9000]
            list2 = [1000, 2000, 3000, 4000, 5000, 6000, 7000, 9000]

            my_trace = root_trace.doing("Merging lists")

            merger = ListMerger(parent_trace=my_trace,
                                list1=list1,
                                list2=list2,
                                list1_name="left",
                                list2_name="right")

            merged_list = merger.merge(my_trace)

            my_trace = root_trace.doing(
                "Comparing merge list to expected output")

            output_txt = '============ List1 ================\n' + str(list1)
            output_txt += '\n\n============ List2 ================\n' + str(
                list2)
            output_txt += '\n\n============ Merged Result ================\n' + merger.format_results(
                my_trace)
            '''
            output_txt                      = '\n'.join(['\t\t'.join(["Element: " + str(e[0]), 
                                                                    "LEFT" if e[1] else "    ", 
                                                                    "RIGHT" if e[2] else "     "]) for e in merged_list])
            '''

            self._compare_to_expected_txt(parent_trace=my_trace,
                                          output_txt=output_txt,
                                          test_output_name=TEST_SCENARIO,
                                          save_output_txt=True)

        except ApodeixiError as ex:
            print(ex.trace_message())
            self.assertTrue(1 == 2)
예제 #7
0
    def test_cli_diff_basic(self):
        '''
        Tests diff functionality between the lastest version of a manifest and its prior version
        '''
        self.setScenario("cli.basic_diff")
        self.setCurrentTestName('basic_diff')
        self.selectTestDataLocation()

        root_trace                      = FunctionalTrace(parent_trace=None, path_mask=self._path_mask) \
                                            .doing("Running " + self.currentTestName())

        PRODUCTS_FILE = 'products.static-data.admin.a6i.xlsx'
        SCORING_CYCLES_FILE = 'scoring-cycles.static-data.admin.a6i.xlsx'
        BIG_ROCKS_FILE_V1 = 'v1.big-rocks.journeys.a6i.xlsx'
        BIG_ROCKS_FILE_V2 = 'v2.big-rocks.journeys.a6i.xlsx'
        MANIFEST_API = 'delivery-planning.journeys.a6i.io'
        KIND = 'big-rock'
        NAMESPACE = 'cicloquimica.production'
        NAME = 'modernization.fy-22.astrea.official'

        #STATIC_DATA_WORKING_DIR         = "admin/static-data"
        #PRODUCT_WORKING_DIR             = "journeys/FY 22/Astrea/Official"

        _path_of = self.fullpath_of

        MASK_COMBINED = CLI_Utils().combined_mask(root_trace, self.a6i_config)

        # This will fool the CLI to treat our provisioned environment for this test as if it were the base environment
        self.overwrite_test_context(
            root_trace
        )  # Overwrites self.a6i_config , the store, the test_db, etc.

        my_trace = root_trace.doing("Running commands")

        COMMANDS = [
            ['post', '--timestamp', "_CLI__1",
             _path_of(PRODUCTS_FILE)],
            ['post', '--timestamp', "_CLI__2",
             _path_of(SCORING_CYCLES_FILE)],
            ['post', '--timestamp', "_CLI__3",
             _path_of(BIG_ROCKS_FILE_V1)],
            ['post', '--timestamp', "_CLI__4",
             _path_of(BIG_ROCKS_FILE_V2)],
            ['diff', MANIFEST_API, KIND, NAMESPACE, NAME]
        ]

        self.skeleton_test(
            parent_trace=my_trace,
            cli_command_list=COMMANDS,
            output_cleanining_lambda=MASK_COMBINED,
            when_to_check_environment=CLI_Test_Skeleton.ONLY_AT_END)
예제 #8
0
    def __init__(self):
        try:
            func_trace = FunctionalTrace(parent_trace=None, path_mask=None)
            root_trace = func_trace.doing(
                "Initializing KB_Session for Apodeixi CLI",
                origination={'signaled_from': __file__})

            # The initializer will set self.a6i_config. But in a sort of chicken-and egg situation, we find
            # ourselves forced to load a "temporary" config object to figure out the class name of the initializer ot use.
            # This "temporary" config might not be the "right class" if the initializer
            # is not the default Apodeixi class (for example, if an Apodeixi extension is using a derived initializer
            # class), but at least the "temporary" config will let us get the initializer class.
            #
            temporary_config = ApodeixiConfig(root_trace)

            initializer_class_name = temporary_config.get_CLI_InitializerClassname(
                root_trace)

            try:
                module_path, class_name = initializer_class_name.rsplit('.', 1)
                module = import_module(module_path)
                initializer_class = getattr(module, class_name)
                initializer = initializer_class()
            except (ImportError, AttributeError) as ex:
                raise ApodeixiError(root_trace,
                                    "Unable to construct class '" +
                                    str(initializer_class_name) + "'",
                                    data={"error": ex.msg})

            initializer.initialize(root_trace, self)

            # This will look like '210703.102746', meaning the 3rd of July of 2021 at 10:27 am (and 46 sec).
            # Intention is this timestamp as an "identifier" of this KnowledgeBase session, by using as prefix
            # to folders or files (e.g., sandboxes, logs) created during the existence of this KnowledgeBase session
            dt = _datetime.datetime.today()
            self.timestamp = dt.strftime("%y%m%d.%H%M%S")

            self.error_count = 1  # Increments each time we log an error

        except ApodeixiError as ex:
            error_msg = CLI_ErrorReporting(None).report_a6i_error(
                parent_trace=root_trace, a6i_error=ex)
            # GOTCHA
            #       Use print, not click.echo or click exception because they don't correctly display styling
            #       (colors, underlines, etc.). So use vanilla Python print and then exit
            print(error_msg)
            _sys.exit()
        except Exception as ex:
            print("Unrecoverable error: " + str(ex))
            _sys.exit()
예제 #9
0
def config(kb_session, environment):
    '''
    Displays the Apodeixi configuration.
    '''
    T0 = _datetime.datetime.now()
    func_trace = FunctionalTrace(parent_trace=None, path_mask=None)
    root_trace = func_trace.doing("CLI call to get products",
                                  origination={'signaled_from': __file__})
    try:
        if environment != None:
            kb_session.store.activate(parent_trace=root_trace,
                                      environment_name=environment)
            click.echo(CLI_Utils().sandox_announcement(environment))

        client_url = kb_session.store.getClientURL(root_trace)
        postings_url = kb_session.store.getPostingsURL(root_trace)
        click.echo("\n----- Current environment -----")
        click.echo("\nclient URL:\t\t" + str(client_url))
        click.echo("postings URL:\t\t" + str(postings_url))
        config_txt = DictionaryFormatter().dict_2_nice(
            root_trace, kb_session.a6i_config.config_dict, flatten=True)
        click.echo("\n\n----- Config Settings -----")
        click.echo("\n" + config_txt)
        output = "Success"
        click.echo(output)
    except ApodeixiError as ex:
        error_msg = CLI_ErrorReporting(kb_session).report_a6i_error(
            parent_trace=root_trace, a6i_error=ex)
        # GOTCHA
        #       Use print, not click.echo or click exception because they don't correctly display styling
        #       (colors, underlines, etc.). So use vanilla Python print and then exit
        print(error_msg)
        _sys.exit()
    except Exception as ex:
        click.echo("Unrecoverable error: " + str(ex))
        _sys.exit()
    T1 = _datetime.datetime.now()
    duration = T1 - T0

    duration_msg = str(duration.seconds) + "." + str(
        duration.microseconds) + " sec"
    click.echo(duration_msg)
예제 #10
0
    def _posting_testing_skeleton(self, store, test_case_name, excel_file):

        all_manifests_dicts                     = []

        try:
            root_trace                          = FunctionalTrace(parent_trace=None, path_mask=self._path_mask).doing("Posting excel file", 
                                                                                data={  'excel_file'    : excel_file},
                                                                                origination = {
                                                                                        'signaled_from' : __file__,
                                                                                        'concrete class': str(self.__class__.__name__)})

            kbase                               = KnowledgeBase(root_trace, store, a6i_config=self.a6i_config)

            response, log_txt                   = kbase.postByFile( parent_trace                = root_trace, 
                                                                    path_of_file_being_posted   = excel_file,
                                                                    excel_sheet                 = "Sheet1")

            NB_MANIFESTS_EXPECTED               = 3
            if len(response.createdManifests()) != NB_MANIFESTS_EXPECTED:
                raise ApodeixiError(root_trace, 'Expected ' + str(NB_MANIFESTS_EXPECTED) + ' manifests, but found ' 
                                    + str(len(all_manifests_dicts)))

            # Retrieve the manifests created
            manifest_dict                       = {}
            for handle in response.createdManifests():
                loop_trace                      = root_trace.doing("Retrieving manifest for handle " + str(handle),
                                                        origination = {    
                                                                    'concrete class': str(self.__class__.__name__), 
                                                                    'signaled_from': __file__})
                manifest_dict, manifest_path    = store.retrieveManifest(loop_trace, handle)
                self._compare_to_expected_yaml(loop_trace, manifest_dict, test_case_name + "." + handle.kind)

            return
        except ApodeixiError as ex:
            print(ex.trace_message()) 
            self.assertTrue(1==2)                 

        # If we get this far, the tests failed since we should have returned within the try statement. 
        # So hardcode an informative failure.
        self.assertTrue("Shouldn't have gotten to this line" == 0)                                                                      
예제 #11
0
    def test_cli_rollover_basic(self):
        '''
        Tests rollover functionality when traversing fiscal years: if there is no previous manifest for FY 23 but one
        exists from FY 22, then trying to retrieve the latest manifest in FY 23 will result in the latest one from FY 22,
        as opposed to a template-based default.
        '''
        self.setScenario("cli.basic_rollover")
        self.setCurrentTestName('basic_rollover')
        self.selectTestDataLocation()

        root_trace                      = FunctionalTrace(parent_trace=None, path_mask=self._path_mask) \
                                            .doing("Running " + self.currentTestName())

        PRODUCTS_FILE = 'products.static-data.admin.a6i.xlsx'
        SCORING_CYCLES_FILE = 'scoring-cycles.static-data.admin.a6i.xlsx'
        BIG_ROCKS_FILE_V1 = 'v1.big-rocks.journeys.a6i.xlsx'
        BIG_ROCKS_FILE_V2 = 'v2.big-rocks.journeys.a6i.xlsx'
        BIG_ROCKS_POSTING_API = 'big-rocks.journeys.a6i'
        BIG_ROCKS_MANIFEST_API = "delivery-planning.journeys.a6i.io"  #/v1a"
        NAMESPACE = 'cicloquimica.production'
        FY23_NAME = "modernization.fy-23.astrea.official"
        SUB_NAMESPACE = 'modernization'
        FY22_REL_PATH_IN_EXT_COLLAB = "journeys/FY 22/Astrea/Official"
        FY23_REL_PATH_IN_EXT_COLLAB = "journeys/FY 23/Astrea/Official"
        FY23_GENERATED_FORM_FILE = "Astrea.modernization.big-rocks.journeys.a6i.xlsx"

        STATIC_DATA_WORKING_DIR = "admin/static-data"

        _path_of = self.fullpath_of

        MASK_COMBINED = CLI_Utils().combined_mask(root_trace, self.a6i_config)

        # This will fool the CLI to treat our provisioned environment for this test as if it were the base environment
        self.overwrite_test_context(
            root_trace
        )  # Overwrites self.a6i_config , the store, the test_db, etc.

        store = self.stack().store()
        clientURL = store.base_environment(root_trace).clientURL(root_trace)

        # Post the static data
        my_trace = root_trace.doing("Running with working directory '" +
                                    STATIC_DATA_WORKING_DIR + "'")

        working_dir = clientURL + "/" + STATIC_DATA_WORKING_DIR

        PathUtils().create_path_if_needed(my_trace, working_dir)
        _os.chdir(working_dir)

        COMMANDS_1 = [
            ['post', '--timestamp', "_CLI__1",
             _path_of(PRODUCTS_FILE)],
            ['post', '--timestamp', "_CLI__2",
             _path_of(SCORING_CYCLES_FILE)],
        ]

        self.skeleton_test(parent_trace=my_trace,
                           cli_command_list=COMMANDS_1,
                           output_cleanining_lambda=MASK_COMBINED,
                           when_to_check_environment=CLI_Test_Skeleton.NEVER)

        # Post the FY 22 big rocks
        my_trace = root_trace.doing("Running with working directory '" +
                                    FY22_REL_PATH_IN_EXT_COLLAB + "'")
        fy22_working_dir = clientURL + "/" + FY22_REL_PATH_IN_EXT_COLLAB

        PathUtils().create_path_if_needed(my_trace, fy22_working_dir)
        _os.chdir(fy22_working_dir)

        COMMANDS_2 = [[
            'post', '--timestamp', "_CLI__3",
            _path_of(BIG_ROCKS_FILE_V1)
        ], ['post', '--timestamp', "_CLI__4",
            _path_of(BIG_ROCKS_FILE_V2)],
                      [
                          'get', 'form', '--timestamp', "_CLI__5",
                          BIG_ROCKS_POSTING_API, NAMESPACE, SUB_NAMESPACE
                      ]]

        self.skeleton_test(parent_trace=my_trace,
                           cli_command_list=COMMANDS_2,
                           output_cleanining_lambda=MASK_COMBINED,
                           when_to_check_environment=CLI_Test_Skeleton.NEVER)

        # For the next test, we need to switch the working directory for click
        my_trace = root_trace.doing("Running with working directory '" +
                                    FY23_REL_PATH_IN_EXT_COLLAB + "'")

        fy23_working_dir = clientURL + "/" + FY23_REL_PATH_IN_EXT_COLLAB

        PathUtils().create_path_if_needed(my_trace, fy23_working_dir)
        _os.chdir(fy23_working_dir)

        COMMANDS_3 = [
            [
                'get', 'form', '--timestamp', "_CLI__6", BIG_ROCKS_POSTING_API,
                NAMESPACE, SUB_NAMESPACE
            ],
            [
                'post', '--timestamp', "_CLI__7",
                fy23_working_dir + "/" + FY23_GENERATED_FORM_FILE
            ],
        ]

        self.skeleton_test(parent_trace=my_trace,
                           cli_command_list=COMMANDS_3,
                           output_cleanining_lambda=MASK_COMBINED,
                           when_to_check_environment=CLI_Test_Skeleton.NEVER)

        # Check that manifest is as expected right after a first FY 23 manifest is created from a rollover
        # For example, we expect its labels to include the rollFromName field to indicate its lineage as a continuation
        # of FY 22

        self.check_manifest(my_trace, BIG_ROCKS_MANIFEST_API, NAMESPACE,
                            FY23_NAME, 'big-rock')

        # Now we do a full cycle get-form + post, to see that the new lineage in FY 23 can take off as expected
        COMMANDS_4 = [
            [
                'get', 'form', '--timestamp', "_CLI__8", BIG_ROCKS_POSTING_API,
                NAMESPACE, SUB_NAMESPACE
            ],
            [
                'post', '--timestamp', "_CLI__9",
                fy23_working_dir + "/" + FY23_GENERATED_FORM_FILE
            ],
        ]

        self.skeleton_test(
            parent_trace=my_trace,
            cli_command_list=COMMANDS_4,
            output_cleanining_lambda=MASK_COMBINED,
            when_to_check_environment=CLI_Test_Skeleton.ONLY_AT_END)

        # Check that manifest is as expected right after we are no longer in a rollover situation, and are modifying
        # previous manifests in FY 23.
        #
        # For example, it should no longer be the case that its labels include the rollFromName field, as it used to
        # be the case when we created the first FY 23 manifest, since only that first manifested needed to
        # to indicate its lineage as a continuation of FY 22
        #
        self.check_manifest(my_trace, BIG_ROCKS_MANIFEST_API, NAMESPACE,
                            FY23_NAME, 'big-rock')
예제 #12
0
class Test_ApodeixiError(ApodeixiUnitTest):
    def setUp(self):
        super().setUp()

        self.root = FunctionalTrace(parent_trace=None,
                                    path_mask=self._path_mask)
        self.step1 = self.root.doing(activity="Processing Step 1",
                                     flow_stage=None,
                                     data={'fun fact': '-'},
                                     origination={'secret origin': '-'})

        self.step2 = self.root.doing(activity="Processing Step 2",
                                     flow_stage='Got past Step 1',
                                     data=None)

        for idx in range(5):
            if idx == 3:
                self.step2i = self.step2.doing(
                    activity="In loop cycle Step 2-" + str(idx),
                    flow_stage="Loop inside Step 2",
                    data={
                        'idx': idx,
                        'comment': 'Merrily processing loop'
                    },
                    origination={
                        'concrete class': str(self.__class__.__name__)
                    })

    def test_functional_trace(self):

        root_trace = FunctionalTrace(
            parent_trace=None,
            path_mask=self._path_mask).doing('Testing functional trace')
        output = "================== Step 1 =============\n\n" \
                + '\n\n'.join([str(trace_level) for trace_level in self.step1.examine(as_string=True,)]) \
                + "\n\n\n================== Step 2 =============\n\n" \
                + '\n\n'.join([str(trace_level) for trace_level in self.step2.examine(as_string=True,)]) \
                + "\n\n\n================== Step 2i =============\n\n" \
                + '\n\n'.join([str(trace_level) for trace_level in self.step2i.examine(as_string=True,)]) \

        self._compare_to_expected_txt(root_trace,
                                      output,
                                      test_output_name='functional_trace',
                                      save_output_txt=True)

    def test_a6i_error(self):
        MSG = "Error with horrible consequences for you"
        root_trace = FunctionalTrace(
            parent_trace=None,
            path_mask=self._path_mask).doing('Testing Apodeixi error message')
        try:
            raise ApodeixiError(self.step2i, MSG)
        except ApodeixiError as ex:
            trace = ex.functional_trace
            msg = ex.msg
            output = msg + "\n\n" \
                    + '\n\n'.join([str(trace_level) for trace_level in trace.examine(as_string=True,)]) \

            self._compare_to_expected_txt(root_trace,
                                          output,
                                          test_output_name='a6i_error',
                                          save_output_txt=True)
예제 #13
0
    def test_path_utils(self):
        root_trace                      = FunctionalTrace(parent_trace=None, path_mask=self._path_mask).doing("Testing Path Utils")
        try:
            INPUT_FOLDER                    = self.input_data
            OUTPUT_FOLDER                   = self.output_data
            TEST_SCENARIO                   = 'test_path_utils'
            OUTPUT_FILE                     = TEST_SCENARIO + '_OUTPUT.txt'
            EXPECTED_FILE                   = TEST_SCENARIO + '_EXPECTED.txt'



            list1                           = [ 1000,           3000,   4000,   5000,                   8000,   9000]
            list2                           = [ 1000,   2000,   3000,   4000,   5000,   6000,   7000,           9000]

            root_dir, parent_dir            = _os.path.split(self.input_data)

            rel_real_file                   = parent_dir + '/' + TEST_SCENARIO + '_INPUT.txt'
            real_file                       = root_dir + '/' + rel_real_file

            rel_fake_file                   = parent_dir + '/' + TEST_SCENARIO +  '_NOT_REAL.foo'
            fake_file                       = root_dir + '/' + rel_fake_file

            leaf                            = "my_file.txt"
            non_leaf                        = "secrets/my_file.txt"

            bad_path                        = "/august/marzo/time.txt"

            # Test is_leaf
            my_trace                        = root_trace.doing("Testing is_leaf")
            output_txt                      = '============ Testing is_leaf ================\n'

            val                             = PathUtils().is_leaf(my_trace, leaf)
            output_txt                      += "\nis_leaf(" + leaf + ")\t\t= " + str(val)

            val                             = PathUtils().is_leaf(my_trace, non_leaf)
            output_txt                      += "\n\nis_leaf(" + non_leaf + ")\t\t= " + str(val)

            # Test is_parent
            my_trace                        = root_trace.doing("Testing is_parent")
            output_txt                      += '\n\n============ Testing is_parent ================\n'

            val                             = PathUtils().is_parent(my_trace, parent_dir = root_dir, path = real_file)
            output_txt                      += "\nis_parent(" + "< ... >" \
                                                + ", < ... >/" + rel_real_file + ") = " + str(val)

            val                             = PathUtils().is_parent(my_trace, parent_dir = root_dir, path = bad_path)
            output_txt                      += "\n\nis_parent(" + "< ... >, " + bad_path + ") = " + str(val)

            # Test relativize
            my_trace                        = root_trace.doing("Testing relativize")
            output_txt                      += '\n\n============ Testing is_parent ================\n'

            val                             = PathUtils().relativize(my_trace, root_dir = root_dir, full_path = real_file)
            output_txt                      += "\nrelativize(" + "< ... >" \
                                                + ", < ... >/" + rel_real_file + ") = \n\t\t" + str(val)            

            try:
                val                             = PathUtils().relativize(my_trace, root_dir = root_dir, full_path = fake_file)
            except ApodeixiError as ex:
                val                         = str(ex)
            output_txt                      += "\n\nrelativize(" + "< ... >" \
                                                + ", < ... >/" + rel_fake_file + ") = \n\t\t" + str(val)  

            # Test tokenize_path
            my_trace                        = root_trace.doing("Testing tokenize_path")
            output_txt                      += '\n\n============ Testing tokenize_path ================\n'

            relative_path                   = "/visions\\ideas\\problems/corrections"
            val                             = PathUtils().tokenizePath(my_trace, relative_path, absolute = False)
            output_txt                      += "\ntokenizePath(" + relative_path + ") = \n\t\t" + str(val)
                                                
            # To test tokenization of an absolute path, we must be sensitive to whether we are in Windows or Linux in order
            # to produce deterministic regression output. This means:
            #   1. The absolute path should start with "C:\" in windows and "/C/" in Linux.
            #   2. Don't display the drive in the regression test output (i.e., don't print the first token)
            if _os.name == "nt":
                absolute_path               = "C:\\visions\\ideas\\problems/corrections"
            else:
                absolute_path               = "/C/visions\\ideas\\problems/corrections"

            val                             = PathUtils().tokenizePath(my_trace, absolute_path)
            output_txt                      += "\n\ntokenizePath(" + "C:\\visions\\ideas\\problems/corrections" + ")[1:] = \n\t\t" + str(val[1:])

            self._compare_to_expected_txt(  parent_trace        = my_trace,
                                            output_txt          = output_txt,
                                            test_output_name    = TEST_SCENARIO, 
                                            save_output_txt     = True)

        except ApodeixiError as ex:
            print(ex.trace_message())
            self.assertTrue(1==2)
예제 #14
0
def diff(kb_session, manifest_api, kind, namespace, name):
    '''
    Makes a diff between two versions of a manifest.
    
    For a list of valid MANIFEST_APIs and KINDs, try 'get apis'
    
    For a list of valid NAMESPACEs and NAMEs, try 'get assertions'

    MANIFEST_API must be a versionless manifest API. 
    
    Example: 'delivery-planning.journeys.a6i.io', (as opposed to 'delivery-planning.journeys.a6i.io/v1a'). 
    '''
    timer = ApodeixiTimer()
    func_trace = FunctionalTrace(parent_trace=None, path_mask=None)
    root_trace = func_trace.doing("CLI call to post",
                                  origination={'signaled_from': __file__})

    kb_operation_succeeded = False
    try:

        my_trace = root_trace.doing(
            "Invoking ManifestUtils's postByFile service")

        diff_result = ManifestUtils().diff_manifest(
            parent_trace=my_trace,
            store=kb_session.store,
            manifest_api_name=manifest_api,
            namespace=namespace,
            name=name,
            kind=kind,
            version1=None,
            version2=None)
        kb_operation_succeeded = True

        diff_description = CLI_Utils().describe_diff_response(
            my_trace, kb_session, diff_result)

        # GOTCHA:
        # Make sure to remove non-ascii characters before passing the description to click.echo, since it
        # will raise errors if there are characters like \uFFFFD in the description
        #
        diff_description = StringUtils().to_ascii(diff_description)

        click.echo(diff_description)
        output = "Success"
        click.echo(output)
        click.echo(timer.elapsed_time_message())
    except ApodeixiError as ex:
        error_msg = CLI_ErrorReporting(kb_session).report_a6i_error(
            parent_trace=root_trace, a6i_error=ex)
        if kb_operation_succeeded:
            error_msg                       = "KnowledgeBase operation completed, but run into a problem when preparing "\
                                                + "a description of the response:\n"\
                                                + error_msg
        # GOTCHA
        #       Use print, not click.echo or click exception because they don't correctly display styling
        #       (colors, underlines, etc.). So use vanilla Python print and then exit
        print(error_msg)
        _sys.exit()
    except Exception as ex:
        try:
            error_msg = CLI_ErrorReporting(kb_session).report_generic_error(
                parent_trace=root_trace, generic_error=ex)
            if kb_operation_succeeded:
                error_msg                   = "KnowledgeBase operation completed, but run into a problem when preparing "\
                                                + "a description of the response:\n"\
                                                + error_msg
        except Exception as ex2:
            error_msg                       = "CLI run into trouble: found error:\n\n\t" + str(ex) + "\n\n" \
                                                + "To make things worse, when trying to produce an error log file with a "\
                                                + "stack trace, run into an additional error:\n\n\t" + str(ex2)
        # GOTCHA
        #       Use print, not click.echo or click exception because they don't correctly display styling
        #       (colors, underlines, etc.). So use vanilla Python print and then exit
        print(error_msg)
        _sys.exit()
예제 #15
0
def form(kb_session, posting_api, namespace, subnamespace, dry_run,
         environment, timestamp):
    '''
    Requests a form (an Excel spreadsheet) which (after some edits, as appropriate) can be used as the
    input to the post command.
    '''
    timer = ApodeixiTimer()
    func_trace = FunctionalTrace(parent_trace=None, path_mask=None)
    root_trace = func_trace.doing("CLI call to post",
                                  origination={'signaled_from': __file__})
    kb_operation_succeeded = False
    try:
        # Catch warnings and handle them so that we avoid spurious noise in the CLI due to noisy 3rd party libraries
        with warnings.catch_warnings(record=True) as w:
            WarningUtils().turn_traceback_on(root_trace, warnings_list=w)
            if environment != None:
                kb_session.store.activate(parent_trace=root_trace,
                                          environment_name=environment)
                click.echo(CLI_Utils().sandox_announcement(environment))
            elif dry_run == True:
                sandbox_name = kb_session.provisionSandbox(root_trace)
                click.echo(CLI_Utils().sandox_announcement(sandbox_name))
            '''
            else:
                raise ApodeixiError(root_trace, "Sorry, only sandbox-isolated runs are supported at this time. Aborting.")
            '''
            # Now that we have pinned down the environment (sandbox or not) in which to call the KnowledgeBase's services,
            # set that environment's tag to use for KnoweldgeBase's posting logs, if the user set it.
            if timestamp:
                kb_session.store.current_environment(root_trace).config(
                    root_trace).use_timestamps = timestamp

            my_trace = root_trace.doing(
                "Invoking KnowledgeBase's requestForm service")

            output_dir = _os.getcwd()
            clientURL = kb_session.store.getClientURL(my_trace)
            relative_path, void = PathUtils().relativize(parent_trace=my_trace,
                                                         root_dir=clientURL,
                                                         full_path=output_dir)

            form_request = kb_session.store.getBlindFormRequest(
                parent_trace=my_trace,
                relative_path=relative_path,
                posting_api=posting_api,
                namespace=namespace,
                subnamespace=subnamespace)

            response, log_txt, rep = kb_session.kb.requestForm(
                parent_trace=my_trace, form_request=form_request)
            kb_operation_succeeded = True
            manifests_description = CLI_Utils().describe_req_form_response(
                my_trace,
                form_request_response=response,
                store=kb_session.store,
                representer=rep)

            click.echo(manifests_description)
            output = "Success"
            click.echo(output)
            click.echo(timer.elapsed_time_message())

            WarningUtils().handle_warnings(root_trace, warning_list=w)

    except ApodeixiError as ex:
        error_msg = CLI_ErrorReporting(kb_session).report_a6i_error(
            parent_trace=root_trace, a6i_error=ex)
        if kb_operation_succeeded:
            error_msg                       = "KnowledgeBase operation completed, but run into a problem when preparing "\
                                                + "a description of the response:\n"\
                                                + error_msg
        # GOTCHA
        #       Use print, not click.echo or click exception because they don't correctly display styling
        #       (colors, underlines, etc.). So use vanilla Python print and then exit
        print(error_msg)
        _sys.exit()
    except Exception as ex:
        try:
            error_msg = CLI_ErrorReporting(kb_session).report_generic_error(
                parent_trace=root_trace, generic_error=ex)
            if kb_operation_succeeded:
                error_msg                   = "KnowledgeBase operation completed, but run into a problem when preparing "\
                                                + "a description of the response:\n"\
                                                + error_msg
        except Exception as ex2:
            error_msg                       = "CLI run into trouble: found error:\n\n\t" + str(ex) + "\n\n" \
                                                + "To make things worse, when trying to produce an error log file with a "\
                                                + "stack trace, run into an additional error:\n\n\t" + str(ex2)
        # GOTCHA
        #       Use print, not click.echo or click exception because they don't correctly display styling
        #       (colors, underlines, etc.). So use vanilla Python print and then exit
        print(error_msg)
        _sys.exit()
예제 #16
0
def post(kb_session, file, dry_run, environment, timestamp):
    '''
    Posts contents of an Excel file to the KnowledgeBase.
    The filename must be of the form '<some string><posting API>.xlsx' for some supported KnowledgeBase posting API.
    '''
    timer = ApodeixiTimer()
    func_trace = FunctionalTrace(parent_trace=None, path_mask=None)
    root_trace = func_trace.doing("CLI call to post",
                                  origination={'signaled_from': __file__})

    kb_operation_succeeded = False
    try:
        if environment != None:
            kb_session.store.activate(parent_trace=root_trace,
                                      environment_name=environment)
            click.echo(CLI_Utils().sandox_announcement(environment))
        elif dry_run == True:
            sandbox_name = kb_session.provisionSandbox(root_trace)
            click.echo(CLI_Utils().sandox_announcement(sandbox_name))
        '''
        else:
            raise ApodeixiError(root_trace, "Sorry, only sandbox-isolated runs are supported at this time. Aborting.")
        '''
        # Now that we have pinned down the environment (sandbox or not) in which to call the KnowledgeBase's services,
        # set that environment's tag to use for KnoweldgeBase's posting logs, if the user set it.
        if timestamp:
            kb_session.store.current_environment(root_trace).config(
                root_trace).use_timestamps = timestamp

        if len(
                _os.path.split(file)[0]
        ) == 0:  # This must be a local file in our working directory, no folder was given
            file = _os.getcwd() + "/" + file
        my_trace = root_trace.doing(
            "Invoking KnowledgeBase's postByFile service")
        response, log_txt = kb_session.kb.postByFile(
            parent_trace=my_trace,
            path_of_file_being_posted=file,
            excel_sheet="Posting Label")
        kb_operation_succeeded = True
        manifests_description = CLI_Utils().describe_post_response(
            my_trace, response, kb_session.store)

        click.echo(manifests_description)
        output = "Success"
        click.echo(output)
        click.echo(timer.elapsed_time_message())
    except ApodeixiError as ex:
        error_msg = CLI_ErrorReporting(kb_session).report_a6i_error(
            parent_trace=root_trace, a6i_error=ex)
        if kb_operation_succeeded:
            error_msg                       = "KnowledgeBase operation completed, but run into a problem when preparing "\
                                                + "a description of the response:\n"\
                                                + error_msg
        # GOTCHA
        #       Use print, not click.echo or click exception because they don't correctly display styling
        #       (colors, underlines, etc.). So use vanilla Python print and then exit
        print(error_msg)
        _sys.exit()
    except Exception as ex:
        try:
            error_msg = CLI_ErrorReporting(kb_session).report_generic_error(
                parent_trace=root_trace, generic_error=ex)
            if kb_operation_succeeded:
                error_msg                   = "KnowledgeBase operation completed, but run into a problem when preparing "\
                                                + "a description of the response:\n"\
                                                + error_msg
        except Exception as ex2:
            error_msg                       = "CLI run into trouble: found error:\n\n\t" + str(ex) + "\n\n" \
                                                + "To make things worse, when trying to produce an error log file with a "\
                                                + "stack trace, run into an additional error:\n\n\t" + str(ex2)
        # GOTCHA
        #       Use print, not click.echo or click exception because they don't correctly display styling
        #       (colors, underlines, etc.). So use vanilla Python print and then exit
        print(error_msg)
        _sys.exit()
예제 #17
0
    def test_notebook_run(self):
        root_trace = FunctionalTrace(
            parent_trace=None,
            path_mask=self._path_mask).doing("Testing Notebook execution")
        try:
            INPUT_FOLDER = self.input_data
            OUTPUT_FOLDER = self.output_data
            EXPECTED_FOLDER = self.expected_data
            TEST_SCENARIO = 'test_notebook_run'

            PathUtils().create_path_if_needed(root_trace,
                                              OUTPUT_FOLDER + "/notebooks/")
            nb_utils = NotebookUtils(
                src_folder=INPUT_FOLDER,
                src_filename=TEST_SCENARIO + "_INPUT.ipynb",
                destination_folder=OUTPUT_FOLDER + "/notebooks/",
                destination_filename=TEST_SCENARIO +
                "_executed_notebook.ipynb")

            my_trace = root_trace.doing("Running notebook")
            result_dict = nb_utils.run(my_trace)

            # Remove a path with timestamps since it changes all the time
            my_trace = root_trace.doing("Removing path with timestamps")
            hide_timestamps = lambda x: '<Timestamps removed in test output>'
            cleaned_dict = DictionaryUtils().replace_path(
                parent_trace=my_trace,
                root_dict=result_dict,
                root_dict_name='nb_utils_run_result_dict',
                path_list=['cells', '*', 'metadata', 'execution', '*'],
                replacement_lambda=hide_timestamps)
            my_trace = root_trace.doing(
                "Hiding user_folders printed as output")

            def _hide_root_folder(val):
                '''
                1) Hides root directory for paths displayed in output
                2) Converts displayed paths to Linux format, so we get same output in Windows and Linux

                @param val A string; normally the value of an entry in a dictionary
                '''
                folder_hints = [
                    'apodeixi\\util', 'apodeixi\\\\util', 'apodeixi/util'
                ]
                result = val
                for hint in folder_hints:
                    if hint in val:  # val is a path, keep only what comes after 'src/apodeixi'.
                        result = '<Root directory hidden in test output>' + hint + val.split(
                            hint)[1]
                        if _os.name == "nt":  # Display in Linux style
                            result = result.replace("\\\\", "/")
                        return result

                return result

            def _hide_version_nb(val):
                '''
                1) Hides root directory for paths displayed in output
                2) Converts displayed paths to Linux format, so we get same output in Windows and Linux
                3) Masks Python version numbers so that output does not depend on what version of Python is used to run tests

                @param val A string; normally the value of an entry in a dictionary
                '''
                # First mask Python version numbers for vals like: "    version: 3.9.7"
                VERSION_NB_REGEX = _re.compile(r'[0-9]+.[0-9]+.[0-9]+')
                result = _re.sub(VERSION_NB_REGEX, '<VERSION NB>', val)

                return result

            cleaned_dict = DictionaryUtils().replace_path(
                parent_trace=my_trace,
                root_dict=cleaned_dict,
                root_dict_name='aha_configurer_result_dict',
                path_list=['cells', '*', 'outputs', '*', 'data', 'text/plain'],
                replacement_lambda=_hide_root_folder)
            cleaned_dict = DictionaryUtils().replace_path(
                parent_trace=my_trace,
                root_dict=cleaned_dict,
                root_dict_name='aha_configurer_result_dict',
                path_list=['metadata', 'language_info', 'version'],
                replacement_lambda=_hide_version_nb)

            self._compare_to_expected_yaml(parent_trace=my_trace,
                                           output_dict=cleaned_dict,
                                           test_output_name=TEST_SCENARIO,
                                           save_output_dict=True)
        except ApodeixiError as ex:
            print(ex.trace_message())
            self.assertTrue(1 == 2)
    def test_workstream_aggregator(self):

        TEST_NAME = 'test_workstream_aggregator'
        INITIATIVE = 'S1'
        #ENVIRONMENT_NAME                = TEST_NAME + "_ENV"
        self.setScenario("aggregate_workstream_metrics")
        self.setCurrentTestName(TEST_NAME)
        self.selectTestDataLocation()

        try:
            root_trace = FunctionalTrace(parent_trace=None,
                                         path_mask=self._path_mask).doing(
                                             "Testing Workstream Aggregators")

            my_trace = self.trace_environment(root_trace,
                                              "Isolating test case")

            # The inputs for this test are Excel postings residing in the Knowledge Base itself, so only
            # partially isolate the environment for this test, since we want to retrieve such postings.
            # So the read_misses_policy will failover on posting reads only, but *should not* failover on manifest
            # reads because version checks would prevent creating manifests (with version 1) since such exist
            # in the parent environment for historical reasons.
            self.provisionIsolatedEnvironment(
                my_trace,
                read_misses_policy=KB_Environment_Config.
                FAILOVER_POSTING_READS_TO_PARENT)

            my_trace = root_trace.doing("Running WorkstreamAggregator")
            aggregator = WorkstreamAggregator(parent_trace=my_trace,
                                              initiative_UID=INITIATIVE,
                                              knowledge_base=self.stack().kb())

            result_df, errors = aggregator.aggregateMetrics(
                parent_trace=my_trace, filing_coordinates_filter=None)

            explanation_txt = "++++++++++++++++++++ Successes +++++++++++++++\n"
            if not result_df is None:
                explanation_txt += "\nresult_df.shape = " + str(
                    result_df.shape)

            explanation_txt += "\n\n======================= Errors while aggregating metrics ============= "
            error_idxs = list(errors.keys())
            error_idxs.sort()
            for idx in error_idxs:
                explanation_txt += "\n\n============= Error processinng handle #" + str(
                    idx) + "\n"
                explanation_txt += errors[idx].trace_message()

            self._compare_to_expected_txt(parent_trace=my_trace,
                                          output_txt=explanation_txt,
                                          test_output_name=TEST_NAME +
                                          "_explanations",
                                          save_output_txt=True)

            self._compare_to_expected_df(parent_trace=my_trace,
                                         output_df=result_df,
                                         test_output_name=TEST_NAME,
                                         columns_to_ignore=[],
                                         id_column=None)

        except ApodeixiError as ex:
            print(ex.trace_message())
            self.assertTrue(1 == 2)  # Ensure that test fails
예제 #19
0
    def test_compare_dataframes(self):
        root_trace = FunctionalTrace(
            parent_trace=None,
            path_mask=self._path_mask).doing("Testing DataFrame Comparison")
        try:
            INPUT_FOLDER = self.input_data
            OUTPUT_FOLDER = self.output_data
            TEST_SCENARIO = 'test_compare_dataframes'

            my_trace = root_trace.doing("Loading and comparing the dataframes")

            df1 = self.load_csv(
                my_trace,
                INPUT_FOLDER + '/' + TEST_SCENARIO + '_df1_INPUT.csv')
            df2 = self.load_csv(
                my_trace,
                INPUT_FOLDER + '/' + TEST_SCENARIO + '_df2_INPUT.csv')

            comparator = DataFrameComparator(df1=df1,
                                             df2=df2,
                                             df1_name="df1",
                                             df2_name="df2",
                                             id_column='Diario')

            check, comparison_dict = comparator.compare(my_trace)

            my_trace = root_trace.doing("Formatting comparison text")

            output_txt = ''
            for key in comparison_dict:
                output_txt += "\n\n-------------------- " + str(
                    key) + ' ----------------------\n'
                val = comparison_dict[key]
                if type(val) == dict:
                    for sub_key in val.keys():
                        output_txt += str(sub_key) + ":\n"
                        subval = val[sub_key]
                        if type(subval) == dict:
                            subval_txt = DictionaryFormatter().dict_2_nice(
                                parent_trace=my_trace,
                                a_dict=subval,
                                flatten=True)
                        else:
                            subval_txt = str(subval)
                        output_txt += "" + subval_txt + "\n"

                else:
                    output_txt += str(val)

            self._compare_to_expected_txt(parent_trace=my_trace,
                                          output_txt=output_txt,
                                          test_output_name=TEST_SCENARIO +
                                          '_comparison',
                                          save_output_txt=True)

            self.assertTrue(
                check == False
            )  # The comparison should result in the two DataFrames being different

        except ApodeixiError as ex:
            print(ex.trace_message())
            self.assertTrue(1 == 2)
    def test_milestones_referenced_big_rock_version(self):
        '''
        Tests that integrity checks exist to prevent posting a milestones manifest if it references a
        version of the big rocks that is not the latest.
        '''
        try:
            self.setScenario("foreign_key.milestones_big_rock_version")
            self.setCurrentTestName('fkey.ml_2_br')
            self.selectTestDataLocation()

            root_trace                      = FunctionalTrace(parent_trace=None, path_mask=self._path_mask) \
                                                .doing("Running " + self.currentTestName())

            PRODUCT_FILE = "products.static-data.admin.a6i.xlsx"
            SCORING_CYCLE_FILE = "scoring-cycles.static-data.admin.a6i.xlsx"
            BIG_ROCKS_v1_FILE = "opus.v1.big-rocks.journeys.a6i.xlsx"
            BIG_ROCKS_v2_FILE = "opus.v2.big-rocks.journeys.a6i.xlsx"
            MILESTONES_FILE = "opus.v1.milestone.journeys.a6i.xlsx"
            BIG_ROCKS_API = "big-rocks.journeys.a6i"
            MILESTONES_API = "milestone.journeys.a6i"
            NAMESPACE = "my-corp.production"
            SUB_NAMESPACE = "modernization"
            REL_PATH_IN_EXT_COLLABORATION = "journeys/Dec 2020/FusionOpus/Default"

            _path_of = self.fullpath_of

            MASK_COMBINED = CLI_Utils().combined_mask(root_trace,
                                                      self.a6i_config)

            # This will fool the CLI to treat our provisioned environment for this test as if it were the base environment
            self.overwrite_test_context(
                root_trace
            )  # Overwrites self.a6i_config , the store, the test_db, etc.

            # For this test, we need to switch the working directory for click
            my_trace = root_trace.doing(
                "Running with working directory in the collaboration area")
            store = self.stack().store()

            clientURL = store.base_environment(my_trace).clientURL(my_trace)
            working_area = clientURL + "/" + REL_PATH_IN_EXT_COLLABORATION
            PathUtils().create_path_if_needed(my_trace, working_area)
            _os.chdir(working_area)

            COMMANDS = [
                ['post', '--timestamp', "_CLI__1",
                 _path_of(PRODUCT_FILE)],
                [
                    'post', '--timestamp', "_CLI__2",
                    _path_of(SCORING_CYCLE_FILE)
                ],
                [
                    'post', '--timestamp', "_CLI__3",
                    _path_of(BIG_ROCKS_v1_FILE)
                ],  # v1 of big-rocks
                [
                    'get', 'form', '--timestamp', "_CLI__4", MILESTONES_API,
                    NAMESPACE, SUB_NAMESPACE
                ],  # milestones -> big-rocks v1
                [
                    'get', 'form', '--timestamp', "_CLI__5", BIG_ROCKS_API,
                    NAMESPACE, SUB_NAMESPACE
                ],
                [
                    'post', '--timestamp', "_CLI__6",
                    _path_of(BIG_ROCKS_v2_FILE)
                ],  # v2 of big-rocks
                ['get', 'assertions'],
                ['post', '--timestamp', "_CLI__7",
                 _path_of(MILESTONES_FILE)],  # Should trigger an error
            ]

            self.skeleton_test(
                parent_trace=my_trace,
                cli_command_list=COMMANDS,
                output_cleanining_lambda=MASK_COMBINED,
                when_to_check_environment=CLI_Test_Skeleton.NEVER)
        except ApodeixiError as ex:
            print(ex.trace_message())
            self.assertTrue(1 == 2)