def test_experiment_config(self):
        config_dict = {
            'uuid': uuid.uuid4().hex,
            'project': 'name.name',
            'experiment_group': 'name.name.1',
            'build_job': 'name.name.1',
            'unique_name': 'user.proj.1',
            'last_status': 'Running',
            'description': 'description',
            'content': "{'k': 'v'}",
            'is_managed': False,
            'tags': ['tag1'],
            'num_jobs': 1,
            'backend': 'foo',
            'framework': 'bar',
            'created_at': local_now().isoformat(),
            'updated_at': local_now().isoformat(),
            'has_tensorboard': True,
        }
        config = ExperimentConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        config_to_dict.pop('params')
        config_to_dict.pop('finished_at')
        config_to_dict.pop('is_clone')
        config_to_dict.pop('jobs')
        config_to_dict.pop('last_metric')
        config_to_dict.pop('resources')
        config_to_dict.pop('run_env')
        config_to_dict.pop('ttl')
        config_to_dict.pop('id')
        config_to_dict.pop('started_at')
        config_to_dict.pop('total_run')
        config_to_dict.pop('user')
        config_to_dict.pop('name')
        assert config_to_dict == config_dict

        config_to_dict = config.to_light_dict()
        config_dict.pop('uuid')
        config_dict.pop('description')
        config_dict.pop('content')
        config_dict.pop('project')
        config_dict.pop('updated_at')
        config_dict.pop('tags')
        config_dict.pop('num_jobs')
        config_dict.pop('is_managed')
        config_dict.pop('framework')
        config_dict.pop('backend')
        config_to_dict.pop('finished_at')
        config_to_dict.pop('id')
        config_to_dict.pop('started_at')
        config_dict.pop('has_tensorboard')
        config_to_dict.pop('total_run')
        config_to_dict.pop('user')
        assert config_to_dict == config_dict

        config_to_dict = config.to_light_dict(humanize_values=True)
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
        assert config_to_dict.pop('started_at') is None
Example #2
0
    def test_build_job_config(self):
        config_dict = {
            'uuid': uuid.uuid4().hex,
            'project': 'name.name',
            'build_job': 'name.name',
            'unique_name': 'user.proj.1',
            'pod_id': 'job_1',
            'last_status': 'Running',
            'description': 'description',
            'content': "{'k': 'v'}",
            'is_managed': False,
            'tags': ['test'],
            'definition': None,
            'dockerfile': 'some container',
            'backend': 'kaniko',
            'created_at': local_now().isoformat(),
            'updated_at': local_now().isoformat(),
            'started_at': local_now().isoformat(),
            'finished_at': local_now().isoformat(),
        }
        config = BuildJobConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        config_to_dict.pop('is_clone')
        config_to_dict.pop('resources')
        config_to_dict.pop('id')
        config_to_dict.pop('total_run')
        config_to_dict.pop('user')
        config_to_dict.pop('name')
        config_to_dict.pop('ttl')
        assert config_to_dict == config_dict

        config_to_dict = config.to_light_dict()
        config_dict.pop('uuid')
        config_dict.pop('description')
        config_dict.pop('content')
        config_dict.pop('project')
        config_dict.pop('build_job')
        config_dict.pop('updated_at')
        config_dict.pop('definition')
        config_dict.pop('tags')
        config_dict.pop('pod_id')
        config_dict.pop('is_managed')
        config_dict.pop('dockerfile')
        config_to_dict.pop('id')
        config_to_dict.pop('total_run')
        config_to_dict.pop('user')
        assert config_to_dict == config_dict

        config_to_dict = config.to_light_dict(humanize_values=True)
        assert config_to_dict.pop('total_run') == '0s'
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
        assert config_to_dict.pop('started_at') == 'a few seconds ago'
        assert config_to_dict.pop('finished_at') == 'a few seconds ago'
