forked from port-labs/ocean
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into clickup-integrations
- Loading branch information
Showing
13 changed files
with
358 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -159,3 +159,8 @@ cython_debug/ | |
# VSCode | ||
.vscode/* | ||
!.vscode/launch.json | ||
|
||
# Junit | ||
|
||
junit/* | ||
**/junit/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# ruff: noqa | ||
from port_ocean.tests.helpers.fixtures import ( | ||
port_client_for_fake_integration, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,80 +0,0 @@ | ||
import sys | ||
from inspect import getmembers | ||
from pathlib import Path | ||
from typing import Dict, List, Set, Tuple, Union | ||
|
||
from yaml import safe_load | ||
|
||
from port_ocean.bootstrap import create_default_app | ||
from port_ocean.core.handlers.port_app_config.models import ResourceConfig | ||
from port_ocean.core.ocean_types import RESYNC_RESULT | ||
from port_ocean.ocean import Ocean | ||
from port_ocean.utils.misc import get_spec_file, load_module | ||
|
||
|
||
def get_integration_ocean_app(integration_path: str) -> Ocean: | ||
spec_file = get_spec_file(Path(integration_path)) | ||
|
||
config_factory = None if not spec_file else spec_file.get("configurations", []) | ||
|
||
default_app = create_default_app( | ||
integration_path, | ||
config_factory, | ||
{ | ||
"port": { | ||
"client_id": "bla", | ||
"client_secret": "bla", | ||
}, | ||
}, | ||
) | ||
main_path = f"{integration_path}/main.py" | ||
sys.path.append(integration_path) | ||
app_module = load_module(main_path) | ||
app: Ocean = {name: item for name, item in getmembers(app_module)}.get( | ||
"app", default_app | ||
) | ||
|
||
return app | ||
|
||
|
||
def get_integation_resource_configs(integration_path: str) -> List[ResourceConfig]: | ||
with open( | ||
f"{integration_path}/.port/resources/port-app-config.yml" | ||
) as port_app_config_file: | ||
resource_configs = safe_load(port_app_config_file) | ||
|
||
return [ResourceConfig(**item) for item in resource_configs["resources"]] | ||
|
||
|
||
def get_integation_resource_config_by_name( | ||
integration_path: str, kind: str | ||
) -> Union[ResourceConfig, None]: | ||
resource_configs = get_integation_resource_configs(integration_path) | ||
|
||
relevant_configs = [x for x in resource_configs if x.kind == kind] | ||
|
||
return relevant_configs[0] if len(relevant_configs) else None | ||
|
||
|
||
async def get_raw_result_on_integration_sync_kinds( | ||
integration_path: str, override_kinds: Union[Set[str], None] = None | ||
) -> Dict[str, List[Tuple[RESYNC_RESULT, List[Exception]]]]: | ||
app = get_integration_ocean_app(integration_path) | ||
|
||
resource_configs = get_integation_resource_configs(integration_path) | ||
|
||
if override_kinds: | ||
resource_configs = [x for x in resource_configs if x.kind in override_kinds] | ||
|
||
results: Dict[str, List[Tuple[RESYNC_RESULT, List[Exception]]]] = {} | ||
|
||
for resource_config in resource_configs: | ||
resource_result = await app.integration._get_resource_raw_results( | ||
resource_config | ||
) | ||
|
||
results[resource_config.kind] = results.get(resource_config.kind, []) + [ | ||
resource_result | ||
] | ||
|
||
return results | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
from os import environ, path | ||
from typing import Any, AsyncGenerator, Callable, List, Tuple, Union | ||
|
||
import pytest_asyncio | ||
from pydantic import BaseModel | ||
|
||
from port_ocean.clients.port.client import PortClient | ||
from port_ocean.core.handlers.port_app_config.models import ResourceConfig | ||
from port_ocean.ocean import Ocean | ||
from port_ocean.tests.helpers.ocean_app import ( | ||
get_integation_resource_configs, | ||
get_integration_ocean_app, | ||
) | ||
|
||
|
||
def get_port_client_for_integration( | ||
client_id: str, | ||
client_secret: str, | ||
integration_identifier: str, | ||
integration_type: str, | ||
integration_version: str, | ||
base_url: Union[str, None], | ||
) -> PortClient: | ||
return PortClient( | ||
base_url=base_url or "https://api.getport/io", | ||
client_id=client_id, | ||
client_secret=client_secret, | ||
integration_identifier=integration_identifier, | ||
integration_type=integration_type, | ||
integration_version=integration_version, | ||
) | ||
|
||
|
||
async def cleanup_integration(client: PortClient, blueprints: List[str]) -> None: | ||
for blueprint in blueprints: | ||
bp = await client.get_blueprint(blueprint) | ||
if bp is not None: | ||
migration_id = await client.delete_blueprint( | ||
identifier=blueprint, delete_entities=True | ||
) | ||
if migration_id: | ||
await client.wait_for_migration_to_complete(migration_id=migration_id) | ||
headers = await client.auth.headers() | ||
await client.client.delete(f"{client.auth.api_url}/integrations", headers=headers) | ||
|
||
|
||
class SmokeTestDetails(BaseModel): | ||
integration_identifier: str | ||
blueprint_department: str | ||
blueprint_person: str | ||
|
||
|
||
@pytest_asyncio.fixture() | ||
async def port_client_for_fake_integration() -> ( | ||
AsyncGenerator[Tuple[SmokeTestDetails, PortClient], None] | ||
): | ||
blueprint_department = "fake-department" | ||
blueprint_person = "fake-person" | ||
integration_identifier = "smoke-test-integration" | ||
smoke_test_suffix = environ.get("SMOKE_TEST_SUFFIX") | ||
client_id = environ.get("PORT_CLIENT_ID") | ||
client_secret = environ.get("PORT_CLIENT_SECRET") | ||
|
||
if not client_secret or not client_id: | ||
assert False, "Missing port credentials" | ||
|
||
base_url = environ.get("PORT_BASE_URL") | ||
integration_version = "0.1.1-dev" | ||
integration_type = "smoke-test" | ||
if smoke_test_suffix is not None: | ||
integration_identifier = f"{integration_identifier}-{smoke_test_suffix}" | ||
blueprint_person = f"{blueprint_person}-{smoke_test_suffix}" | ||
blueprint_department = f"{blueprint_department}-{smoke_test_suffix}" | ||
|
||
client = get_port_client_for_integration( | ||
client_id, | ||
client_secret, | ||
integration_identifier, | ||
integration_type, | ||
integration_version, | ||
base_url, | ||
) | ||
|
||
smoke_test_details = SmokeTestDetails( | ||
integration_identifier=integration_identifier, | ||
blueprint_person=blueprint_person, | ||
blueprint_department=blueprint_department, | ||
) | ||
yield smoke_test_details, client | ||
await cleanup_integration(client, [blueprint_department, blueprint_person]) | ||
|
||
|
||
@pytest_asyncio.fixture | ||
def get_mocked_ocean_app(request: Any) -> Callable[[], Ocean]: | ||
test_dir = path.join(path.dirname(request.module.__file__), "..") | ||
|
||
def get_ocean_app() -> Ocean: | ||
return get_integration_ocean_app(test_dir) | ||
|
||
return get_ocean_app | ||
|
||
|
||
@pytest_asyncio.fixture | ||
def get_mock_ocean_resource_configs(request: Any) -> Callable[[], List[ResourceConfig]]: | ||
module_dir = path.join(path.dirname(request.module.__file__), "..") | ||
|
||
def get_ocean_resource_configs() -> List[ResourceConfig]: | ||
return get_integation_resource_configs(module_dir) | ||
|
||
return get_ocean_resource_configs |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import sys | ||
from inspect import getmembers | ||
from pathlib import Path | ||
from typing import List, Tuple | ||
|
||
from yaml import safe_load | ||
|
||
from port_ocean.bootstrap import create_default_app | ||
from port_ocean.core.handlers.port_app_config.models import ResourceConfig | ||
from port_ocean.core.ocean_types import RESYNC_RESULT | ||
from port_ocean.ocean import Ocean | ||
from port_ocean.utils.misc import get_spec_file, load_module | ||
|
||
|
||
def get_integration_ocean_app(integration_path: str) -> Ocean: | ||
spec_file = get_spec_file(Path(integration_path)) | ||
|
||
config_factory = None if not spec_file else spec_file.get("configurations", []) | ||
|
||
default_app = create_default_app( | ||
integration_path, | ||
config_factory, | ||
{ | ||
"port": { | ||
"client_id": "bla", | ||
"client_secret": "bla", | ||
}, | ||
}, | ||
) | ||
main_path = f"{integration_path}/main.py" | ||
sys.path.append(integration_path) | ||
app_module = load_module(main_path) | ||
app: Ocean = {name: item for name, item in getmembers(app_module)}.get( | ||
"app", default_app | ||
) | ||
|
||
return app | ||
|
||
|
||
def get_integation_resource_configs(integration_path: str) -> List[ResourceConfig]: | ||
with open( | ||
f"{integration_path}/.port/resources/port-app-config.yml" | ||
) as port_app_config_file: | ||
resource_configs = safe_load(port_app_config_file) | ||
|
||
return [ResourceConfig(**item) for item in resource_configs["resources"]] | ||
|
||
|
||
async def get_raw_result_on_integration_sync_resource_config( | ||
app: Ocean, resource_config: ResourceConfig | ||
) -> Tuple[RESYNC_RESULT, List[Exception]]: | ||
resource_result = await app.integration._get_resource_raw_results(resource_config) | ||
|
||
return resource_result |
Oops, something went wrong.