Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: missed project-id in command lean cloud live deploy ... #531

Merged
merged 3 commits into from
Dec 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lean/commands/cloud/live/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ def deploy(project: str,

live_data_provider_settings = {}
lean_config = container.lean_config_manager.get_lean_config()
lean_config["project-id"] = cloud_project.projectId

if brokerage is not None:
ensure_options(["brokerage", "node", "auto_restart", "notify_order_events", "notify_insights"])
Expand Down
22 changes: 15 additions & 7 deletions tests/commands/cloud/live/test_cloud_live_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
# limitations under the License.

from unittest import mock
import responses
from click.testing import CliRunner
import pytest
import sys
from lean.commands import lean
from lean.container import container
from lean.models.api import QCEmailNotificationMethod, QCWebhookNotificationMethod, QCSMSNotificationMethod, QCTelegramNotificationMethod
from lean.models.api import QCEmailNotificationMethod, QCWebhookNotificationMethod, QCSMSNotificationMethod, \
QCTelegramNotificationMethod, QCAuth0Authorization
from tests.test_helpers import create_fake_lean_cli_directory, create_qc_nodes
from tests.commands.test_live import brokerage_required_options

Expand Down Expand Up @@ -245,7 +247,7 @@ def test_cloud_live_deploy_with_notifications(notice_method: str, configs: str)
("Terminal Link", "USD:100"),
("Tradier", "USD:100"),
("Zerodha", "USD:100"),
("TDAmeritrade", "USD:100")])
("CharlesSchwab", "USD:100")])
def test_cloud_live_deploy_with_live_cash_balance(brokerage: str, cash: str) -> None:
if (brokerage == "Interactive Brokers" and sys.platform == "darwin"):
pytest.skip("MacOS does not support IB tests")
Expand Down Expand Up @@ -303,6 +305,7 @@ def test_cloud_live_deploy_with_live_cash_balance(brokerage: str, cash: str) ->
mock.ANY)


@responses.activate
@pytest.mark.parametrize("brokerage,holdings", [("Paper Trading", ""),
("Paper Trading", "A:A 2T:1:145.1"),
("Paper Trading", "A:A 2T:1:145.1,AA:AA 2T:2:20.35"),
Expand All @@ -328,18 +331,23 @@ def test_cloud_live_deploy_with_live_cash_balance(brokerage: str, cash: str) ->
("Tradier", "A:A 2T:1:145.1"),
("Zerodha", ""),
("Zerodha", "A:A 2T:1:145.1"),
("TDAmeritrade", ""),
("TDAmeritrade", "A:A 2T:1:145.1")])
("CharlesSchwab", ""),
("CharlesSchwab", "A:A 2T:1:145.1")])
def test_cloud_live_deploy_with_live_holdings(brokerage: str, holdings: str) -> None:
if (brokerage == "Interactive Brokers" and sys.platform == "darwin"):
pytest.skip("MacOS does not support IB tests")

create_fake_lean_cli_directory()

cloud_project_manager = mock.Mock()
container.cloud_project_manager = cloud_project_manager
container.cloud_project_manager = mock.Mock(get_cloud_project=mock.Mock(return_value=mock.Mock(projectId=123)))

api_client = mock.Mock()
api_client.auth0.read.return_value = QCAuth0Authorization(
authorization={
"accounts": [
{"id": "123", "name": "123 | Margin | USD"}
]
}
)
api_client.nodes.get_all.return_value = create_qc_nodes()
api_client.get.return_value = {
"status": "stopped",
Expand Down
46 changes: 26 additions & 20 deletions tests/commands/test_live.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@
from unittest import mock

import pytest
import responses
from click.testing import CliRunner

from lean.commands import lean
from lean.constants import DEFAULT_ENGINE_IMAGE
from lean.container import container
from lean.models.docker import DockerImage
from lean.models.json_module import JsonModule
from tests.test_helpers import create_fake_lean_cli_directory, reset_state_installed_modules
from tests.test_helpers import create_fake_lean_cli_directory, reset_state_installed_modules, \
setup_mock_api_client_and_responses
from tests.conftest import initialize_container
from click.testing import Result

Expand Down Expand Up @@ -428,10 +430,8 @@ def test_live_sets_dependent_configurations_from_modules_json_based_on_environme
"tt-order-routing-port": "abc",
"tt-log-fix-messages": "no"
},
"TDAmeritrade": {
"tdameritrade-account-number": "123",
"tdameritrade-api-key": "abc",
"tdameritrade-access-token": "abc",
"CharlesSchwab": {
"charles-schwab-account-number": "123"
},
"Bybit": {
"bybit-api-key": "abc",
Expand All @@ -441,10 +441,6 @@ def test_live_sets_dependent_configurations_from_modules_json_based_on_environme
}
}