Example #3
0
    def test_executable(self):
        config_dict = {"start_at": "foo", "container": {"image": "test"}}
        with self.assertRaises(ValidationError):
            ComponentConfig.from_dict(config_dict)

        config_dict = {
            "schedule": {
                "execute_at": "foo"
            },
            "container": {
                "image": "test"
            },
        }
        with self.assertRaises(ValidationError):
            ComponentConfig.from_dict(config_dict)

        config_dict = {"timeout": 2}
        with self.assertRaises(ValidationError):
            ComponentConfig.from_dict(config_dict)

        config_dict = {
            "termination": {
                "timeout": 2
            },
            "schedule": {
                "kind": "exact_time",
                "execute_at": local_now().isoformat()
            },
            "container": {
                "image": "test"
            },
        }
        ComponentConfig.from_dict(config_dict)
Example #4
0
    def test_exact_time_schedule(self):
        config_dict = {"start_at": "foo"}
        with self.assertRaises(ValidationError):
            ExactTimeScheduleConfig.from_dict(config_dict)

        config_dict = {"kind": "exact_time", "start_at": local_now().isoformat()}
        ExactTimeScheduleConfig.from_dict(config_dict).to_dict()
Example #5
0
    def test_schedule(self):
        configs = [{
            'kind': 'interval',
            'frequency': 2,
            'start_at': local_now().isoformat(),
            'end_at': local_now().isoformat(),
            'depends_on_past': False,
        }, {
            'kind': 'cron',
            'cron': '0 0 * * *',
            'start_at': local_now().isoformat(),
            'end_at': local_now().isoformat(),
            'depends_on_past': False,
        }]

        ScheduleSchema().load(configs, many=True)
Example #6
0
    def test_tensorboard_job_config(self):
        config_dict = {
            'uuid': uuid.uuid4().hex,
            'project': 'name.name',
            'experiment': 1,
            'experiment_group': 1,
            'unique_name': 'user.proj.1',
            'pod_id': 'job_1',
            'last_status': 'Running',
            'tags': ['test'],
            'is_managed': False,
            'created_at': local_now().isoformat(),
            'updated_at': local_now().isoformat(),
            'started_at': local_now().isoformat(),
            'finished_at': local_now().isoformat(),
        }
        config = TensorboardJobConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        config_to_dict.pop('is_clone')
        config_to_dict.pop('resources')
        config_to_dict.pop('id')
        config_to_dict.pop('total_run')
        config_to_dict.pop('user')
        config_to_dict.pop('name')
        config_to_dict.pop('build_job')
        config_to_dict.pop('content')
        config_to_dict.pop('definition')
        config_to_dict.pop('description')
        config_to_dict.pop('ttl')
        assert config_to_dict == config_dict

        config_to_dict = config.to_light_dict()
        config_dict.pop('uuid')
        config_dict.pop('project')
        config_dict.pop('updated_at')
        config_dict.pop('tags')
        config_dict.pop('is_managed')
        config_to_dict.pop('id')
        config_to_dict.pop('total_run')
        config_to_dict.pop('user')
        assert config_to_dict == config_dict

        config_to_dict = config.to_light_dict(humanize_values=True)
        assert config_to_dict.pop('total_run') == '0s'
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
        assert config_to_dict.pop('started_at') == 'a few seconds ago'
        assert config_to_dict.pop('finished_at') == 'a few seconds ago'
Example #7
0
    def test_schedule(self):
        configs = [
            {
                "kind": "interval",
                "frequency": 2,
                "start_at": local_now().isoformat(),
                "end_at": local_now().isoformat(),
                "depends_on_past": False,
            },
            {
                "kind": "cron",
                "cron": "0 0 * * *",
                "start_at": local_now().isoformat(),
                "end_at": local_now().isoformat(),
                "depends_on_past": False,
            },
        ]

        ScheduleSchema().load(configs, many=True)
