Skip to content

Commit

Permalink
Make sure that data_server_cli fixture is not run when running othe…
Browse files Browse the repository at this point in the history
…r tests, separate tests requiring RCC environments from the other tests.
  • Loading branch information
fabioz committed Dec 12, 2024
1 parent 83a4038 commit 28c89b5
Show file tree
Hide file tree
Showing 14 changed files with 199 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,9 @@ jobs:
# Big timeout to create environment in windows.
RUN_TESTS_TIMEOUT: 3000
ACTION_SERVER_TEST_ACCESS_CREDENTIALS: ${{ secrets.ACTION_SERVER_TEST_ACCESS_CREDENTIALS }}
PYTEST_CAN_RUN_DATA_SERVER: 1

run: poetry run python -u ../../sema4ai-python-ls-core/tests/run_tests.py -rfE -otests_output_data_server -vv -m data_server .
run: poetry run python -u ../../sema4ai-python-ls-core/tests/run_tests.py -rfE -n 1 -otests_output_data_server -vv -m data_server .

- uses: actions/upload-artifact@v4
if: always()
Expand Down
84 changes: 84 additions & 0 deletions .github/workflows/tests-sema4ai-sdk-rcc-integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: Tests - Sema4.ai RCC Integration (sema4ai)

on:
push:
paths:
- sema4ai/**
- sema4ai-python-ls-core/**
- .github/**

pull_request:
paths:
- sema4ai/**
- sema4ai-python-ls-core/**
- .github/**

jobs:
build:
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
name: [
"ubuntu-py311",
"windows-py311",
# "mac-py311", mac disabled because it takes too long for runners to pick the mac job up.
]

include:
- name: "ubuntu-py311"
python: "3.11"
os: ubuntu-latest
- name: "windows-py311"
python: "3.11"
os: windows-latest
# - name: "mac-py311"
# python: "3.11"
# os: mac-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python }}
- name: Upgrade pip
run: python -m pip install --upgrade pip
- name: Vendor sema4ai_ls_core
working-directory: ./sema4ai
run: |
pip install fire poetry
python -m dev vendor-robocorp-ls-core
- name: poetry install
working-directory: ./sema4ai
run: poetry install
- name: Run codegen
run: python -m dev codegen
working-directory: ./sema4ai
env:
PYTHONPATH: src
- name: Test
working-directory: ./sema4ai/tests
env:
PYTHONPATH: .
CI_CREDENTIALS: ${{ secrets.CI_CREDENTIALS }}
CI_ENDPOINT: ${{ secrets.CI_ENDPOINT }}
# Big timeout to create environment in windows.
RUN_TESTS_TIMEOUT: 3000
ACTION_SERVER_TEST_ACCESS_CREDENTIALS: ${{ secrets.ACTION_SERVER_TEST_ACCESS_CREDENTIALS }}

run: poetry run python -u ../../sema4ai-python-ls-core/tests/run_tests.py -rfE -n 1 -otests_output_rcc -vv -m rcc_env .

- uses: actions/upload-artifact@v4
if: always()
with:
name: tests_output_rcc.${{ matrix.name }}.txt
path: sema4ai/tests/tests_output_rcc
- uses: actions/upload-artifact@v4
if: always()
with:
name: log_rcc.${{ matrix.name }}.html
path: sema4ai/tests/output/log.html

2 changes: 1 addition & 1 deletion .github/workflows/tests-sema4ai-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
RUN_TESTS_TIMEOUT: 3000
ACTION_SERVER_TEST_ACCESS_CREDENTIALS: ${{ secrets.ACTION_SERVER_TEST_ACCESS_CREDENTIALS }}

run: poetry run python -u ../../sema4ai-python-ls-core/tests/run_tests.py -rfE -otests_output -vv -m "not data_server" .
run: poetry run python -u ../../sema4ai-python-ls-core/tests/run_tests.py -rfE -otests_output -vv -n 1 -m "not data_server and not rcc_env" .

- uses: actions/upload-artifact@v4
if: always()
Expand Down
10 changes: 5 additions & 5 deletions sema4ai-python-ls-core/src/sema4ai_ls_core/core_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
"""

import os.path
import traceback
import threading
import sys
import threading
import traceback
from datetime import datetime
from sema4ai_ls_core.protocols import ILog
from typing import Dict

from sema4ai_ls_core.constants import NULL
from sema4ai_ls_core.protocols import ILog

name_to_logger: dict[str, ILog] = {}

Expand All @@ -39,7 +39,7 @@ def _as_str(s):
return s


MAX_LOG_MSG_SIZE = 2000
MAX_LOG_MSG_SIZE = 20000
try:
MAX_LOG_MSG_SIZE = int(os.environ.get("MAX_LOG_MSG_SIZE", MAX_LOG_MSG_SIZE))
except Exception:
Expand Down
2 changes: 1 addition & 1 deletion sema4ai-python-ls-core/src/sema4ai_ls_core/system_mutex.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ def __init__(
try:
try:
with open(filename) as stream:
curr_pid = stream.readline().strip()[-1]
curr_pid = stream.readline().strip()
except:
log.exception("Unable to get locking pid.")
curr_pid = "<unable to get locking pid>"
Expand Down
125 changes: 69 additions & 56 deletions sema4ai/src/sema4ai_code/robocorp_language_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,11 @@ def _get_linked_account_info(self, params=None) -> ActionResultDict:
@command_dispatcher(commands.SEMA4AI_CLOUD_LIST_WORKSPACES_INTERNAL)
def _cloud_list_workspaces(
self, params: CloudListWorkspaceDict
) -> ListWorkspacesActionResultDict:
return require_monitor(partial(self._cloud_list_workspaces_impl, params))

def _cloud_list_workspaces_impl(
self, params: CloudListWorkspaceDict, monitor: IMonitor
) -> ListWorkspacesActionResultDict:
from sema4ai_ls_core.progress_report import progress_context

Expand Down Expand Up @@ -663,72 +668,80 @@ def _cloud_list_workspaces(

last_error_result = None

with progress_context(
self._endpoint, "Listing Control Room workspaces", self._dir_cache
):
ws: IRccWorkspace
ret: list[WorkspaceInfoDict] = []
result = self._rcc.cloud_list_workspaces()
if not result.success:
# It's an error, so, the data should be None.
return typing.cast(
ActionResultDict[list[WorkspaceInfoDict]], result.as_dict()
)

workspaces = result.result
for ws in workspaces or []:
packages: list[PackageInfoDict] = []
try:
with progress_context(
self._endpoint, "Listing Control Room workspaces", self._dir_cache
):
ws: IRccWorkspace
ret: list[WorkspaceInfoDict] = []
result = self._rcc.cloud_list_workspaces()
if not result.success:
# It's an error, so, the data should be None.
return typing.cast(
ActionResultDict[list[WorkspaceInfoDict]], result.as_dict()
)

activity_package: IRccRobotMetadata
activities_result = self._rcc.cloud_list_workspace_robots(
ws.workspace_id
)
if not activities_result.success:
# If we can't list the robots of a specific workspace, just skip it
# (the log should still show it but we can proceed to list the
# contents of other workspaces).
last_error_result = activities_result
continue
workspaces = result.result
for ws in workspaces or []:
packages: list[PackageInfoDict] = []

workspace_activities = activities_result.result
for activity_package in workspace_activities or []:
key = (ws.workspace_id, activity_package.robot_id)
sort_key = "%05d%s" % (
ws_id_and_pack_id_to_lru_index.get(key, DEFAULT_SORT_KEY),
activity_package.robot_name.lower(),
activity_package: IRccRobotMetadata
activities_result = self._rcc.cloud_list_workspace_robots(
ws.workspace_id
)
if not activities_result.success:
# If we can't list the robots of a specific workspace, just skip it
# (the log should still show it but we can proceed to list the
# contents of other workspaces).
last_error_result = activities_result
continue

workspace_activities = activities_result.result
for activity_package in workspace_activities or []:
key = (ws.workspace_id, activity_package.robot_id)
sort_key = "%05d%s" % (
ws_id_and_pack_id_to_lru_index.get(key, DEFAULT_SORT_KEY),
activity_package.robot_name.lower(),
)

package_info = {
"name": activity_package.robot_name,
"id": activity_package.robot_id,
"sortKey": sort_key,
package_info = {
"name": activity_package.robot_name,
"id": activity_package.robot_id,
"sortKey": sort_key,
"organizationName": ws.organization_name,
"workspaceId": ws.workspace_id,
"workspaceName": ws.workspace_name,
}
packages.append(package_info)

ws_dict = {
"organizationName": ws.organization_name,
"workspaceId": ws.workspace_id,
"workspaceName": ws.workspace_name,
"workspaceId": ws.workspace_id,
"packages": packages,
}
packages.append(package_info)
ret.append(ws_dict)

ws_dict = {
"organizationName": ws.organization_name,
"workspaceName": ws.workspace_name,
"workspaceId": ws.workspace_id,
"packages": packages,
}
ret.append(ws_dict)

if not ret and last_error_result is not None:
# It's an error, so, the data should be None.
return typing.cast(
ActionResultDict[list[WorkspaceInfoDict]], last_error_result.as_dict()
)
if not ret and last_error_result is not None:
# It's an error, so, the data should be None.
return typing.cast(
ActionResultDict[list[WorkspaceInfoDict]],
last_error_result.as_dict(),
)

if ret: # Only store if we got something.
store: ListWorkspaceCachedInfoDict = {
"ws_info": ret,
"account_cache_key": account_cache_key,
if ret: # Only store if we got something.
store: ListWorkspaceCachedInfoDict = {
"ws_info": ret,
"account_cache_key": account_cache_key,
}
self._dir_cache.store(self.CLOUD_LIST_WORKSPACE_CACHE_KEY, store)
return {"success": True, "message": None, "result": ret}
except Exception as e:
return {
"success": False,
"message": f"Error listing workspaces: {e}",
"result": None,
}
self._dir_cache.store(self.CLOUD_LIST_WORKSPACE_CACHE_KEY, store)
return {"success": True, "message": None, "result": ret}

@command_dispatcher(commands.SEMA4AI_CREATE_ROBOT_INTERNAL)
def _create_robot(self, params: CreateRobotParamsDict) -> ActionResultDict:
Expand Down
1 change: 1 addition & 0 deletions sema4ai/tests/pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ timeout=1800
; https://docs.pytest.org/en/stable/how-to/mark.html
markers =
data_server: marks data server tests (deselect with '-m "not data_server"')
rcc_env: marks rcc environment tests (deselect with '-m "not rcc_env"')
9 changes: 9 additions & 0 deletions sema4ai/tests/sema4ai_code_tests/data_server_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,15 @@ def _is_current_db_data_valid(

@pytest.fixture(scope="session")
def data_server_cli(request, tmpdir_factory) -> Iterator["DataServerCliWrapper"]:
import os

if os.getenv("GITHUB_ACTIONS"):
# Detect if running in github actions
if not os.getenv("PYTEST_CAN_RUN_DATA_SERVER"):
raise RuntimeError(
"Test must be marked with @pytest.mark.data_server to run in github actions to use `data_server_cli` fixture"
)

from sema4ai_code_tests.data_server_cli_wrapper import DataServerCliWrapper
from sema4ai_ls_core.system_mutex import timed_acquire_mutex

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ def setup_data_source(datasource: DatasourceInfoTypedDict):
data_regression.check(fixed_result, basename="missing_data_source_none")


@pytest.mark.data_server
def setup_sqlite_data_source(data_server_cli, tmpdir):
import json

Expand All @@ -275,6 +274,7 @@ def setup_sqlite_data_source(data_server_cli, tmpdir):
)


@pytest.mark.data_server
def test_compute_data_sources_state(
data_server_cli: DataServerCliWrapper,
ws_root_path,
Expand Down
Empty file.
16 changes: 11 additions & 5 deletions sema4ai/tests/sema4ai_code_tests/test_language_server_directly.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,21 @@ def test_cloud_list_workspaces_cache_invalidate(
rcc = language_server._rcc
rcc._last_verified_account_info = AccountInfo("default account", "123", "", "")

assert language_server._cloud_list_workspaces({"refresh": False})["success"]
assert language_server._cloud_list_workspaces({"refresh": False})(monitor=NULL)[
"success"
]
rcc_patch.disallow_calls()
assert language_server._cloud_list_workspaces({"refresh": False})["success"]
assert language_server._cloud_list_workspaces({"refresh": False})(monitor=NULL)[
"success"
]

rcc._last_verified_account_info = AccountInfo("another account", "123", "", "")

# As account changed, the data should be fetched (as we can't due to the patching
# the error is expected).
with pytest.raises(AssertionError) as e:
assert not language_server._cloud_list_workspaces({"refresh": False})["success"]
result = language_server._cloud_list_workspaces({"refresh": False})(monitor=NULL)
assert not result["success"]

assert "This should not be called at this time (data should be cached)." in str(e)
assert "This should not be called at this time (data should be cached)." in str(
result["message"]
)
3 changes: 3 additions & 0 deletions sema4ai/tests/sema4ai_code_tests/test_rcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ def custom_handler(args, *sargs, **kwargs):
assert [ws.workspace_name for ws in workspaces_listed] == ["Ex3"]


@pytest.mark.rcc_env
def test_rcc_cloud(rcc: IRcc, ci_credentials: str, tmpdir):
"""
Note on the setup:
Expand Down Expand Up @@ -243,6 +244,7 @@ def conda_yaml_contents(self):
return self.conda_yaml.read_text("utf-8")


@pytest.mark.rcc_env
def test_get_robot_yaml_environ(rcc: IRcc, datadir, holotree_manager):
from sema4ai_ls_core.protocols import ActionResult

Expand Down Expand Up @@ -386,6 +388,7 @@ def test_get_robot_yaml_environ(rcc: IRcc, datadir, holotree_manager):
)


@pytest.mark.rcc_env
def test_get_robot_yaml_environ_not_ok(rcc: IRcc, datadir, holotree_manager):
# Test what happens when things go don't go as planned (i.e.: an environment
# cannot be created).
Expand Down
Loading

0 comments on commit 28c89b5

Please sign in to comment.