brokerage_required_options_not_persistently_save_in_lean_config = {
"TDAmeritrade": ["tdameritrade-access-token"]
}

data_feed_required_options = {
"Interactive Brokers": brokerage_required_options["Interactive Brokers"],
"Tradier": brokerage_required_options["Tradier"],
Expand All @@ -456,7 +452,7 @@ def test_live_sets_dependent_configurations_from_modules_json_based_on_environme
"Samco": brokerage_required_options["Samco"],
"Terminal Link": terminal_link_required_options,
"Kraken": brokerage_required_options["Kraken"],
"TDAmeritrade": brokerage_required_options["TDAmeritrade"],
"CharlesSchwab": brokerage_required_options["CharlesSchwab"],
"Bybit": brokerage_required_options["Bybit"],
}

Expand Down Expand Up @@ -589,13 +585,16 @@ def test_live_non_interactive_aborts_when_missing_data_feed_options(data_feed: s
container.lean_runner.run_lean.assert_not_called()


@responses.activate
@pytest.mark.parametrize("brokerage,data_feed",
itertools.product(brokerage_required_options.keys(), data_feed_required_options.keys()))
def test_live_non_interactive_do_not_store_non_persistent_properties_in_lean_config(brokerage: str, data_feed: str) -> None:
if ((brokerage == "Interactive Brokers" or data_feed == "Interactive Brokers") and sys.platform == "darwin"):
pytest.skip("MacOS does not support IB tests")

create_fake_lean_cli_directory()
container.api_client = setup_mock_api_client_and_responses()

lean_runner = container.lean_runner

options = []
Expand Down Expand Up @@ -630,18 +629,17 @@ def test_live_non_interactive_do_not_store_non_persistent_properties_in_lean_con
{})

config = container.lean_config_manager.get_lean_config()
if brokerage in brokerage_required_options_not_persistently_save_in_lean_config:
for key in brokerage_required_options_not_persistently_save_in_lean_config[brokerage]:
assert key not in config


@responses.activate
@pytest.mark.parametrize("brokerage,data_feed",
itertools.product(brokerage_required_options.keys(), data_feed_required_options.keys()))
def test_live_non_interactive_calls_run_lean_when_all_options_given(brokerage: str, data_feed: str) -> None:
if ((brokerage == "Interactive Brokers" or data_feed == "Interactive Brokers") and sys.platform == "darwin"):
pytest.skip("MacOS does not support IB tests")

create_fake_lean_cli_directory()
container.api_client = setup_mock_api_client_and_responses()
lean_runner = container.lean_runner

options = []
Expand Down Expand Up @@ -675,13 +673,15 @@ def test_live_non_interactive_calls_run_lean_when_all_options_given(brokerage: s
{},
{})

@responses.activate
@pytest.mark.parametrize("brokerage,data_feed1,data_feed2",[(brokerage, *data_feeds) for brokerage, data_feeds in
itertools.product(brokerage_required_options.keys(), itertools.combinations(data_feed_required_options.keys(), 2))])
def test_live_non_interactive_calls_run_lean_when_all_options_given_with_multiple_data_feeds(brokerage: str, data_feed1: str, data_feed2: str) -> None:
if ((brokerage == "Interactive Brokers" or data_feed1 == "Interactive Brokers" or data_feed2 == "Interactive Brokers") and sys.platform == "darwin"):
pytest.skip("MacOS does not support IB tests")

create_fake_lean_cli_directory()
container.api_client = setup_mock_api_client_and_responses()
lean_runner = container.lean_runner

options = []
Expand Down Expand Up @@ -833,12 +833,14 @@ def test_live_non_interactive_falls_back_to_lean_config_for_data_feed_settings(d
{})


@responses.activate
@pytest.mark.parametrize("data_feed1,data_feed2", itertools.combinations(data_feed_required_options.keys(), 2))
def test_live_non_interactive_falls_back_to_lean_config_for_multiple_data_feed_settings(data_feed1: str, data_feed2: str) -> None:
if ((data_feed1 == "Interactive Brokers" or data_feed2 == "Interactive Brokers") and sys.platform == "darwin"):
pytest.skip("MacOS does not support IB tests")

create_fake_lean_cli_directory()
mock_api_client = setup_mock_api_client_and_responses()

required_options = list(data_feed_required_options[data_feed1].items()) + list(data_feed_required_options[data_feed2].items())
if len(required_options) > 8:
Expand All @@ -848,7 +850,7 @@ def test_live_non_interactive_falls_back_to_lean_config_for_multiple_data_feed_s
for current_options in itertools.combinations(required_options, length):
lean_runner = mock.Mock()
# refresh so we assert we are called once
initialize_container(None, lean_runner)
initialize_container(None, lean_runner,api_client_to_use=mock_api_client)