Example #8
0
    def test_pipelines_base_attrs(self):
        config_dict = {"concurrency": "foo", "container": {"image": "test"}}
        with self.assertRaises(ValidationError):
            ComponentConfig.from_dict(config_dict)

        config_dict = {"concurrency": 2, "container": {"image": "test"}}
        with self.assertRaises(ValidationError):
            ComponentConfig.from_dict(config_dict)

        config_dict = {
            "workflow": {
                "concurrency": 2,
                "strategy": {
                    "kind": "mapping",
                    "values": [{
                        "a": 1
                    }, {
                        "a": 1
                    }]
                },
            },
            "container": {
                "image": "test"
            },
        }
        config = ComponentConfig.from_dict(config_dict)
        assert config.to_dict()["workflow"] == config_dict["workflow"]

        config_dict = {
            "workflow": {
                "concurrency": 2,
                "strategy": {
                    "kind": "mapping",
                    "values": [{
                        "a": 1
                    }, {
                        "a": 1
                    }]
                },
            },
            "schedule": {
                "kind": "exact_time",
                "execute_at": local_now().isoformat()
            },
            "termination": {
                "timeout": 1000
            },
            "container": {
                "image": "test"
            },
        }
        config = ComponentConfig.from_dict(config_dict)
        config_to_light = config.to_light_dict()
        assert config_to_light == config_dict
    def test_project_config(self):
        config_dict = {
            'name': 'test',
            'description': '',
            'is_public': True,
            'has_code': True,
            'has_tensorboard': True,
            'tags': ['foo'],
            'num_experiments': 0,
            'num_independent_experiments': 0,
            'num_experiment_groups': 0,
            'num_jobs': 0,
            'num_builds': 0,
            'created_at': local_now().isoformat(),
            'updated_at': local_now().isoformat()
        }
        config = ProjectConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        config_to_dict.pop('id', None)
        config_to_dict.pop('experiment_groups', None)
        config_to_dict.pop('experiments', None)
        config_to_dict.pop('has_notebook', None)
        config_to_dict.pop('unique_name', None)
        config_to_dict.pop('user', None)
        config_to_dict.pop('owner', None)
        config_to_dict.pop('uuid', None)
        assert config_to_dict == config_dict
        config_dict.pop('description')
        config_dict.pop('updated_at')
        config_dict.pop('has_code')
        config_to_dict = config.to_light_dict()
        config_to_dict.pop('has_notebook', None)
        config_to_dict.pop('unique_name', None)
        assert config_to_dict == config_dict

        config_to_dict = config.to_dict(humanize_values=True)
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
        assert config_to_dict.pop('updated_at') == 'a few seconds ago'

        config_to_dict = config.to_light_dict(humanize_values=True)
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
Example #10
0
    def test_cron_schedule(self):
        config_dict = {'cron': 2, 'start_at': 'foo'}
        with self.assertRaises(ValidationError):
            CronScheduleConfig.from_dict(config_dict)

        config_dict = {
            'kind': 'interval',
            'cron': '0 0 * * *',
            'start_at': local_now().isoformat(),
            'end_at': local_now().isoformat()
        }
        with self.assertRaises(ValidationError):
            CronScheduleConfig.from_dict(config_dict)

        config_dict = {
            'cron': '0 0 * * *',
        }
        CronScheduleConfig.from_dict(config_dict)

        config_dict = {
            'cron': '0 0 * * *',
            'start_at': local_now().isoformat(),
            'end_at': local_now().isoformat()
        }
        CronScheduleConfig.from_dict(config_dict)

        config_dict = {
            'kind': 'cron',
            'cron': '0 0 * * *',
            'start_at': local_now().isoformat(),
            'end_at': local_now().isoformat(),
            'depends_on_past': False,
        }
        CronScheduleConfig.from_dict(config_dict)
