def setUp(self):
     VirtualTerminal().print_lowlight(
         "\n----------------- setup test runner -----------------")
     self.runtime = RuntimeComposer()
     self.logger = self.runtime.logger
     self.json_file_handler = self.runtime.json_file_handler
     self.config_public_settings_fields = Constants.ConfigPublicSettingsFields
 def setUp(self):
     VirtualTerminal().print_lowlight(
         "\n----------------- setup test runner -----------------")
     self.runtime = RuntimeComposer()
     runtime_context_handler = RuntimeContextHandler(self.runtime.logger)
     ext_env_handler = ExtEnvHandler(self.runtime.json_file_handler,
                                     handler_env_file_path=os.path.join(
                                         os.path.pardir, "tests",
                                         "helpers"))
     ext_config_settings_handler = ExtConfigSettingsHandler(
         self.runtime.logger, self.runtime.json_file_handler,
         ext_env_handler.config_folder)
     core_state_handler = CoreStateHandler(ext_env_handler.config_folder,
                                           self.runtime.json_file_handler)
     ext_state_handler = ExtStateHandler(ext_env_handler.config_folder,
                                         self.runtime.utility,
                                         self.runtime.json_file_handler)
     ext_output_status_handler = ExtOutputStatusHandler(
         self.runtime.logger, self.runtime.utility,
         self.runtime.json_file_handler, ext_env_handler.status_folder)
     process_handler = ProcessHandler(self.runtime.logger,
                                      ext_output_status_handler)
     self.action_handler = ActionHandler(
         self.runtime.logger, self.runtime.utility, runtime_context_handler,
         self.runtime.json_file_handler, ext_env_handler,
         ext_config_settings_handler, core_state_handler, ext_state_handler,
         ext_output_status_handler, process_handler,
         "2020-09-02T13:40:54.8862542Z")
 def setUp(self):
     VirtualTerminal().print_lowlight(
         "\n----------------- setup test runner -----------------")
     self.runtime = RuntimeComposer()
     self.utility = self.runtime.utility
     self.json_file_handler = self.runtime.json_file_handler
     self.core_state_fields = Constants.CoreStateFields
