diff --git a/openbb_platform/extensions/tests/utils/integration_tests_api_generator.py b/openbb_platform/extensions/tests/utils/integration_tests_api_generator.py index ff79f4aa278..e07f5246634 100644 --- a/openbb_platform/extensions/tests/utils/integration_tests_api_generator.py +++ b/openbb_platform/extensions/tests/utils/integration_tests_api_generator.py @@ -1,10 +1,11 @@ """Generate API integration tests.""" import argparse import os +from pathlib import Path from typing import Dict, List, Literal, Type, get_type_hints import requests -from openbb_core.app.charting_service import ChartingService +from openbb_charting import Charting from openbb_core.app.provider_interface import ProviderInterface from openbb_core.app.router import CommandMap @@ -159,25 +160,21 @@ def write_commands_integration_tests( def write_charting_extension_integration_tests(): """Write the charting extension integration tests.""" - functions = ChartingService.get_implemented_charting_functions() + import openbb_charting # pylint: disable=import-outside-toplevel - # we assume test file exists - path = os.path.join( - "openbb_platform", - "extensions", - "charting", - "integration", - "test_charting_api.py", - ) + functions = Charting.functions() + + charting_ext_path = Path(openbb_charting.__file__).parent.parent + test_file = charting_ext_path / "integration" / "test_charting_api.py" for function in functions: route = "/" + function.replace("_", "/") - if not test_exists(route=function, path=path): + if not test_exists(route=function, path=test_file): write_test_w_template( http_method="post", params_list=[{"chart": True}], route=route, - path=path, + path=test_file, chart=True, ) diff --git a/openbb_platform/extensions/tests/utils/integration_tests_generator.py b/openbb_platform/extensions/tests/utils/integration_tests_generator.py index cffe91bac76..36b4de9135c 100644 --- a/openbb_platform/extensions/tests/utils/integration_tests_generator.py +++ b/openbb_platform/extensions/tests/utils/integration_tests_generator.py @@ -13,7 +13,7 @@ from typing import ( get_type_hints, ) -from openbb_core.app.charting_service import ChartingService +from openbb_charting import Charting from openbb_core.app.provider_interface import ProviderInterface from openbb_core.app.router import CommandMap from pydantic.fields import FieldInfo @@ -278,7 +278,7 @@ def write_charting_extension_integration_tests(): """Write charting extension integration tests.""" import openbb_charting # pylint: disable=import-outside-toplevel - functions = ChartingService.get_implemented_charting_functions() + functions = Charting.functions() charting_ext_path = Path(openbb_charting.__file__).parent.parent test_file = charting_ext_path / "integration" / "test_charting_python.py" @@ -305,15 +305,15 @@ if __name__ == "__main__": parser.add_argument( "--charting", dest="charting", - default=True, - action="store_false", + default=False, + action="store_true", help="Generate charting extension integration tests", ) parser.add_argument( "--commands", dest="commands", - default=True, - action="store_false", + default=False, + action="store_true", help="Generate commands integration tests", ) diff --git a/openbb_platform/obbject_extensions/charting/integration/test_charting_api.py b/openbb_platform/obbject_extensions/charting/integration/test_charting_api.py new file mode 100644 index 00000000000..15ea8decc1c --- /dev/null +++ b/openbb_platform/obbject_extensions/charting/integration/test_charting_api.py @@ -0,0 +1,404 @@ +import base64 +import json + +import pytest +import requests +from extensions.tests.conftest import parametrize +from openbb_core.env import Env +from openbb_core.provider.utils.helpers import get_querystring + + +@pytest.fixture(scope="session") +def headers(): + """Headers fixture.""" + return get_headers() + + +# pylint:disable=redefined-outer-name + +data: dict = {} + + +def get_headers(): + """Get headers for requests.""" + if "headers" in data: + return data["headers"] + + userpass = f"{Env().API_USERNAME}:{Env().API_PASSWORD}" + userpass_bytes = userpass.encode("ascii") + base64_bytes = base64.b64encode(userpass_bytes) + + data["headers"] = {"Authorization": f"Basic {base64_bytes.decode('ascii')}"} + return data["headers"] + + +def get_equity_data(): + """Get equity data.""" + if "stocks_data" in data: + return data["stocks_data"] + + url = "http://0.0.0.0:8000/api/v1/equity/price/historical?symbol=AAPL&provider=fmp" + result = requests.get(url, headers=get_headers(), timeout=10) + data["stocks_data"] = result.json()["results"] + + return data["stocks_data"] + + +@parametrize( + "params", + [ + ( + { + "provider": "fmp", + "symbol": "AAPL", + "chart": True, + } + ), + ], +) +@pytest.mark.integration +def test_chart_equity_price_historical(params, headers): + """Test chart equity load.""" + params = {p: v for p, v in params.items() if v} + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/equity/price/historical?{query_str}" + result = requests.get(url, headers=headers, timeout=40) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [({"symbol": "AAPL", "limit": 100, "chart": True})], +) +@pytest.mark.integration +def test_chart_equity_fundamental_multiples(params, headers): + """Test chart equity multiples.""" + params = {p: v for p, v in params.items() if v} + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/equity/fundamental/multiples?{query_str}" + result = requests.get(url, headers=headers, timeout=10) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [ + ( + { + "data": "", + "index": "date", + "length": "60", + "scalar": "90.0", + "drift": "2", + "chart": True, + } + ) + ], +) +@pytest.mark.integration +def test_chart_technical_adx(params, headers): + """Test chart ta adx.""" + params = {p: v for p, v in params.items() if v} + body = json.dumps(get_equity_data()) + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/technical/adx?{query_str}" + result = requests.post(url, headers=headers, timeout=10, data=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [({"data": "", "index": "date", "length": "30", "scalar": "110", "chart": True})], +) +@pytest.mark.integration +def test_chart_technical_aroon(params, headers): + """Test chart ta aroon.""" + params = {p: v for p, v in params.items() if v} + body = json.dumps(get_equity_data()) + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/technical/aroon?{query_str}" + result = requests.post(url, headers=headers, timeout=10, data=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "", + "length": "60", + "offset": "10", + "chart": True, + } + ) + ], +) +@pytest.mark.integration +def test_chart_technical_ema(params, headers): + """Test chart ta ema.""" + params = {p: v for p, v in params.items() if v} + body = json.dumps(get_equity_data()) + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/technical/ema?{query_str}" + result = requests.post(url, headers=headers, timeout=10, data=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "55", + "offset": "2", + "chart": True, + } + ) + ], +) +@pytest.mark.integration +def test_chart_technical_hma(params, headers): + """Test chart ta hma.""" + params = {p: v for p, v in params.items() if v} + body = json.dumps(get_equity_data()) + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/technical/hma?{query_str}" + result = requests.post(url, headers=headers, timeout=10, data=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "fast": "10", + "slow": "30", + "signal": "10", + "chart": True, + } + ) + ], +) +@pytest.mark.integration +def test_chart_technical_macd(params, headers): + """Test chart ta macd.""" + params = {p: v for p, v in params.items() if v} + body = json.dumps(get_equity_data()) + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/technical/macd?{query_str}" + result = requests.post(url, headers=headers, timeout=10, data=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "16", + "scalar": "90.0", + "drift": "2", + "chart": True, + } + ) + ], +) +@pytest.mark.integration +def test_chart_technical_rsi(params, headers): + """Test chart ta rsi.""" + params = {p: v for p, v in params.items() if v} + body = json.dumps(get_equity_data()) + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/technical/rsi?{query_str}" + result = requests.post(url, headers=headers, timeout=10, data=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "55", + "offset": "2", + "chart": True, + } + ) + ], +) +@pytest.mark.integration +def test_chart_technical_sma(params, headers): + """Test chart ta sma.""" + params = {p: v for p, v in params.items() if v} + body = json.dumps(get_equity_data()) + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/technical/sma?{query_str}" + result = requests.post(url, headers=headers, timeout=10, data=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "60", + "offset": "10", + "chart": True, + } + ) + ], +) +@pytest.mark.integration +def test_chart_technical_wma(params, headers): + """Test chart ta wma.""" + params = {p: v for p, v in params.items() if v} + body = json.dumps(get_equity_data()) + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/technical/wma?{query_str}" + result = requests.post(url, headers=headers, timeout=10, data=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "55", + "offset": "5", + "chart": True, + } + ) + ], +) +@pytest.mark.integration +def test_chart_technical_zlma(params, headers): + """Test chart ta zlma.""" + params = {p: v for p, v in params.items() if v} + body = json.dumps(get_equity_data()) + + query_str = get_querystring(params, []) + url = f"http://0.0.0.0:8000/api/v1/technical/zlma?{query_str}" + result = requests.post(url, headers=headers, timeout=10, data=body) + assert isinstance(result, requests.Response) + assert result.status_code == 200 + + chart = result.json()["chart"] + fig = chart.pop("fig", {}) + + assert chart + assert not fig + assert list(chart.keys()) == ["content", "format"] diff --git a/openbb_platform/obbject_extensions/charting/integration/test_charting_python.py b/openbb_platform/obbject_extensions/charting/integration/test_charting_python.py new file mode 100644 index 00000000000..90bc88151b2 --- /dev/null +++ b/openbb_platform/obbject_extensions/charting/integration/test_charting_python.py @@ -0,0 +1,350 @@ +"""Test charting extension.""" + +import pytest +from extensions.tests.conftest import parametrize +from openbb_charting.core.openbb_figure import OpenBBFigure +from openbb_core.app.model.obbject import OBBject + + +# pylint:disable=inconsistent-return-statements +@pytest.fixture(scope="session") +def obb(pytestconfig): + """Fixture to setup obb.""" + if pytestconfig.getoption("markexpr") != "not integration": + import openbb # pylint:disable=import-outside-toplevel + + return openbb.obb + + +# pylint:disable=redefined-outer-name + +data: dict = {} + + +def get_equity_data(): + """Get equity data.""" + import openbb # pylint:disable=import-outside-toplevel + + if "stocks_data" in data: + return data["stocks_data"] + + symbol = "AAPL" + provider = "fmp" + + data["stocks_data"] = openbb.obb.equity.price.historical( + symbol=symbol, provider=provider + ).results + return data["stocks_data"] + + +@parametrize( + "params", + [ + ( + { + "provider": "fmp", + "symbol": "AAPL", + "chart": True, + } + ), + ], +) +@pytest.mark.integration +def test_chart_equity_price_historical(params, obb): + """Test chart equity price historical.""" + result = obb.equity.price.historical(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ({"symbol": "AAPL", "limit": 100, "chart": "True"}), + ], +) +@pytest.mark.integration +def test_chart_equity_fundamental_multiples(params, obb): + """Test chart equity multiples.""" + params = {p: v for p, v in params.items() if v} + + result = obb.equity.fundamental.multiples(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "data": "", + "index": "date", + "length": "60", + "scalar": "90.0", + "drift": "2", + "chart": "True", + } + ), + ], +) +@pytest.mark.integration +def test_chart_technical_adx(params, obb): + """Test chart ta adx.""" + params = {p: v for p, v in params.items() if v} + + params["data"] = get_equity_data() + + result = obb.technical.adx(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "data": "", + "index": "date", + "length": "30", + "scalar": "110", + "chart": "True", + } + ), + ], +) +@pytest.mark.integration +def test_chart_technical_aroon(params, obb): + """Test chart ta aroon.""" + params = {p: v for p, v in params.items() if v} + + params["data"] = get_equity_data() + + result = obb.technical.aroon(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "", + "length": "60", + "offset": "10", + "chart": "True", + } + ), + ], +) +@pytest.mark.integration +def test_chart_technical_ema(params, obb): + """Test chart ta ema.""" + params = {p: v for p, v in params.items() if v} + + params["data"] = get_equity_data() + + result = obb.technical.ema(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "55", + "offset": "2", + "chart": "True", + } + ), + ], +) +@pytest.mark.integration +def test_chart_technical_hma(params, obb): + """Test chart ta hma.""" + params = {p: v for p, v in params.items() if v} + + params["data"] = get_equity_data() + + result = obb.technical.hma(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "fast": "10", + "slow": "30", + "signal": "10", + "chart": "True", + } + ), + ], +) +@pytest.mark.integration +def test_chart_technical_macd(params, obb): + """Test chart ta macd.""" + params = {p: v for p, v in params.items() if v} + + params["data"] = get_equity_data() + + result = obb.technical.macd(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "16", + "scalar": "90.0", + "drift": "2", + "chart": "True", + } + ), + ], +) +@pytest.mark.integration +def test_chart_technical_rsi(params, obb): + """Test chart ta rsi.""" + params = {p: v for p, v in params.items() if v} + + params["data"] = get_equity_data() + + result = obb.technical.rsi(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "55", + "offset": "2", + "chart": "True", + } + ), + ], +) +@pytest.mark.integration +def test_chart_technical_sma(params, obb): + """Test chart ta sma.""" + params = {p: v for p, v in params.items() if v} + + params["data"] = get_equity_data() + + result = obb.technical.sma(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "60", + "offset": "10", + "chart": "True", + } + ), + ], +) +@pytest.mark.integration +def test_chart_technical_wma(params, obb): + """Test chart ta wma.""" + params = {p: v for p, v in params.items() if v} + + params["data"] = get_equity_data() + + result = obb.technical.wma(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure) + + +@parametrize( + "params", + [ + ( + { + "data": "", + "target": "high", + "index": "date", + "length": "55", + "offset": "5", + "chart": "True", + } + ), + ], +) +@pytest.mark.integration +def test_chart_technical_zlma(params, obb): + """Test chart ta zlma.""" + params = {p: v for p, v in params.items() if v} + + params["data"] = get_equity_data() + + result = obb.technical.zlma(**params) + assert result + assert isinstance(result, OBBject) + assert len(result.results) > 0 + assert result.chart.content + assert isinstance(result.chart.fig, OpenBBFigure)