Example #11
0
    def test_cron_schedule(self):
        config_dict = {"cron": 2, "start_at": "foo"}
        with self.assertRaises(ValidationError):
            CronScheduleConfig.from_dict(config_dict)

        config_dict = {
            "kind": "interval",
            "cron": "0 0 * * *",
            "start_at": local_now().isoformat(),
            "end_at": local_now().isoformat(),
        }
        with self.assertRaises(ValidationError):
            CronScheduleConfig.from_dict(config_dict)

        config_dict = {"cron": "0 0 * * *"}
        CronScheduleConfig.from_dict(config_dict)

        config_dict = {
            "cron": "0 0 * * *",
            "start_at": local_now().isoformat(),
            "end_at": local_now().isoformat(),
        }
        CronScheduleConfig.from_dict(config_dict)

        config_dict = {
            "kind": "cron",
            "cron": "0 0 * * *",
            "start_at": local_now().isoformat(),
            "end_at": local_now().isoformat(),
            "depends_on_past": False,
        }
        CronScheduleConfig.from_dict(config_dict)
    def test_experiment_job_config(self):
        config_dict = {
            'uuid': uuid.uuid4().hex,
            'experiment': 1,
            'created_at': local_now().isoformat(),
            'updated_at': local_now().isoformat(),
            'started_at': local_now().isoformat(),
            'finished_at': local_now().isoformat(),
            'definition': {},
            'role': 'master',
            'id': 1,
            'pod_id': 'job_1',
            'unique_name': 'project.1.1.master'
        }
        config = ExperimentJobConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        assert config_to_dict.pop('total_run') == '0s'
        config_to_dict.pop('last_status')
        config_to_dict.pop('resources')
        assert config_to_dict == config_dict

        config_dict.pop('definition')
        config_dict.pop('experiment')
        config_dict.pop('updated_at')
        config_dict.pop('uuid')
        config_to_dict = config.to_light_dict()
        assert config_to_dict.pop('total_run') == '0s'
        config_dict.pop('unique_name')
        config_to_dict.pop('last_status')
        assert config_to_dict == config_dict

        config_to_dict = config.to_light_dict(humanize_values=True)
        assert config_to_dict.pop('total_run') == '0s'
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
        assert config_to_dict.pop('started_at') == 'a few seconds ago'
        assert config_to_dict.pop('finished_at') == 'a few seconds ago'
Example #13
0
 def create_pod_state(cls):
     event_type = 'ADDED'
     phase = 'Running'
     labels = cls.create_pod_labels()
     deletion_timestamp = local_now().isoformat()
     pod_conditions = {}
     container_statuses = {}
     return {
         'event_type': event_type,
         'phase': phase,
         'labels': labels,
         'node_name': 'node1',
         'deletion_timestamp': deletion_timestamp,
         'pod_conditions': pod_conditions,
         'container_statuses': container_statuses,
     }
Example #14
0
    def test_executable(self):
        config_dict = {'start_at': 'foo'}
        with self.assertRaises(ValidationError):
            ExecutableConfig.from_dict(config_dict)

        config_dict = {'execute_at': 'foo'}
        with self.assertRaises(ValidationError):
            ExecutableConfig.from_dict(config_dict)

        config_dict = {
            'timeout': 2,
            'execute_at': local_now().isoformat()
        }
        ExecutableConfig.from_dict(config_dict)

        config_dict = {
            'timeout': 2,
        }
        ExecutableConfig.from_dict(config_dict)
Example #15
0
    def test_group_status_config(self):
        config_dict = {'id': 1,
                       'uuid': uuid.uuid4().hex,
                       'experiment_group': 1,
                       'created_at': local_now().isoformat(),
                       'status': 'Running',
                       'message': None,
                       'details': None}
        config = GroupStatusConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        assert config_to_dict == config_dict

        config_dict.pop('experiment_group', None)
        config_dict.pop('uuid', None)
        config_dict.pop('details', None)
        config_to_dict = config.to_light_dict()
        assert config_to_dict == config_dict

        config_to_dict = config.to_dict(humanize_values=True)
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
    def test_experiment_metric_config(self):
        config_dict = {
            'id': 1,
            'uuid': uuid.uuid4().hex,
            'experiment': 1,
            'created_at': local_now().isoformat(),
            'values': {
                'accuracy': 0.9
            }
        }
        config = ExperimentMetricConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        assert config_to_dict == config_dict

        config_dict.pop('experiment', None)
        config_dict.pop('uuid', None)
        config_to_dict = config.to_light_dict()
        assert config_to_dict == config_dict

        config_to_dict = config.to_dict(humanize_values=True)
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
Example #17
0
 def test_data_config(self):
     config_dict = {
         'uuid':
         uuid.uuid4().hex,
         'name':
         'foo',
         'created_at':
         local_now().isoformat(),
         'description':
         'foo data',
         'details':
         DataDetailsConfig(state='state',
                           size=1.4,
                           uri='http://www.foo.com/data').to_dict(),
         'version':
         None,
         'resource_id':
         '1'
     }
     config = DataConfig.from_dict(config_dict)
     config_to_dict = config.to_dict()
     assert config_to_dict == config_dict