Example #4
0
class TestUtility(unittest.TestCase):
    def setUp(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- setup test runner -----------------")
        self.runtime = RuntimeComposer()
        self.utility = self.runtime.utility

    def tearDown(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- tear down test runner -----------------")

    def mock_os_remove_to_return_exception(self, path):
        raise Exception

    def test_delete_file_success(self):
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        file_name = "test.json"
        file_path = os.path.join(test_dir, file_name)
        # create a file
        self.runtime.create_temp_file(test_dir, file_name, content=None)
        # delete file
        self.utility.delete_file(test_dir, "test.json")
        # once the file is deleted, parent directory is empty
        self.assertTrue(len(os.listdir(test_dir)) == 0)
        # Remove the directory after the test
        shutil.rmtree(test_dir)

    def test_delete_file_failure(self):
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()

        # FileNotFound
        self.assertRaises(Exception, self.utility.delete_file, test_dir,
                          "test1.json")

        # delete on a directory
        file_path = os.path.join(test_dir, "test")
        # create a directory
        os.makedirs(file_path)
        self.assertRaises(Exception, self.utility.delete_file, test_dir,
                          "test")

        # delete file
        file_name = "test.json"
        # create a file
        self.runtime.create_temp_file(test_dir, file_name, content=None)
        os_remove_backup = os.remove
        os.remove = self.mock_os_remove_to_return_exception
        self.assertRaises(Exception, self.utility.delete_file, test_dir,
                          "test.json")
        os.remove = os_remove_backup

        # Remove the directory after the test
        shutil.rmtree(test_dir)
 def setUp(self):
     VirtualTerminal().print_lowlight("\n----------------- setup test runner -----------------")
     runtime = RuntimeComposer()
     self.logger = runtime.logger
     self.json_file_handler = runtime.json_file_handler
     self.get_json_file_content_backup = self.json_file_handler.get_json_file_content
     self.json_file_handler.get_json_file_content = self.mock_get_json_file_content_to_return_none
Example #6
0
 def setUp(self):
     VirtualTerminal().print_lowlight(
         "\n----------------- setup test runner -----------------")
     runtime = RuntimeComposer()
     self.logger = runtime.logger
     self.json_file_handler = runtime.json_file_handler
     self.runtime_context_handler = RuntimeContextHandler(self.logger)
     self.core_state_fields = Constants.CoreStateFields
Example #7
0
 def setUp(self):
     VirtualTerminal().print_lowlight("\n----------------- setup test runner -----------------")
     self.runtime = RuntimeComposer()
     self.logger = self.runtime.logger
     self.telemetry_writer = self.runtime.telemetry_writer
     self.logger.telemetry_writer = self.telemetry_writer
     self.utility = self.runtime.utility
     self.json_file_handler = self.runtime.json_file_handler
     self.status_file_fields = Constants.StatusFileFields
     self.status = Constants.Status
    def setUp(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- setup test runner -----------------")
        self.temp_dir = tempfile.mkdtemp()

        self.runtime = RuntimeComposer()
        runtime_context_handler = RuntimeContextHandler(self.runtime.logger)
        self.ext_env_handler = ExtEnvHandler(
            self.runtime.json_file_handler,
            handler_env_file_path=os.path.join(os.path.pardir, "tests",
                                               "helpers"))
        self.setup_files_and_folders(self.temp_dir)

        self.ext_config_settings_handler = ExtConfigSettingsHandler(
            self.runtime.logger, self.runtime.json_file_handler,
            self.ext_env_handler.config_folder)
        core_state_handler = CoreStateHandler(
            self.ext_env_handler.config_folder, self.runtime.json_file_handler)
        ext_state_handler = ExtStateHandler(self.ext_env_handler.config_folder,
                                            self.runtime.utility,
                                            self.runtime.json_file_handler)
        ext_output_status_handler = ExtOutputStatusHandler(
            self.runtime.logger, self.runtime.utility,
            self.runtime.json_file_handler, self.ext_env_handler.status_folder)
        process_handler = ProcessHandler(self.runtime.logger,
                                         self.runtime.env_layer,
                                         ext_output_status_handler)
        self.action_handler = ActionHandler(
            self.runtime.logger, self.runtime.env_layer,
            self.runtime.telemetry_writer, self.runtime.utility,
            runtime_context_handler, self.runtime.json_file_handler,
            self.runtime.env_health_manager, self.ext_env_handler,
            self.ext_config_settings_handler, core_state_handler,
            ext_state_handler, ext_output_status_handler, process_handler,
            datetime.datetime.utcnow())

        self.backup_get_seq_no_from_env_var = self.ext_config_settings_handler.get_seq_no_from_env_var
        self.ext_config_settings_handler.get_seq_no_from_env_var = self.mock_get_seq_no_from_env_var

        self.backup_mock_os_path_realpath = os.path.realpath
        os.path.realpath = self.mock_os_path_realpath
Example #9
0
 def setUp(self):
     VirtualTerminal().print_lowlight(
         "\n----------------- setup test runner -----------------")
     runtime = RuntimeComposer()
     self.logger = runtime.logger
     self.utility = runtime.utility
     self.json_file_handler = runtime.json_file_handler
     seq_no = 1234
     dir_path = os.path.join(os.path.pardir, "tests", "helpers")
     self.ext_output_status_handler = ExtOutputStatusHandler(
         self.logger, self.utility, self.json_file_handler, dir_path)
     self.process = subprocess.Popen(["echo", "Hello World!"],
                                     shell=True,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
class TestExtEnvHandler(unittest.TestCase):
    def setUp(self):
        VirtualTerminal().print_lowlight("\n----------------- setup test runner -----------------")
        self.runtime = RuntimeComposer()
        self.json_file_handler = self.runtime.json_file_handler
        self.env_settings_fields = Constants.EnvSettingsFields

    def tearDown(self):
        VirtualTerminal().print_lowlight("\n----------------- tear down test runner -----------------")

    def test_file_read_success(self):
        ext_env_handler = ExtEnvHandler(self.json_file_handler, handler_env_file_path=os.path.join(os.path.pardir, "tests", "helpers"))
        self.assertTrue(ext_env_handler.log_folder is not None)
        self.assertEqual(ext_env_handler.log_folder, "mockLog")
        self.assertTrue(ext_env_handler.status_folder is not None)

    def test_file_read_failure(self):
        # empty file
        test_dir = tempfile.mkdtemp()
        file_name = "test_handler_env.json"
        self.runtime.create_temp_file(test_dir, file_name, content=None)
        self.assertRaises(Exception, ExtEnvHandler, self.json_file_handler, handler_env_file=file_name, handler_env_file_path=test_dir)
        shutil.rmtree(test_dir)

        # invalid file content
        json_content = [{"key1": "value"}, {"key2": "value2"}]
        test_dir = tempfile.mkdtemp()
        file_name = "test_handler_env.json"
        self.runtime.create_temp_file(test_dir, file_name, str(json_content))
        self.assertRaises(Exception, ExtEnvHandler, self.json_file_handler, handler_env_file=file_name, handler_env_file_path=test_dir)
        shutil.rmtree(test_dir)

        # invalid file content
        json_content = [{}]
        test_dir = tempfile.mkdtemp()
        file_name = "test_handler_env.json"
        self.runtime.create_temp_file(test_dir, file_name, str(json_content))
        self.assertRaises(Exception, ExtEnvHandler, self.json_file_handler, handler_env_file=file_name, handler_env_file_path=test_dir)
        shutil.rmtree(test_dir)
Example #11
0
class TestExtStateHandler(unittest.TestCase):
    def setUp(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- setup test runner -----------------")
        self.runtime = RuntimeComposer()
        self.logger = self.runtime.logger
        self.utility = self.runtime.utility
        self.json_file_handler = self.runtime.json_file_handler
        self.ext_state_fields = Constants.ExtStateFields

    def tearDown(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- tear down test runner -----------------")

    def test_create_file(self):
        test_dir = tempfile.mkdtemp()
        ext_state_handler = ExtStateHandler(test_dir, self.utility,
                                            self.json_file_handler)
        ext_state_handler.create_file(1, "Assessment",
                                      datetime.datetime.utcnow())
        self.assertTrue(
            os.path.exists(os.path.join(test_dir, Constants.EXT_STATE_FILE)))
        self.utility.delete_file(ext_state_handler.dir_path,
                                 ext_state_handler.file)
        shutil.rmtree(test_dir)

    def test_read_file(self):
        ext_state_handler = ExtStateHandler(
            os.path.join(os.path.pardir, "tests", "helpers"), self.utility,
            self.json_file_handler)
        ext_state_values = ext_state_handler.read_file()
        self.assertTrue(
            ext_state_values.__getattribute__(
                self.ext_state_fields.ext_seq_number) is not None)
        self.assertEqual(
            ext_state_values.__getattribute__(
                self.ext_state_fields.ext_seq_number), 1234)
        self.assertTrue(
            ext_state_values.__getattribute__(
                self.ext_state_fields.ext_seq_achieve_enable_by) is not None)
        self.assertTrue(
            ext_state_values.__getattribute__(
                self.ext_state_fields.ext_seq_operation) is not None)
        self.assertEqual(
            ext_state_values.__getattribute__(
                self.ext_state_fields.ext_seq_operation), "Installation")

    def test_read_file_no_content(self):
        ext_state_handler = ExtStateHandler(
            os.path.join(os.path.pardir, "tests", "helper"), self.utility,
            self.json_file_handler)
        ext_state_values = ext_state_handler.read_file()
        self.assertTrue(ext_state_values is not None)
        self.assertTrue(
            ext_state_values.__getattribute__(
                self.ext_state_fields.ext_seq_number) is None)
        self.assertTrue(
            ext_state_values.__getattribute__(
                self.ext_state_fields.ext_seq_achieve_enable_by) is None)
        self.assertTrue(
            ext_state_values.__getattribute__(
                self.ext_state_fields.ext_seq_operation) is None)

    def test_delete_file_failure(self):
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        file_name = Constants.EXT_STATE_FILE
        file_path = os.path.join(test_dir, file_name)
        # create a file
        self.runtime.create_temp_file(test_dir, file_name, content=None)
        # delete file
        ext_state_handler = ExtStateHandler('test', self.utility,
                                            self.json_file_handler)
        self.assertRaises(Exception, self.utility.delete_file,
                          ext_state_handler.dir_path, ext_state_handler.file)
        self.assertTrue(os.path.exists(file_path))
        # Remove the directory after the test
        shutil.rmtree(test_dir)

    def test_delete_file_success(self):
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        file_name = Constants.EXT_STATE_FILE
        file_path = os.path.join(test_dir, file_name)
        # create a file
        self.runtime.create_temp_file(test_dir, file_name, content=None)
        # delete file
        ext_state_handler = ExtStateHandler(test_dir, self.utility,
                                            self.json_file_handler)
        self.utility.delete_file(ext_state_handler.dir_path,
                                 ext_state_handler.file)
        self.assertFalse(os.path.exists(file_path))
        # Remove the directory after the test
        shutil.rmtree(test_dir)
 def setUp(self):
     VirtualTerminal().print_lowlight("\n----------------- setup test runner -----------------")
     self.runtime = RuntimeComposer()
     self.json_file_handler = self.runtime.json_file_handler
     self.env_settings_fields = Constants.EnvSettingsFields
Example #13
0
 def setUp(self):
     VirtualTerminal().print_lowlight(
         "\n----------------- setup test runner -----------------")
     self.runtime = RuntimeComposer()
     self.utility = self.runtime.utility
class TestExtConfigSettingsHandler(unittest.TestCase):
    def setUp(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- setup test runner -----------------")
        self.runtime = RuntimeComposer()
        self.logger = self.runtime.logger
        self.telemetry_writer = self.runtime.telemetry_writer
        self.logger.telemetry_writer = self.telemetry_writer
        self.json_file_handler = self.runtime.json_file_handler
        self.config_public_settings_fields = Constants.ConfigPublicSettingsFields

    def tearDown(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- tear down test runner -----------------")

    def mock_getenv(self, key):
        return 1234

    def test_get_seq_no_found_in_env_variable_for_enable_cmd(self):
        test_dir = tempfile.mkdtemp()
        os_getenv_backup = os.getenv
        os.getenv = self.mock_getenv

        self.runtime.create_temp_file(test_dir, "1234.settings", content=None)
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = ext_config_settings_handler.get_seq_no(is_enable_request=True)
        self.assertTrue(seq_no is not None)
        self.assertEqual(seq_no, 1234)

        os.getenv = os_getenv_backup
        shutil.rmtree(test_dir)

    def test_get_seq_no_found_in_env_variable_for_non_enable_cmd(self):
        test_dir = tempfile.mkdtemp()
        os_getenv_backup = os.getenv
        os.getenv = self.mock_getenv

        self.runtime.create_temp_file(test_dir, "1234.settings", content=None)
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = ext_config_settings_handler.get_seq_no(
            is_enable_request=False)
        self.assertTrue(seq_no is not None)
        self.assertEqual(seq_no, 1234)

        os.getenv = os_getenv_backup
        shutil.rmtree(test_dir)

    def test_get_seq_no_not_found_in_env_variable_for_non_enable_cmd(self):
        # not set in env var
        test_dir = tempfile.mkdtemp()
        self.runtime.create_temp_file(test_dir, "1234.settings", content=None)
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = ext_config_settings_handler.get_seq_no(
            is_enable_request=False)
        self.assertTrue(seq_no is None)
        shutil.rmtree(test_dir)

        # set in env var, settings file does not exist
        test_dir = tempfile.mkdtemp()
        os_getenv_backup = os.getenv
        os.getenv = self.mock_getenv
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = ext_config_settings_handler.get_seq_no(
            is_enable_request=False)
        self.assertTrue(seq_no is None)
        os.getenv = os_getenv_backup
        shutil.rmtree(test_dir)

    def test_get_seq_no_not_found_in_env_variable_for_enable_cmd(self):
        # set in env var, settings file does not exist
        test_dir = tempfile.mkdtemp()
        os_getenv_backup = os.getenv
        os.getenv = self.mock_getenv
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = ext_config_settings_handler.get_seq_no(is_enable_request=True)
        self.assertTrue(seq_no is None)
        os.getenv = os_getenv_backup
        shutil.rmtree(test_dir)

        # not set in env var, seq_no fetched from config settings file
        test_dir = tempfile.mkdtemp()
        self.runtime.create_temp_file(test_dir, "1234.settings", content=None)
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = ext_config_settings_handler.get_seq_no(is_enable_request=True)
        self.assertTrue(seq_no is not None)
        self.assertEqual(seq_no, 1234)
        shutil.rmtree(test_dir)

    def test_seq_no_from_config_folder(self):
        files = [{
            "name": '1.json',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": '2.json',
            "lastModified": '2018-07-20T12:12:14Z'
        }, {
            "name": '11.json',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": '12.settings',
            "lastModified": '2019-07-02T12:12:14Z'
        }, {
            "name": '121.settings',
            "lastModified": '2017-07-20T12:12:14Z'
        }, {
            "name": '122.settings',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": '123.json',
            "lastModified": '2019-07-20T11:12:14Z'
        }, {
            "name": '10.settings',
            "lastModified": '2019-07-20T10:12:14Z'
        }, {
            "name": '111.settings',
            "lastModified": '2019-07-20T12:10:14Z'
        }, {
            "name": 'dir1',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": '111111',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": '2.settings',
            "lastModified": '2019-07-20T12:12:12Z'
        }, {
            "name": '3a.settings',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": 'aa.settings',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": 'a3.settings',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": '22.settings.settings',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": '0.settings',
            "lastModified": '2019-07-19T12:12:14Z'
        }, {
            "name": 'abc.123.settings',
            "lastModified": '2019-07-20T12:12:14Z'
        }, {
            "name": '.settings',
            "lastModified": '2019-07-20T12:12:14Z'
        }]

        test_dir = tempfile.mkdtemp()
        for file in files:
            file_path = os.path.join(test_dir, file["name"])
            with open(file_path, 'w') as f:
                timestamp = time.mktime(
                    datetime.strptime(
                        file["lastModified"],
                        Constants.UTC_DATETIME_FORMAT).timetuple())
                os.utime(file_path, (timestamp, timestamp))
                f.close()
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = ext_config_settings_handler.get_seq_no(is_enable_request=True)
        self.assertEqual(122, seq_no)
        shutil.rmtree(test_dir)

    def test_seq_no_from_empty_config_folder(self):
        test_dir = tempfile.mkdtemp()
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = ext_config_settings_handler.get_seq_no(is_enable_request=True)
        self.assertEqual(None, seq_no)
        shutil.rmtree(test_dir)

    def test_are_config_settings_valid(self):
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, "mockConfig")

        runtime_settings_key = Constants.RUNTIME_SETTINGS
        handler_settings_key = Constants.HANDLER_SETTINGS
        public_settings_key = Constants.PUBLIC_SETTINGS

        config_settings_json = None
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))

        config_settings_json = []
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))

        config_settings_json = {}
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))

        # runtimeSettings not in file
        config_settings_json = {'key': 'test'}
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        # runtimeSettings not of type list
        config_settings_json = {runtime_settings_key: "test"}
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        config_settings_json = {runtime_settings_key: {}}
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        # runtimeSettings is None or empty
        config_settings_json = {runtime_settings_key: None}
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        # runtimeSettings is on len 0
        config_settings_json = {runtime_settings_key: []}
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))

        # handlerSettings not in runtimeSettings
        config_settings_json = {runtime_settings_key: ["test"]}
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        # handlerSettings not of type dict
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: []
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: "test"
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: ["test"]
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        # handlerSettings is None or empty
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: None
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: {}
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))

        # publicSettings not in handlerSettings
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: {
                    "testKey": "testVal"
                }
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        # handlerSettings not of type dict
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: {
                    "testKey": "testVal",
                    public_settings_key: []
                }
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: {
                    "testKey": "testVal",
                    public_settings_key: "test"
                }
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: {
                    "testKey": "testVal",
                    public_settings_key: ["test"]
                }
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        # publicSettings is None or empty
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: {
                    "testKey": "testVal",
                    public_settings_key: None
                }
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: {
                    "testKey": "testVal",
                    public_settings_key: {}
                }
            }]
        }
        self.assertFalse(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))

        # accepted config settings
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: {
                    "testKey": "testVal",
                    public_settings_key: {
                        self.config_public_settings_fields.operation:
                        "test",
                        self.config_public_settings_fields.activity_id:
                        "12345-2312-1234-23245-32112",
                        self.config_public_settings_fields.start_time:
                        "2019-07-20T12:12:14Z",
                        self.config_public_settings_fields.maximum_duration:
                        "20m",
                        self.config_public_settings_fields.reboot_setting:
                        "IfRequired",
                        self.config_public_settings_fields.include_classifications:
                        ["Critical", "Security"],
                        self.config_public_settings_fields.include_patches:
                        ["*", "test*", "*ern*=1.2*", "kern*=1.23.45"],
                        self.config_public_settings_fields.exclude_patches:
                        ["*", "test", "*test"],
                        self.config_public_settings_fields.internal_settings:
                        "<serialized-json>",
                        self.config_public_settings_fields.maintenance_run_id:
                        "2019-07-20T12:12:14Z",
                        self.config_public_settings_fields.patch_mode:
                        "AutomaticByPlatform",
                        self.config_public_settings_fields.assessment_mode:
                        "AutomaticByPlatform",
                        self.config_public_settings_fields.maximum_assessment_interval:
                        "PT3H",
                    }
                }
            }]
        }
        self.assertTrue(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))

        # Testing with only required fields
        config_settings_json = {
            runtime_settings_key: [{
                handler_settings_key: {
                    public_settings_key: {
                        self.config_public_settings_fields.operation:
                        "test",
                        self.config_public_settings_fields.activity_id:
                        "12345-2312-1234-23245-32112",
                        self.config_public_settings_fields.start_time:
                        "2019-07-20T12:12:14Z"
                    }
                }
            }]
        }
        self.assertTrue(
            ext_config_settings_handler.are_config_settings_valid(
                config_settings_json))

    def test_read_file_success(self):
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler,
            os.path.join(os.path.pardir, "tests", "helpers"))
        seq_no = "1234"
        config_values = ext_config_settings_handler.read_file(seq_no)
        self.assertEqual(
            config_values.__getattribute__(
                self.config_public_settings_fields.operation), "Installation")
        self.assertEqual(
            config_values.__getattribute__(
                self.config_public_settings_fields.reboot_setting),
            "IfRequired")

    def test_read_file_failures(self):
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler,
            os.path.join(os.path.pardir, "tests", "helpers"))
        # Seq_no invalid, none, -1, empty
        seq_no = None
        self.assertRaises(Exception, ext_config_settings_handler.read_file,
                          seq_no)
        seq_no = -1
        self.assertRaises(Exception, ext_config_settings_handler.read_file,
                          seq_no)
        seq_no = ""
        self.assertRaises(Exception, ext_config_settings_handler.read_file,
                          seq_no)

        # FileNotFound
        seq_no = "12345"
        self.assertRaises(Exception, ext_config_settings_handler.read_file,
                          seq_no)

        # empty file
        test_dir = tempfile.mkdtemp()
        file_name = "123.settings"
        self.runtime.create_temp_file(test_dir, file_name, content=None)
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = "123"
        self.assertRaises(Exception, ext_config_settings_handler.read_file,
                          seq_no)
        shutil.rmtree(test_dir)

        # empty valid file
        test_dir = tempfile.mkdtemp()
        file_name = "1237.settings"
        self.runtime.create_temp_file(test_dir, file_name, content="{}")
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        seq_no = "1237"
        self.assertRaises(Exception, ext_config_settings_handler.read_file,
                          seq_no)
        shutil.rmtree(test_dir)

        # file not valid
        test_dir = tempfile.mkdtemp()
        seq_no = "1237"
        file_name = seq_no + ".settings"
        self.runtime.create_temp_file(test_dir,
                                      file_name,
                                      content='{"runtimeSettings": []}')
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler, test_dir)
        self.assertRaises(Exception, ext_config_settings_handler.read_file,
                          seq_no)
        shutil.rmtree(test_dir)

    def test_read_all_config_settings_from_file(self):
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.logger, self.json_file_handler,
            os.path.join(os.path.pardir, "tests", "helpers"))
        seq_no = ext_config_settings_handler.get_seq_no(is_enable_request=True)
        config_settings = ext_config_settings_handler.read_file(seq_no)

        # verify operation is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.operation), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.operation), "Installation")

        # verify activityId is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.activity_id), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.activity_id),
            "12345-2312-1234-23245-32112")

        # verify startTime is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.start_time), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.start_time),
            "2021-08-08T12:34:56Z")

        # verify maximumDuration is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.maximum_duration), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.maximum_duration), "PT2H")

        # verify rebootSetting is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.reboot_setting), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.reboot_setting),
            "IfRequired")

        # verify classificationsToInclude is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.include_classifications),
            None)
        self.assertTrue(
            "Critical" in config_settings.__getattribute__(
                self.config_public_settings_fields.include_classifications)
            and "Security" in config_settings.__getattribute__(
                self.config_public_settings_fields.include_classifications))

        # verify patchesToInclude is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.include_patches), None)
        self.assertTrue(
            "*ern*=1.2*" in config_settings.__getattribute__(
                self.config_public_settings_fields.include_patches)
            and "kern*=1.23.45" in config_settings.__getattribute__(
                self.config_public_settings_fields.include_patches))

        # verify patchesToExclude is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.exclude_patches), None)
        self.assertTrue("test" in config_settings.__getattribute__(
            self.config_public_settings_fields.exclude_patches))

        # verify internalSettings is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.internal_settings), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.internal_settings), "test")

        # verify patchMode is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.patch_mode), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.patch_mode),
            "AutomaticByPlatform")

        # verify maintenanceRunId is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.maintenance_run_id), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.maintenance_run_id),
            "2019-07-20T12:12:14Z")

        # verify healthStoreId is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.health_store_id), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.health_store_id),
            "2021-09-15T12:12:14Z")

        # verify assessmentMode is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.assessment_mode), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.assessment_mode),
            "AutomaticByPlatform")

        # verify maximumAssessmentInterval is read successfully
        self.assertNotEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.maximum_assessment_interval
            ), None)
        self.assertEqual(
            config_settings.__getattribute__(
                self.config_public_settings_fields.maximum_assessment_interval
            ), "PT3H")
