pipelines/sdk/python/kfp/local/testing_utilities.py

102 lines
3.3 KiB
Python
Executable File

# Copyright 2023 The Kubeflow Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Utilities for testing local execution."""
import datetime
import functools
import os
import pathlib
import tempfile
import unittest
from unittest import mock
from absl.testing import parameterized
from google.protobuf import json_format
from google.protobuf import message
from kfp import components
from kfp import dsl
from kfp.local import config as local_config
_LOCAL_KFP_PACKAGE_PATH = os.path.join(
os.path.dirname(__file__),
os.path.pardir,
os.path.pardir,
)
class LocalRunnerEnvironmentTestCase(parameterized.TestCase):
"""Test class that uses an isolated filesystem and updates the
dsl.component decorator to install from the local KFP source, rather than
the latest release."""
def setUp(self):
# ENTER: start each test case without an uninitialized environment
local_config.LocalExecutionConfig.instance = None
# ENTER: use tempdir for all tests
self.working_dir = pathlib.Path.cwd()
self.temp_dir = tempfile.TemporaryDirectory()
os.chdir(self.temp_dir.name)
def tearDown(self):
# EXIT: use tempdir for all tests
self.temp_dir.cleanup()
os.chdir(self.working_dir)
@classmethod
def setUpClass(cls):
# ENTER: use local KFP package path for subprocess runner
cls.original_component, dsl.component = dsl.component, functools.partial(
dsl.component, kfp_package_path=_LOCAL_KFP_PACKAGE_PATH)
@classmethod
def tearDownClass(cls):
# EXIT: use local KFP package path for subprocess runner
dsl.component = cls.original_component
class MockedDatetimeTestCase(unittest.TestCase):
def setUp(self):
# set up patch, cleanup, and start
patcher = mock.patch('kfp.local.executor_input_utils.datetime.datetime')
self.addCleanup(patcher.stop)
self.mock_datetime = patcher.start()
# set mock return values
mock_now = mock.MagicMock(
wraps=datetime.datetime(2023, 10, 10, 13, 32, 59, 420710))
self.mock_datetime.now.return_value = mock_now
mock_now.strftime.return_value = '2023-10-10-13-32-59-420710'
def write_proto_to_json_file(
proto_message: message.Message,
file_path: str,
) -> None:
"""Writes proto_message to file_path as JSON."""
json_string = json_format.MessageToJson(proto_message)
with open(file_path, 'w') as json_file:
json_file.write(json_string)
def compile_and_load_component(
base_component: dsl.base_component.BaseComponent,
) -> dsl.yaml_component.YamlComponent:
"""Compiles a component to PipelineSpec and reloads it as a
YamlComponent."""
return components.load_component_from_text(
json_format.MessageToJson(base_component.pipeline_spec))