Example #18
0
    def test_tensorboard_status_config(self):
        config_dict = {'id': 1,
                       'uuid': uuid.uuid4().hex,
                       'job': 1,
                       'created_at': local_now().isoformat(),
                       'status': 'Running',
                       'message': None,
                       'traceback': None,
                       'details': None}
        config = JobStatusConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        assert config_to_dict == config_dict

        config_dict.pop('job', None)
        config_dict.pop('uuid', None)
        config_dict.pop('details', None)
        config_dict.pop('traceback', None)
        config_to_dict = config.to_light_dict()
        assert config_to_dict == config_dict

        config_to_dict = config.to_dict(humanize_values=True)
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
Example #19
0
    def test_interval_schedule(self):
        config_dict = {"frequency": 2, "start_at": "foo"}
        with self.assertRaises(ValidationError):
            IntervalScheduleConfig.from_dict(config_dict)

        config_dict = {"frequency": "foo", "start_at": local_now().isoformat()}
        with self.assertRaises(ValidationError):
            IntervalScheduleConfig.from_dict(config_dict)

        config_dict = {
            "kind": "cron",
            "frequency": 2,
            "start_at": local_now().isoformat(),
            "end_at": local_now().isoformat(),
        }
        with self.assertRaises(ValidationError):
            IntervalScheduleConfig.from_dict(config_dict)

        config_dict = {"frequency": 2, "start_at": local_now().isoformat()}
        IntervalScheduleConfig.from_dict(config_dict)

        config_dict = {
            "frequency": 2,
            "start_at": local_now().isoformat(),
            "end_at": local_now().isoformat(),
        }
        IntervalScheduleConfig.from_dict(config_dict)

        config_dict = {
            "kind": "interval",
            "frequency": 2,
            "start_at": local_now().isoformat(),
            "end_at": local_now().isoformat(),
            "depends_on_past": False,
        }
        IntervalScheduleConfig.from_dict(config_dict)
    def test_experiment_job_status_config(self):
        config_dict = {
            'id': 1,
            'uuid': uuid.uuid4().hex,
            'job': 1,
            'created_at': local_now().isoformat(),
            'status': 'Running'
        }
        config = ExperimentJobStatusConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        config_to_dict.pop('details')
        config_to_dict.pop('message')
        assert config_to_dict == config_dict

        config_to_dict = config.to_light_dict()
        config_dict.pop('details', None)
        config_dict.pop('job', None)
        config_dict.pop('uuid', None)
        config_to_dict.pop('message')
        assert config_to_dict == config_dict

        config_to_dict = config.to_light_dict(humanize_values=True)
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
    def test_experiment_with_jobs_config(self):
        config_dict = {
            'id':
            2,
            'unique_name':
            'adam.proj.1',
            'uuid':
            uuid.uuid4().hex,
            'project':
            'user.name',
            'experiment_group':
            'user.name.1',
            'last_status':
            'Running',
            'num_jobs':
            1,
            'backend':
            'foo',
            'framework':
            'bar',
            'created_at':
            local_now().isoformat(),
            'updated_at':
            local_now().isoformat(),
            'started_at':
            local_now().isoformat(),
            'finished_at':
            local_now().isoformat(),
            'has_tensorboard':
            False,
            'is_managed':
            False,
            'tags': ['tag'],
            'jobs': [
                ExperimentJobConfig(uuid=uuid.uuid4().hex,
                                    experiment=2,
                                    created_at=local_now(),
                                    updated_at=local_now(),
                                    definition={}).to_dict()
            ]
        }
        config = ExperimentConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        assert config_to_dict.pop('total_run') == '0s'
        config_to_dict.pop('declarations')
        config_to_dict.pop('description')
        config_to_dict.pop('is_clone')
        config_to_dict.pop('last_metric')
        config_to_dict.pop('resources')
        config_to_dict.pop('run_env')
        config_to_dict.pop('user')
        config_to_dict.pop('name')
        config_to_dict.pop('build_job')
        config_to_dict.pop('ttl')
        config_to_dict.pop('content')
        assert config_to_dict == config_dict

        config_dict.pop('tags')
        config_to_dict = config.to_light_dict(humanize_values=True)
        assert config_to_dict.pop('total_run') == '0s'
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
        assert config_to_dict.pop('started_at') == 'a few seconds ago'
        assert config_to_dict.pop('finished_at') == 'a few seconds ago'