options = []

Expand Down Expand Up @@ -983,6 +985,7 @@ def test_live_passes_custom_python_venv_to_lean_runner_when_given_as_option(pyth
assert "python-venv" not in args[0]


@responses.activate
@pytest.mark.parametrize("brokerage,cash", [("Paper Trading", ""),
("Paper Trading", "USD:100"),
("Paper Trading", "USD:100,EUR:200"),
Expand All @@ -1009,14 +1012,15 @@ def test_live_passes_custom_python_venv_to_lean_runner_when_given_as_option(pyth
("Tradier", "USD:100"),
("Zerodha", ""),
("Zerodha", "USD:100"),
("TDAmeritrade", ""),
("TDAmeritrade", "USD:100")])
("CharlesSchwab", ""),
("CharlesSchwab", "USD:100")])
def test_live_passes_live_cash_balance_to_lean_runner_when_given_as_option(brokerage: str, cash: str) -> None:
if (brokerage == "Interactive Brokers" and sys.platform == "darwin"):
pytest.skip("MacOS does not support IB tests")

create_fake_lean_cli_directory()
lean_runner= container.lean_runner
container.api_client = setup_mock_api_client_and_responses()
lean_runner = container.lean_runner

options = []
required_options = brokerage_required_options[brokerage].items()
Expand Down Expand Up @@ -1051,6 +1055,7 @@ def test_live_passes_live_cash_balance_to_lean_runner_when_given_as_option(broke
assert args[0]["live-cash-balance"] == cash_list


@responses.activate
@pytest.mark.parametrize("brokerage,holdings", [("Paper Trading", ""),
("Paper Trading", "A:A 2T:1:145.1"),
("Paper Trading", "A:A 2T:1:145.1,AA:AA 2T:2:20.35"),
Expand All @@ -1076,14 +1081,15 @@ def test_live_passes_live_cash_balance_to_lean_runner_when_given_as_option(broke
("Tradier", "A:A 2T:1:145.1"),
("Zerodha", ""),
("Zerodha", "A:A 2T:1:145.1"),
("TDAmeritrade", ""),
("TDAmeritrade", "A:A 2T:1:145.1")])
("CharlesSchwab", ""),
("CharlesSchwab", "A:A 2T:1:145.1")])
def test_live_passes_live_holdings_to_lean_runner_when_given_as_option(brokerage: str, holdings: str) -> None:
if (brokerage == "Interactive Brokers" and sys.platform == "darwin"):
pytest.skip("MacOS does not support IB tests")

create_fake_lean_cli_directory()
lean_runner= container.lean_runner
container.api_client = setup_mock_api_client_and_responses()
lean_runner = container.lean_runner

options = []
required_options = brokerage_required_options[brokerage].items()
Expand Down
37 changes: 35 additions & 2 deletions tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@
# limitations under the License.

import json
import responses
from datetime import datetime
from pathlib import Path
from typing import List
from unittest import mock

from lean.constants import DEFAULT_LEAN_DOTNET_FRAMEWORK
from lean.components.util.http_client import HTTPClient
from lean.components.api.api_client import APIClient
from lean.constants import DEFAULT_LEAN_DOTNET_FRAMEWORK, API_BASE_URL
from lean.models.cli import (cli_brokerages, cli_data_downloaders, cli_data_queue_handlers,
cli_addon_modules, cli_history_provider)

Expand Down Expand Up @@ -85,7 +89,9 @@ def _get_lean_config_file_content() -> str:
"data-folder": "data",

// organization-id documentation
"organization-id": "abc"
"organization-id": "abc",

"project-id": 123
}
"""

Expand All @@ -105,6 +111,33 @@ def create_fake_lean_cli_directory() -> None:
_write_fake_directory(files)


def setup_mock_api_client_and_responses() -> APIClient:
"""
Sets up a mock API client and configures a mock response for API calls.

- Creates a mock `APIClient` with test credentials.
- Adds a mock POST response to the `live/auth0/read` endpoint with sample authorization data.

Returns:
APIClient: A mock API client for testing.
"""
api_client = APIClient(mock.Mock(), HTTPClient(mock.Mock()), user_id="123", api_token="abc")
responses.add(
responses.POST,
f"{API_BASE_URL}live/auth0/read",
json={
"authorization": {
"accounts": [
{"id": "123", "name": "123 | Margin | USD"}
]
},
"success": "true"
},
status=200
)
return api_client


def create_fake_lean_cli_project(name: str, language: str) -> None:
"""Creates a directory structure similar to the one created by `lean init` with a given project info"""
(Path.cwd() / "data").mkdir()
Expand Down
Loading