Example #15
0
 def setUp(self):
     VirtualTerminal().print_lowlight("\n----------------- setup test runner -----------------")
     runtime = RuntimeComposer()
     self.json_file_handler = runtime.json_file_handler
class TestActionHandler(unittest.TestCase):
    def setUp(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- setup test runner -----------------")
        self.temp_dir = tempfile.mkdtemp()

        self.runtime = RuntimeComposer()
        runtime_context_handler = RuntimeContextHandler(self.runtime.logger)
        self.ext_env_handler = ExtEnvHandler(
            self.runtime.json_file_handler,
            handler_env_file_path=os.path.join(os.path.pardir, "tests",
                                               "helpers"))
        self.setup_files_and_folders(self.temp_dir)

        self.ext_config_settings_handler = ExtConfigSettingsHandler(
            self.runtime.logger, self.runtime.json_file_handler,
            self.ext_env_handler.config_folder)
        core_state_handler = CoreStateHandler(
            self.ext_env_handler.config_folder, self.runtime.json_file_handler)
        ext_state_handler = ExtStateHandler(self.ext_env_handler.config_folder,
                                            self.runtime.utility,
                                            self.runtime.json_file_handler)
        ext_output_status_handler = ExtOutputStatusHandler(
            self.runtime.logger, self.runtime.utility,
            self.runtime.json_file_handler, self.ext_env_handler.status_folder)
        process_handler = ProcessHandler(self.runtime.logger,
                                         self.runtime.env_layer,
                                         ext_output_status_handler)
        self.action_handler = ActionHandler(
            self.runtime.logger, self.runtime.env_layer,
            self.runtime.telemetry_writer, self.runtime.utility,
            runtime_context_handler, self.runtime.json_file_handler,
            self.runtime.env_health_manager, self.ext_env_handler,
            self.ext_config_settings_handler, core_state_handler,
            ext_state_handler, ext_output_status_handler, process_handler,
            datetime.datetime.utcnow())

        self.backup_get_seq_no_from_env_var = self.ext_config_settings_handler.get_seq_no_from_env_var
        self.ext_config_settings_handler.get_seq_no_from_env_var = self.mock_get_seq_no_from_env_var

        self.backup_mock_os_path_realpath = os.path.realpath
        os.path.realpath = self.mock_os_path_realpath

    def tearDown(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- tear down test runner -----------------")
        self.ext_config_settings_handler.get_seq_no_from_env_var = self.backup_get_seq_no_from_env_var
        os.path.realpath = self.backup_mock_os_path_realpath
        # delete tempdir
        shutil.rmtree(self.temp_dir)

    def setup_files_and_folders(self, temp_dir):
        config_folder = self.ext_env_handler.config_folder
        status_folder = self.ext_env_handler.status_folder
        log_folder = self.ext_env_handler.log_folder
        events_folder = self.ext_env_handler.events_folder

        # creating the required folder (e.g: config folder, log folder, status folder) under the temp directory
        config_folder_complete_path = os.path.join(temp_dir, config_folder)
        status_folder_complete_path = os.path.join(temp_dir, status_folder)
        log_folder_complete_path = os.path.join(temp_dir, log_folder)
        events_folder_complete_path = os.path.join(temp_dir, log_folder,
                                                   events_folder)

        os.mkdir(config_folder_complete_path)
        os.mkdir(status_folder_complete_path)
        os.mkdir(log_folder_complete_path)
        os.mkdir(events_folder_complete_path)

        # copying a sample version of the <seqno>.settings file from the helpers folder to the temp directory
        shutil.copy(os.path.join("helpers", "1234.settings"),
                    config_folder_complete_path)
        config_file_path = os.path.join(config_folder_complete_path,
                                        '1234.settings')

        self.ext_env_handler.config_folder = config_folder_complete_path
        self.ext_env_handler.status_folder = status_folder_complete_path
        self.ext_env_handler.log_folder = log_folder_complete_path
        self.ext_env_handler.events_folder = events_folder_complete_path

    def mock_get_all_versions(self, extension_pardir):
        return [
            extension_pardir +
            '/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.3',
            extension_pardir +
            '/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5',
            extension_pardir +
            '/Microsoft.CPlat.Core.LinuxPatchExtension-1.1.9'
        ]

    def mock_get_all_versions_exception(self, extension_pardir):
        raise Exception

    def mock_get_seq_no_from_env_var(self, is_enable_request=False):
        return 1234

    def mock_os_path_realpath(self, file):
        return self.ext_env_handler.config_folder

    @staticmethod
    def create_latest_extension_dir(version, test_dir):
        latest_extension_version = version
        os.mkdir(os.path.join(test_dir, latest_extension_version))
        new_version_config_folder = os.path.join(test_dir,
                                                 latest_extension_version,
                                                 'config')
        os.mkdir(new_version_config_folder)
        return new_version_config_folder

    def create_previous_extension_version(self, version, test_dir):
        os.mkdir(os.path.join(test_dir, version))
        previous_version_config_folder = os.path.join(test_dir, version,
                                                      'config')
        os.mkdir(previous_version_config_folder)
        self.runtime.create_temp_file(previous_version_config_folder,
                                      Constants.CORE_STATE_FILE,
                                      content='[test]')
        self.runtime.create_temp_file(previous_version_config_folder,
                                      Constants.EXT_STATE_FILE,
                                      content='test')
        self.runtime.create_temp_file(previous_version_config_folder,
                                      'backup.bak',
                                      content='{"testkey": "testVal"}')
        self.runtime.create_temp_file(previous_version_config_folder,
                                      'test.txt',
                                      content='{"testkey": "testVal"}')
        return previous_version_config_folder

    def test_update_command_success(self):
        events_folder_path_backup = self.action_handler.ext_env_handler.events_folder

        # testing with versions 1.2.5, 1.2.3 and 1.1.9
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        # create extension dir for the latest and other extension versions, to be used in the test
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5'
        new_version_config_folder = self.create_latest_extension_dir(
            latest_extension_version, test_dir)
        previous_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.2.3'
        previous_version_config_folder = self.create_previous_extension_version(
            previous_extension_version, test_dir)
        other_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.1.9'
        other_version_config_folder = self.create_previous_extension_version(
            other_extension_version, test_dir)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.action_handler.ext_env_handler.events_folder = test_dir
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.Okay)
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.CORE_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.EXT_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder, 'backup.bak')))
        self.assertFalse(
            os.path.exists(os.path.join(new_version_config_folder,
                                        'test.txt')))
        self.action_handler.ext_env_handler.events_folder = events_folder_path_backup
        self.runtime.telemetry_writer.events_folder_path = None
        # Remove the directory after the test
        shutil.rmtree(test_dir)

        # testing with versions 1.6.99 and 1.6.100
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        # create extension dir for the latest and other extension versions, to be used in the test
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100'
        new_version_config_folder = self.create_latest_extension_dir(
            latest_extension_version, test_dir)
        previous_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.6.99'
        previous_version_config_folder = self.create_previous_extension_version(
            previous_extension_version, test_dir)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.action_handler.ext_env_handler.events_folder = test_dir
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.Okay)
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.CORE_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.EXT_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder, 'backup.bak')))
        self.assertFalse(
            os.path.exists(os.path.join(new_version_config_folder,
                                        'test.txt')))
        self.action_handler.ext_env_handler.events_folder = events_folder_path_backup
        self.runtime.telemetry_writer.events_folder_path = None
        # Remove the directory after the test
        shutil.rmtree(test_dir)

        # testing with versions 1.4.897 and 1.5.23
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        # create extension dir for the latest and other extension versions, to be used in the test
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.5.23'
        new_version_config_folder = self.create_latest_extension_dir(
            latest_extension_version, test_dir)
        previous_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.4.897'
        previous_version_config_folder = self.create_previous_extension_version(
            previous_extension_version, test_dir)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.action_handler.ext_env_handler.events_folder = test_dir
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.Okay)
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.CORE_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.EXT_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder, 'backup.bak')))
        self.assertFalse(
            os.path.exists(os.path.join(new_version_config_folder,
                                        'test.txt')))
        self.action_handler.ext_env_handler.events_folder = events_folder_path_backup
        self.runtime.telemetry_writer.events_folder_path = None
        # Remove the directory after the test
        shutil.rmtree(test_dir)

        # testing with versions 1.0.0 and 2.0.00
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        # create extension dir for the latest and other extension versions, to be used in the test
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-2.0.00'
        new_version_config_folder = self.create_latest_extension_dir(
            latest_extension_version, test_dir)
        previous_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.0.0'
        previous_version_config_folder = self.create_previous_extension_version(
            previous_extension_version, test_dir)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.action_handler.ext_env_handler.events_folder = test_dir
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.Okay)
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.CORE_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.EXT_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder, 'backup.bak')))
        self.assertFalse(
            os.path.exists(os.path.join(new_version_config_folder,
                                        'test.txt')))
        self.action_handler.ext_env_handler.events_folder = events_folder_path_backup
        self.runtime.telemetry_writer.events_folder_path = None
        # Remove the directory after the test
        shutil.rmtree(test_dir)

    def test_update_command_fail(self):
        events_folder_path_backup = self.action_handler.ext_env_handler.events_folder
        # other versions not found
        test_dir = tempfile.mkdtemp()
        self.action_handler.ext_env_handler.events_folder = test_dir
        self.action_handler.ext_env_handler.config_folder = '/test/config'
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.HandlerFailed)
        self.action_handler.ext_env_handler.events_folder = events_folder_path_backup
        self.runtime.telemetry_writer.events_folder_path = None
        # Remove the directory after the test
        shutil.rmtree(test_dir)

        # path to previous version artifacts not found
        # Create a temporary directory and dir for the latest version
        test_dir = tempfile.mkdtemp()
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5'
        os.mkdir(os.path.join(test_dir, latest_extension_version))
        new_version_config_folder = os.path.join(test_dir,
                                                 latest_extension_version,
                                                 'config')
        os.mkdir(new_version_config_folder)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.action_handler.get_all_versions = self.mock_get_all_versions
        self.action_handler.ext_env_handler.events_folder = test_dir
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.HandlerFailed)
        self.action_handler.ext_env_handler.events_folder = events_folder_path_backup
        self.runtime.telemetry_writer.events_folder_path = None
        # Remove the directory after the test
        shutil.rmtree(test_dir)

        # exception path
        test_dir = tempfile.mkdtemp()
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5'
        os.mkdir(os.path.join(test_dir, latest_extension_version))
        new_version_config_folder = os.path.join(test_dir,
                                                 latest_extension_version,
                                                 'config')
        os.mkdir(new_version_config_folder)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.action_handler.get_all_versions = self.mock_get_all_versions_exception
        self.action_handler.ext_env_handler.events_folder = test_dir
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.HandlerFailed)
        self.action_handler.ext_env_handler.events_folder = events_folder_path_backup
        self.runtime.telemetry_writer.events_folder_path = None
        # Remove the directory after the test
        shutil.rmtree(test_dir)

    def test_telemetry_available_env_var_not_exists(self):
        # agent env var is not set so telemetry is not supported
        backup_os_getenv = os.getenv
        backup_telemetry_writer = self.runtime.telemetry_writer

        def mock_os_getenv(name, value=None):
            return None

        # Re-init TelemetryWriter since the env var for compatibility is only checked on init
        os.getenv = mock_os_getenv
        self.runtime.telemetry_writer = TelemetryWriter(
            self.runtime.logger, self.runtime.env_layer)
        self.action_handler.telemetry_writer = self.runtime.telemetry_writer

        self.assertTrue(
            self.action_handler.uninstall() == Constants.ExitCode.Okay)

        file_read = open(self.runtime.logger.file_logger.log_file_path, "r")
        self.assertTrue(file_read is not None)
        file_contents = file_read.read()
        self.assertTrue(
            Constants.TELEMETRY_AT_AGENT_COMPATIBLE_MSG in file_contents)
        self.assertTrue(
            Constants.AgentEnvVarStatusCode.
            FAILED_TO_GET_AGENT_SUPPORTED_FEATURES in file_contents)
        file_read.close()

        with self.assertRaises(SystemExit) as sys_exit:
            self.action_handler.enable()

        os.getenv = backup_os_getenv
        self.runtime.telemetry_writer = backup_telemetry_writer
        self.action_handler.telemetry_writer = backup_telemetry_writer

    def test_telemetry_available_env_var_key_not_exists(self):
        # agent env var is not set so telemetry is not supported
        backup_os_getenv = os.getenv
        backup_telemetry_writer = self.runtime.telemetry_writer

        def mock_os_getenv(name, value=None):
            return '[]'

        # Re-init TelemetryWriter since the env var for compatibility is only checked on init
        os.getenv = mock_os_getenv
        self.runtime.telemetry_writer = TelemetryWriter(
            self.runtime.logger, self.runtime.env_layer)
        self.action_handler.telemetry_writer = self.runtime.telemetry_writer

        self.assertTrue(
            self.action_handler.uninstall() == Constants.ExitCode.Okay)

        file_read = open(self.runtime.logger.file_logger.log_file_path, "r")
        self.assertTrue(file_read is not None)
        file_contents = file_read.read()
        self.assertTrue(
            Constants.TELEMETRY_AT_AGENT_COMPATIBLE_MSG in file_contents)
        self.assertTrue(Constants.AgentEnvVarStatusCode.
                        FAILED_TO_GET_TELEMETRY_KEY in file_contents)
        file_read.close()

        with self.assertRaises(SystemExit) as sys_exit:
            self.action_handler.enable()

        os.getenv = backup_os_getenv
        self.runtime.telemetry_writer = backup_telemetry_writer
        self.action_handler.telemetry_writer = backup_telemetry_writer

    def test_telemetry_available_but_events_folder_not_exists(self):
        # handler actions will continue to execute after logging telemetry not supported message
        events_folder_path_backup = self.action_handler.ext_env_handler.events_folder
        shutil.rmtree(events_folder_path_backup)

        # events folder is set within HandlerEnvironment but the directory path is invalid, so Telemetry is setup but events folder wasn't created by agent. In this case, we create the events folder
        self.assertTrue(
            self.action_handler.uninstall() == Constants.ExitCode.Okay)
        with self.assertRaises(SystemExit) as sys_exit:
            self.action_handler.enable()

        file_read = open(self.runtime.logger.file_logger.log_file_path, "r")
        self.assertTrue(file_read is not None)
        self.assertTrue(Constants.TELEMETRY_AT_AGENT_NOT_COMPATIBLE_ERROR_MSG
                        not in file_read.read())
        file_read.close()

        self.action_handler.ext_env_handler.events_folder = events_folder_path_backup

    def test_timestamp_for_all_actions(self):
        """ All handler actions, specially all non-enable actions should have the same timestamp in OperationId within telemetry event """
        self.action_handler.uninstall()
        self.action_handler.reset()

        event_files = glob.glob(
            self.action_handler.telemetry_writer.events_folder_path +
            '/*.json')
        for event_file in event_files:
            with open(
                    os.path.join(
                        self.action_handler.telemetry_writer.
                        events_folder_path, event_file), 'r+') as f:
                events = json.load(f)
                self.assertEqual(
                    events[0]["OperationId"], self.action_handler.
                    operation_id_substitute_for_all_actions_in_telemetry)

    def test_write_basic_status_uninstall(self):
        """ Check that a basic status file is NOT written during uninstall handler command setup """
        self.action_handler.uninstall()
        self.assertFalse(
            os.path.exists(
                os.path.join(self.ext_env_handler.status_folder,
                             '1234.status')))

    def test_write_basic_status_install(self):
        """ Check that a basic status file is NOT written during install handler command setup """
        self.action_handler.install()
        self.assertFalse(
            os.path.exists(
                os.path.join(self.ext_env_handler.status_folder,
                             '1234.status')))

    def test_write_basic_status_update(self):
        """ Check that a basic status file is NOT written during update handler command setup """
        self.action_handler.update()
        self.assertFalse(
            os.path.exists(
                os.path.join(self.ext_env_handler.status_folder,
                             '1234.status')))

    def test_write_basic_status_disable(self):
        """ Check that a basic status file is NOT written during disable handler command setup """
        self.action_handler.disable()
        self.assertFalse(
            os.path.exists(
                os.path.join(self.ext_env_handler.status_folder,
                             '1234.status')))

    def test_write_basic_status_reset(self):
        """ Check that a basic status file is NOT written during reset handler command setup """
        self.action_handler.reset()
        self.assertFalse(
            os.path.exists(
                os.path.join(self.ext_env_handler.status_folder,
                             '1234.status')))

    def test_write_basic_status_enable(self):
        """ Check that a basic status file is written during enable handler command setup """
        with self.assertRaises(SystemExit) as sys_exit:
            self.action_handler.enable()
        self.assertTrue(
            os.path.exists(
                os.path.join(self.ext_env_handler.status_folder,
                             '1234.status')))