Example #22
0
    def test_experiment_group_config(self):
        uuid_value = uuid.uuid4().hex
        config_dict = {'id': 1,
                       'content': 'some content',
                       'uuid': uuid_value,
                       'project': 'user.name',
                       'num_experiments': 0,
                       'created_at': local_now().isoformat(),
                       'updated_at': local_now().isoformat(),
                       'started_at': local_now().isoformat(),
                       'finished_at': local_now().isoformat(),
                       'group_type': 'study',
                       'backend': 'native',
                       'is_managed': True,
                       'search_algorithm': None,
                       'last_status': None,
                       'has_tensorboard': False,
                       'tags': ['tests'],
                       'experiments': [
                           ExperimentConfig(uuid=uuid_value,
                                            experiment_group=uuid_value,
                                            project=uuid_value).to_dict()]}
        config = GroupConfig.from_dict(config_dict)
        config_to_dict = config.to_dict()
        config_to_dict.pop('concurrency', None)
        config_to_dict.pop('description', None)
        config_to_dict.pop('num_failed_experiments', None)
        config_to_dict.pop('num_pending_experiments', None)
        config_to_dict.pop('num_running_experiments', None)
        config_to_dict.pop('num_scheduled_experiments', None)
        config_to_dict.pop('num_stopped_experiments', None)
        config_to_dict.pop('num_succeeded_experiments', None)
        config_to_dict.pop('unique_name', None)
        config_to_dict.pop('user', None)
        config_to_dict.pop('name', None)
        config_to_dict.pop('total_run', None)
        assert config_to_dict == config_dict

        config_dict.pop('content')
        config_dict.pop('uuid')
        config_dict.pop('project')
        config_dict.pop('updated_at')
        config_dict.pop('id')
        config_dict.pop('experiments')
        config_dict.pop('has_tensorboard')
        config_dict.pop('tags')
        config_dict.pop('backend')
        config_dict.pop('is_managed')
        config_dict.pop('num_experiments', None)
        config_dict.pop('num_failed_experiments', None)
        config_dict.pop('num_pending_experiments', None)
        config_dict.pop('num_running_experiments', None)
        config_dict.pop('num_scheduled_experiments', None)
        config_dict.pop('num_stopped_experiments', None)
        config_dict.pop('num_succeeded_experiments', None)
        assert_equal_dict(config_dict, config.to_light_dict())

        config_to_dict = config.to_dict(humanize_values=True)
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
        assert config_to_dict.pop('updated_at') == 'a few seconds ago'

        config_to_dict = config.to_light_dict(humanize_values=True)
        assert config_to_dict.pop('created_at') == 'a few seconds ago'
Example #23
0
    def test_pipelines_base_attrs(self):
        config_dict = {
            "concurrency": "foo",
            "run": {
                "kind": "container",
                "image": "test"
            },
        }
        with self.assertRaises(ValidationError):
            ComponentConfig.from_dict(config_dict)

        config_dict = {
            "concurrency": 2,
            "run": {
                "kind": "container",
                "image": "test"
            }
        }
        with self.assertRaises(ValidationError):
            ComponentConfig.from_dict(config_dict)

        config_dict = {
            "parallel": {
                "concurrency": 2,
                "kind": "mapping",
                "values": [{
                    "a": 1
                }, {
                    "a": 1
                }],
            },
            "run": {
                "kind": "container",
                "image": "test"
            },
        }
        config = ComponentConfig.from_dict(config_dict)
        assert config.to_dict()["run"] == config_dict["run"]
        assert config.to_dict()["parallel"] == config_dict["parallel"]

        config_dict = {
            "parallel": {
                "concurrency": 2,
                "kind": "mapping",
                "values": [{
                    "a": 1
                }, {
                    "a": 1
                }],
            },
            "schedule": {
                "kind": "exact_time",
                "start_at": local_now().isoformat()
            },
            "termination": {
                "timeout": 1000
            },
            "run": {
                "kind": "container",
                "image": "test"
            },
        }
        config = ComponentConfig.from_dict(config_dict)
        config_to_light = config.to_light_dict()
        config_to_light["schedule"].pop("start_at")
        config_dict["schedule"].pop("start_at")
        assert config_to_light == config_dict