class TestCoreStateHandler(unittest.TestCase):
    def setUp(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- setup test runner -----------------")
        self.runtime = RuntimeComposer()
        self.utility = self.runtime.utility
        self.json_file_handler = self.runtime.json_file_handler
        self.core_state_fields = Constants.CoreStateFields

    def tearDown(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- tear down test runner -----------------")

    def test_file_exists(self):
        core_state_handler = CoreStateHandler(
            os.path.join(os.path.pardir, "tests", "helpers"),
            self.json_file_handler)
        self.assertTrue(core_state_handler.read_file() is not None)

    def test_file_does_not_exists(self):
        core_state_handler = CoreStateHandler(
            os.path.join(os.path.pardir, "tests", "helper"),
            self.json_file_handler)
        core_state_json = core_state_handler.read_file()
        self.assertTrue(core_state_handler.read_file() is None)
        self.assertFalse(
            hasattr(core_state_json, self.core_state_fields.number))
        self.assertFalse(
            hasattr(core_state_json, self.core_state_fields.last_heartbeat))

    def test_file_empty(self):
        test_dir = tempfile.mkdtemp()
        file_name = Constants.CORE_STATE_FILE

        # test on empty file
        self.runtime.create_temp_file(test_dir, file_name, content=None)
        core_state_handler = CoreStateHandler(os.path.join(test_dir),
                                              self.json_file_handler)
        core_state_json = core_state_handler.read_file()
        self.assertTrue(core_state_json is None)
        self.assertFalse(
            hasattr(core_state_json, self.core_state_fields.number))

        # test on file with empty JSON
        self.runtime.create_temp_file(test_dir, file_name, "{}")
        core_state_json = core_state_handler.read_file()
        self.assertTrue(hasattr(core_state_json,
                                self.core_state_fields.number))
        self.assertTrue(hasattr(core_state_json,
                                self.core_state_fields.action))
        self.assertTrue(core_state_json.number is None)
        self.assertTrue(core_state_json.action is None)

        # Remove the directory after the test
        shutil.rmtree(test_dir)

    def test_key_not_in_file(self):
        parent_key = self.core_state_fields.parent_key
        core_state_json = {parent_key: {"test_no": 1}}
        test_dir = tempfile.mkdtemp()
        file_name = Constants.CORE_STATE_FILE
        self.runtime.create_temp_file(test_dir, file_name, "{}")
        core_state_handler = CoreStateHandler(os.path.join(test_dir),
                                              self.json_file_handler)
        core_state_handler.read_file()
        seq_no = self.core_state_fields.number
        self.assertTrue(
            core_state_handler.json_file_handler.get_json_config_value_safely(
                core_state_json, seq_no, parent_key, False) is None)
        # Remove the directory after the test
        shutil.rmtree(test_dir)

    def test_success_file_read(self):
        core_state_handler = CoreStateHandler(
            os.path.join(os.path.pardir, "tests", "helpers"),
            self.json_file_handler)
        core_state_json = core_state_handler.read_file()
        self.assertTrue(core_state_json.number is not None)
        self.assertTrue(core_state_json.completed is not None)
        self.assertEqual(core_state_json.action, "Assessment")
        self.assertEqual(core_state_json.number, 1234)

    def test_delete_file_failure(self):
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        file_name = Constants.EXT_STATE_FILE
        file_path = os.path.join(test_dir, file_name)
        # create a file
        self.runtime.create_temp_file(test_dir, file_name, content=None)
        # delete file
        core_state_handler = CoreStateHandler("test", self.json_file_handler)
        self.assertRaises(Exception, self.utility.delete_file,
                          core_state_handler.dir_path, core_state_handler.file)
        self.assertTrue(os.path.exists(file_path))
        # Remove the directory after the test
        shutil.rmtree(test_dir)

    def test_delete_file_success(self):
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        file_name = Constants.CORE_STATE_FILE
        file_path = os.path.join(test_dir, file_name)
        # create a file
        self.runtime.create_temp_file(test_dir, file_name, content=None)
        # delete file
        core_state_handler = CoreStateHandler(test_dir, self.json_file_handler)
        self.utility.delete_file(core_state_handler.dir_path,
                                 core_state_handler.file)
        self.assertFalse(os.path.exists(file_path))
        # Remove the directory after the test
        shutil.rmtree(test_dir)
class TestActionHandler(unittest.TestCase):
    def setUp(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- setup test runner -----------------")
        self.runtime = RuntimeComposer()
        runtime_context_handler = RuntimeContextHandler(self.runtime.logger)
        ext_env_handler = ExtEnvHandler(self.runtime.json_file_handler,
                                        handler_env_file_path=os.path.join(
                                            os.path.pardir, "tests",
                                            "helpers"))
        ext_config_settings_handler = ExtConfigSettingsHandler(
            self.runtime.logger, self.runtime.json_file_handler,
            ext_env_handler.config_folder)
        core_state_handler = CoreStateHandler(ext_env_handler.config_folder,
                                              self.runtime.json_file_handler)
        ext_state_handler = ExtStateHandler(ext_env_handler.config_folder,
                                            self.runtime.utility,
                                            self.runtime.json_file_handler)
        ext_output_status_handler = ExtOutputStatusHandler(
            self.runtime.logger, self.runtime.utility,
            self.runtime.json_file_handler, ext_env_handler.status_folder)
        process_handler = ProcessHandler(self.runtime.logger,
                                         ext_output_status_handler)
        self.action_handler = ActionHandler(
            self.runtime.logger, self.runtime.utility, runtime_context_handler,
            self.runtime.json_file_handler, ext_env_handler,
            ext_config_settings_handler, core_state_handler, ext_state_handler,
            ext_output_status_handler, process_handler,
            "2020-09-02T13:40:54.8862542Z")

    def tearDown(self):
        VirtualTerminal().print_lowlight(
            "\n----------------- tear down test runner -----------------")

    def mock_get_all_versions(self, extension_pardir):
        return [
            extension_pardir +
            '/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.3',
            extension_pardir +
            '/Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5',
            extension_pardir +
            '/Microsoft.CPlat.Core.LinuxPatchExtension-1.1.9'
        ]

    def mock_get_all_versions_exception(self, extension_pardir):
        raise Exception

    @staticmethod
    def create_latest_extension_dir(version, test_dir):
        latest_extension_version = version
        os.mkdir(os.path.join(test_dir, latest_extension_version))
        new_version_config_folder = os.path.join(test_dir,
                                                 latest_extension_version,
                                                 'config')
        os.mkdir(new_version_config_folder)
        return new_version_config_folder

    def create_previous_extension_version(self, version, test_dir):
        os.mkdir(os.path.join(test_dir, version))
        previous_version_config_folder = os.path.join(test_dir, version,
                                                      'config')
        os.mkdir(previous_version_config_folder)
        self.runtime.create_temp_file(previous_version_config_folder,
                                      Constants.CORE_STATE_FILE,
                                      content='[test]')
        self.runtime.create_temp_file(previous_version_config_folder,
                                      Constants.EXT_STATE_FILE,
                                      content='test')
        self.runtime.create_temp_file(previous_version_config_folder,
                                      'backup.bak',
                                      content='{"testkey": "testVal"}')
        self.runtime.create_temp_file(previous_version_config_folder,
                                      'test.txt',
                                      content='{"testkey": "testVal"}')
        return previous_version_config_folder

    def test_update_command_success(self):
        # testing with versions 1.2.5, 1.2.3 and 1.1.9
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        # create extension dir for the latest and other extension versions, to be used in the test
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5'
        new_version_config_folder = self.create_latest_extension_dir(
            latest_extension_version, test_dir)
        previous_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.2.3'
        previous_version_config_folder = self.create_previous_extension_version(
            previous_extension_version, test_dir)
        other_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.1.9'
        other_version_config_folder = self.create_previous_extension_version(
            other_extension_version, test_dir)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.Okay)
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.CORE_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.EXT_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder, 'backup.bak')))
        self.assertFalse(
            os.path.exists(os.path.join(new_version_config_folder,
                                        'test.txt')))
        # Remove the directory after the test
        shutil.rmtree(test_dir)

        # testing with versions 1.6.99 and 1.6.100
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        # create extension dir for the latest and other extension versions, to be used in the test
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.6.100'
        new_version_config_folder = self.create_latest_extension_dir(
            latest_extension_version, test_dir)
        previous_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.6.99'
        previous_version_config_folder = self.create_previous_extension_version(
            previous_extension_version, test_dir)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.Okay)
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.CORE_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.EXT_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder, 'backup.bak')))
        self.assertFalse(
            os.path.exists(os.path.join(new_version_config_folder,
                                        'test.txt')))
        # Remove the directory after the test
        shutil.rmtree(test_dir)

        # testing with versions 1.4.897 and 1.5.23
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        # create extension dir for the latest and other extension versions, to be used in the test
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.5.23'
        new_version_config_folder = self.create_latest_extension_dir(
            latest_extension_version, test_dir)
        previous_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.4.897'
        previous_version_config_folder = self.create_previous_extension_version(
            previous_extension_version, test_dir)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.Okay)
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.CORE_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.EXT_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder, 'backup.bak')))
        self.assertFalse(
            os.path.exists(os.path.join(new_version_config_folder,
                                        'test.txt')))
        # Remove the directory after the test
        shutil.rmtree(test_dir)

        # testing with versions 1.0.0 and 2.0.00
        # Create a temporary directory
        test_dir = tempfile.mkdtemp()
        # create extension dir for the latest and other extension versions, to be used in the test
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-2.0.00'
        new_version_config_folder = self.create_latest_extension_dir(
            latest_extension_version, test_dir)
        previous_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.0.0'
        previous_version_config_folder = self.create_previous_extension_version(
            previous_extension_version, test_dir)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.Okay)
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.CORE_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder,
                             Constants.EXT_STATE_FILE)))
        self.assertTrue(
            os.path.exists(
                os.path.join(new_version_config_folder, 'backup.bak')))
        self.assertFalse(
            os.path.exists(os.path.join(new_version_config_folder,
                                        'test.txt')))
        # Remove the directory after the test
        shutil.rmtree(test_dir)

    def test_update_command_fail(self):
        # other versions not found
        self.action_handler.ext_env_handler.config_folder = '/test/config'
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.HandlerFailed)

        # path to previous version artifacts not found
        # Create a temporary directory and dir for the latest version
        test_dir = tempfile.mkdtemp()
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5'
        os.mkdir(os.path.join(test_dir, latest_extension_version))
        new_version_config_folder = os.path.join(test_dir,
                                                 latest_extension_version,
                                                 'config')
        os.mkdir(new_version_config_folder)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.action_handler.get_all_versions = self.mock_get_all_versions
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.HandlerFailed)
        # Remove the directory after the test
        shutil.rmtree(test_dir)

        # exception path
        test_dir = tempfile.mkdtemp()
        latest_extension_version = 'Microsoft.CPlat.Core.LinuxPatchExtension-1.2.5'
        os.mkdir(os.path.join(test_dir, latest_extension_version))
        new_version_config_folder = os.path.join(test_dir,
                                                 latest_extension_version,
                                                 'config')
        os.mkdir(new_version_config_folder)
        self.action_handler.ext_env_handler.config_folder = new_version_config_folder
        self.action_handler.get_all_versions = self.mock_get_all_versions_exception
        self.assertTrue(
            self.action_handler.update() == Constants.ExitCode.HandlerFailed)
        # Remove the directory after the test
        shutil.rmtree(test_dir)