lib-x17-fintech 2.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lib_x17_fintech-2.1.3.dist-info/METADATA +633 -0
- lib_x17_fintech-2.1.3.dist-info/RECORD +282 -0
- lib_x17_fintech-2.1.3.dist-info/WHEEL +5 -0
- lib_x17_fintech-2.1.3.dist-info/licenses/LICENSE +1 -0
- lib_x17_fintech-2.1.3.dist-info/top_level.txt +1 -0
- xfintech/__init__.py +0 -0
- xfintech/connect/__init__.py +18 -0
- xfintech/connect/artifact/__init__.py +5 -0
- xfintech/connect/artifact/artifact.py +168 -0
- xfintech/connect/artifact/tests/__init__.py +3 -0
- xfintech/connect/artifact/tests/test_class_artifact_all.py +564 -0
- xfintech/connect/common/__init__.py +12 -0
- xfintech/connect/common/connect.py +49 -0
- xfintech/connect/common/connectref.py +119 -0
- xfintech/connect/common/error.py +62 -0
- xfintech/connect/common/tests/__init__.py +1 -0
- xfintech/connect/common/tests/test_class_connectlike_all.py +544 -0
- xfintech/connect/common/tests/test_class_connectref_all.py +586 -0
- xfintech/connect/common/tests/test_class_errors_all.py +524 -0
- xfintech/connect/instance/__init__.py +7 -0
- xfintech/connect/instance/macos.py +121 -0
- xfintech/connect/instance/s3.py +176 -0
- xfintech/connect/instance/tests/__init__.py +1 -0
- xfintech/connect/instance/tests/test_class_macosconnect_all.py +692 -0
- xfintech/connect/instance/tests/test_class_s3connect_all.py +603 -0
- xfintech/data/__init__.py +20 -0
- xfintech/data/common/__init__.py +15 -0
- xfintech/data/common/cache.py +186 -0
- xfintech/data/common/coolant.py +171 -0
- xfintech/data/common/metric.py +138 -0
- xfintech/data/common/paginate.py +132 -0
- xfintech/data/common/params.py +162 -0
- xfintech/data/common/retry.py +201 -0
- xfintech/data/common/tests/__init__.py +1 -0
- xfintech/data/common/tests/test_class_cache_all.py +681 -0
- xfintech/data/common/tests/test_class_coolant_all.py +534 -0
- xfintech/data/common/tests/test_class_metric_all.py +705 -0
- xfintech/data/common/tests/test_class_paginate_all.py +508 -0
- xfintech/data/common/tests/test_class_params_all.py +891 -0
- xfintech/data/common/tests/test_class_retry_all.py +714 -0
- xfintech/data/job/__init__.py +17 -0
- xfintech/data/job/errors.py +112 -0
- xfintech/data/job/house.py +156 -0
- xfintech/data/job/job.py +247 -0
- xfintech/data/job/joblike.py +47 -0
- xfintech/data/job/tests/__init__.py +1 -0
- xfintech/data/job/tests/test_class_errors_all.py +275 -0
- xfintech/data/job/tests/test_class_house_all.py +801 -0
- xfintech/data/job/tests/test_class_job_all.py +684 -0
- xfintech/data/job/tests/test_class_joblike_all.py +482 -0
- xfintech/data/relay/__init__.py +7 -0
- xfintech/data/relay/client.py +114 -0
- xfintech/data/relay/clientlike.py +45 -0
- xfintech/data/relay/tests/test_class_relayclient_all.py +484 -0
- xfintech/data/relay/tests/test_class_relayclientlike_all.py +500 -0
- xfintech/data/source/__init__.py +7 -0
- xfintech/data/source/baostock/__init__.py +21 -0
- xfintech/data/source/baostock/job/__init__.py +5 -0
- xfintech/data/source/baostock/job/job.py +217 -0
- xfintech/data/source/baostock/job/tests/__init__.py +0 -0
- xfintech/data/source/baostock/job/tests/test_class_baostockjob_all.py +547 -0
- xfintech/data/source/baostock/session/__init__.py +8 -0
- xfintech/data/source/baostock/session/relay.py +223 -0
- xfintech/data/source/baostock/session/session.py +241 -0
- xfintech/data/source/baostock/session/tests/__init__.py +0 -0
- xfintech/data/source/baostock/session/tests/test_class_relay_all.py +694 -0
- xfintech/data/source/baostock/session/tests/test_class_session_all.py +505 -0
- xfintech/data/source/baostock/stock/__init__.py +0 -0
- xfintech/data/source/baostock/stock/hs300stock/__init__.py +3 -0
- xfintech/data/source/baostock/stock/hs300stock/constant.py +49 -0
- xfintech/data/source/baostock/stock/hs300stock/hs300stock.py +133 -0
- xfintech/data/source/baostock/stock/hs300stock/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/hs300stock/tests/test_class_hs300index_all.py +413 -0
- xfintech/data/source/baostock/stock/minuteline/__init__.py +19 -0
- xfintech/data/source/baostock/stock/minuteline/constant.py +89 -0
- xfintech/data/source/baostock/stock/minuteline/minuteline.py +163 -0
- xfintech/data/source/baostock/stock/minuteline/tests/__init__.py +0 -0
- xfintech/data/source/baostock/stock/minuteline/tests/test_class_minuteline_all.py +582 -0
- xfintech/data/source/baostock/stock/stock/__init__.py +19 -0
- xfintech/data/source/baostock/stock/stock/constant.py +55 -0
- xfintech/data/source/baostock/stock/stock/stock.py +149 -0
- xfintech/data/source/baostock/stock/stock/tests/__init__.py +0 -0
- xfintech/data/source/baostock/stock/stock/tests/test_class_stock_all.py +508 -0
- xfintech/data/source/baostock/stock/stockinfo/__init__.py +5 -0
- xfintech/data/source/baostock/stock/stockinfo/constant.py +66 -0
- xfintech/data/source/baostock/stock/stockinfo/stockinfo.py +176 -0
- xfintech/data/source/baostock/stock/stockinfo/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/stockinfo/tests/test_class_stockinfo_all.py +617 -0
- xfintech/data/source/baostock/stock/sz50stock/__init__.py +3 -0
- xfintech/data/source/baostock/stock/sz50stock/constant.py +49 -0
- xfintech/data/source/baostock/stock/sz50stock/sz50stock.py +133 -0
- xfintech/data/source/baostock/stock/sz50stock/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/sz50stock/tests/test_class_sz50stock_all.py +397 -0
- xfintech/data/source/baostock/stock/tradedate/__init__.py +19 -0
- xfintech/data/source/baostock/stock/tradedate/constant.py +72 -0
- xfintech/data/source/baostock/stock/tradedate/tests/__init__.py +0 -0
- xfintech/data/source/baostock/stock/tradedate/tests/test_class_tradedate_all.py +695 -0
- xfintech/data/source/baostock/stock/tradedate/tradedate.py +208 -0
- xfintech/data/source/baostock/stock/zz500stock/__init__.py +3 -0
- xfintech/data/source/baostock/stock/zz500stock/constant.py +55 -0
- xfintech/data/source/baostock/stock/zz500stock/tests/__init__.py +1 -0
- xfintech/data/source/baostock/stock/zz500stock/tests/test_class_zz500stock_all.py +421 -0
- xfintech/data/source/baostock/stock/zz500stock/zz500stock.py +133 -0
- xfintech/data/source/tushare/__init__.py +61 -0
- xfintech/data/source/tushare/job/__init__.py +5 -0
- xfintech/data/source/tushare/job/job.py +257 -0
- xfintech/data/source/tushare/job/tests/test_class_tusharejob_all.py +589 -0
- xfintech/data/source/tushare/session/__init__.py +5 -0
- xfintech/data/source/tushare/session/relay.py +231 -0
- xfintech/data/source/tushare/session/session.py +239 -0
- xfintech/data/source/tushare/session/tests/test_class_relay_all.py +719 -0
- xfintech/data/source/tushare/session/tests/test_class_session_all.py +705 -0
- xfintech/data/source/tushare/stock/__init__.py +55 -0
- xfintech/data/source/tushare/stock/adjfactor/__init__.py +19 -0
- xfintech/data/source/tushare/stock/adjfactor/adjfactor.py +150 -0
- xfintech/data/source/tushare/stock/adjfactor/constant.py +71 -0
- xfintech/data/source/tushare/stock/adjfactor/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/adjfactor/tests/test_class_adjfactor_all.py +372 -0
- xfintech/data/source/tushare/stock/capflow/__init__.py +19 -0
- xfintech/data/source/tushare/stock/capflow/capflow.py +171 -0
- xfintech/data/source/tushare/stock/capflow/constant.py +105 -0
- xfintech/data/source/tushare/stock/capflow/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/capflow/tests/test_class_capflow_all.py +589 -0
- xfintech/data/source/tushare/stock/capflowdc/__init__.py +19 -0
- xfintech/data/source/tushare/stock/capflowdc/capflowdc.py +167 -0
- xfintech/data/source/tushare/stock/capflowdc/constant.py +95 -0
- xfintech/data/source/tushare/stock/capflowdc/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/capflowdc/tests/test_class_capflowdc_all.py +814 -0
- xfintech/data/source/tushare/stock/capflowths/__init__.py +19 -0
- xfintech/data/source/tushare/stock/capflowths/capflowths.py +173 -0
- xfintech/data/source/tushare/stock/capflowths/constant.py +92 -0
- xfintech/data/source/tushare/stock/capflowths/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/capflowths/tests/test_class_capflowths_all.py +551 -0
- xfintech/data/source/tushare/stock/company/__init__.py +19 -0
- xfintech/data/source/tushare/stock/company/company.py +188 -0
- xfintech/data/source/tushare/stock/company/constant.py +92 -0
- xfintech/data/source/tushare/stock/company/tests/__init__.py +1 -0
- xfintech/data/source/tushare/stock/company/tests/test_class_company_all.py +829 -0
- xfintech/data/source/tushare/stock/companybusiness/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companybusiness/companybusiness.py +183 -0
- xfintech/data/source/tushare/stock/companybusiness/constant.py +91 -0
- xfintech/data/source/tushare/stock/companybusiness/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companybusiness/tests/test_class_companybusiness_all.py +633 -0
- xfintech/data/source/tushare/stock/companycashflow/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companycashflow/companycashflow.py +277 -0
- xfintech/data/source/tushare/stock/companycashflow/constant.py +293 -0
- xfintech/data/source/tushare/stock/companycashflow/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companycashflow/tests/test_class_companycashflow_all.py +619 -0
- xfintech/data/source/tushare/stock/companydebt/__init__.py +19 -0
- xfintech/data/source/tushare/stock/companydebt/companydebt.py +339 -0
- xfintech/data/source/tushare/stock/companydebt/constant.py +403 -0
- xfintech/data/source/tushare/stock/companydebt/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companydebt/tests/test_class_companydebt_all.py +655 -0
- xfintech/data/source/tushare/stock/companyoverview/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companyoverview/companyoverview.py +214 -0
- xfintech/data/source/tushare/stock/companyoverview/constant.py +152 -0
- xfintech/data/source/tushare/stock/companyoverview/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companyoverview/tests/test_class_companyoverview_all.py +647 -0
- xfintech/data/source/tushare/stock/companyprofit/__init__.py +21 -0
- xfintech/data/source/tushare/stock/companyprofit/companyprofit.py +272 -0
- xfintech/data/source/tushare/stock/companyprofit/constant.py +259 -0
- xfintech/data/source/tushare/stock/companyprofit/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/companyprofit/tests/test_class_companyprofit_all.py +635 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/__init__.py +21 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/conceptcapflowdc.py +175 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/constant.py +106 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/conceptcapflowdc/tests/test_class_conceptcapflowdc_all.py +568 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/__init__.py +21 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/conceptcapflowths.py +188 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/constant.py +89 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/conceptcapflowths/tests/test_class_conceptcapflowths_all.py +516 -0
- xfintech/data/source/tushare/stock/dayline/__init__.py +19 -0
- xfintech/data/source/tushare/stock/dayline/constant.py +87 -0
- xfintech/data/source/tushare/stock/dayline/dayline.py +177 -0
- xfintech/data/source/tushare/stock/dayline/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/dayline/tests/test_class_dayline_all.py +585 -0
- xfintech/data/source/tushare/stock/industrycapflowths/__init__.py +21 -0
- xfintech/data/source/tushare/stock/industrycapflowths/constant.py +89 -0
- xfintech/data/source/tushare/stock/industrycapflowths/industrycapflowths.py +192 -0
- xfintech/data/source/tushare/stock/industrycapflowths/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/industrycapflowths/tests/test_class_industrycapflowths_all.py +683 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/__init__.py +21 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/constant.py +90 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/marketindexcapflowdc.py +173 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/marketindexcapflowdc/tests/test_class_marketindexcapflowdc_all.py +793 -0
- xfintech/data/source/tushare/stock/monthline/__init__.py +19 -0
- xfintech/data/source/tushare/stock/monthline/constant.py +87 -0
- xfintech/data/source/tushare/stock/monthline/monthline.py +180 -0
- xfintech/data/source/tushare/stock/monthline/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/monthline/tests/test_class_monthline_all.py +574 -0
- xfintech/data/source/tushare/stock/stock/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stock/constant.py +105 -0
- xfintech/data/source/tushare/stock/stock/stock.py +193 -0
- xfintech/data/source/tushare/stock/stock/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stock/tests/test_class_stock_all.py +788 -0
- xfintech/data/source/tushare/stock/stockdividend/__init__.py +21 -0
- xfintech/data/source/tushare/stock/stockdividend/constant.py +111 -0
- xfintech/data/source/tushare/stock/stockdividend/stockdividend.py +180 -0
- xfintech/data/source/tushare/stock/stockdividend/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockdividend/tests/test_class_stockdividend_all.py +725 -0
- xfintech/data/source/tushare/stock/stockinfo/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockinfo/constant.py +104 -0
- xfintech/data/source/tushare/stock/stockinfo/stockinfo.py +208 -0
- xfintech/data/source/tushare/stock/stockinfo/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockinfo/tests/test_class_stockinfo_all.py +881 -0
- xfintech/data/source/tushare/stock/stockipo/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockipo/constant.py +90 -0
- xfintech/data/source/tushare/stock/stockipo/stockipo.py +234 -0
- xfintech/data/source/tushare/stock/stockipo/tests/__init__.py +1 -0
- xfintech/data/source/tushare/stock/stockipo/tests/test_class_stockipo_all.py +750 -0
- xfintech/data/source/tushare/stock/stockpledge/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockpledge/constant.py +72 -0
- xfintech/data/source/tushare/stock/stockpledge/stockpledge.py +158 -0
- xfintech/data/source/tushare/stock/stockpledge/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockpledge/tests/test_class_stockpledge_all.py +664 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/__init__.py +21 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/constant.py +85 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/stockpledgedetail.py +171 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockpledgedetail/tests/test_class_stockpledgedetail_all.py +112 -0
- xfintech/data/source/tushare/stock/stockst/__init__.py +19 -0
- xfintech/data/source/tushare/stock/stockst/constant.py +80 -0
- xfintech/data/source/tushare/stock/stockst/stockst.py +189 -0
- xfintech/data/source/tushare/stock/stockst/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stockst/tests/test_class_stockst_all.py +693 -0
- xfintech/data/source/tushare/stock/stocksuspend/__init__.py +21 -0
- xfintech/data/source/tushare/stock/stocksuspend/constant.py +75 -0
- xfintech/data/source/tushare/stock/stocksuspend/stocksuspend.py +151 -0
- xfintech/data/source/tushare/stock/stocksuspend/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/stocksuspend/tests/test_class_stocksuspend_all.py +626 -0
- xfintech/data/source/tushare/stock/techindex/__init__.py +19 -0
- xfintech/data/source/tushare/stock/techindex/constant.py +600 -0
- xfintech/data/source/tushare/stock/techindex/techindex.py +314 -0
- xfintech/data/source/tushare/stock/techindex/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/techindex/tests/test_class_techindex_all.py +576 -0
- xfintech/data/source/tushare/stock/tradedate/__init__.py +19 -0
- xfintech/data/source/tushare/stock/tradedate/constant.py +93 -0
- xfintech/data/source/tushare/stock/tradedate/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/tradedate/tests/test_class_tradedate_all.py +947 -0
- xfintech/data/source/tushare/stock/tradedate/tradedate.py +234 -0
- xfintech/data/source/tushare/stock/weekline/__init__.py +19 -0
- xfintech/data/source/tushare/stock/weekline/constant.py +87 -0
- xfintech/data/source/tushare/stock/weekline/tests/__init__.py +0 -0
- xfintech/data/source/tushare/stock/weekline/tests/test_class_weekline_all.py +575 -0
- xfintech/data/source/tushare/stock/weekline/weekline.py +182 -0
- xfintech/fabric/__init__.py +18 -0
- xfintech/fabric/column/__init__.py +7 -0
- xfintech/fabric/column/info.py +202 -0
- xfintech/fabric/column/kind.py +102 -0
- xfintech/fabric/column/tests/__init__.py +0 -0
- xfintech/fabric/column/tests/test_class_info_all.py +207 -0
- xfintech/fabric/column/tests/test_class_kind_all.py +80 -0
- xfintech/fabric/table/__init__.py +5 -0
- xfintech/fabric/table/info.py +263 -0
- xfintech/fabric/table/tests/__init__.py +0 -0
- xfintech/fabric/table/tests/test_class_info_all.py +547 -0
- xfintech/serde/__init__.py +35 -0
- xfintech/serde/common/__init__.py +9 -0
- xfintech/serde/common/dataformat.py +78 -0
- xfintech/serde/common/deserialiserlike.py +38 -0
- xfintech/serde/common/error.py +182 -0
- xfintech/serde/common/serialiserlike.py +38 -0
- xfintech/serde/common/tests/__init__.py +1 -0
- xfintech/serde/common/tests/test_class_dataformat_all.py +694 -0
- xfintech/serde/common/tests/test_class_deserialiserlike_all.py +500 -0
- xfintech/serde/common/tests/test_class_errors_all.py +518 -0
- xfintech/serde/common/tests/test_class_serialiserlike_all.py +401 -0
- xfintech/serde/deserialiser/__init__.py +7 -0
- xfintech/serde/deserialiser/pandas.py +113 -0
- xfintech/serde/deserialiser/python.py +68 -0
- xfintech/serde/deserialiser/tests/__init__.py +1 -0
- xfintech/serde/deserialiser/tests/test_class_pandasdeserialiser_all.py +503 -0
- xfintech/serde/deserialiser/tests/test_class_pythondeserialiser_all.py +570 -0
- xfintech/serde/serialiser/__init__.py +7 -0
- xfintech/serde/serialiser/pandas.py +116 -0
- xfintech/serde/serialiser/python.py +71 -0
- xfintech/serde/serialiser/tests/__init__.py +1 -0
- xfintech/serde/serialiser/tests/test_class_pandasserialiser_all.py +474 -0
- xfintech/serde/serialiser/tests/test_class_pythonserialiser_all.py +508 -0
|
@@ -0,0 +1,547 @@
|
|
|
1
|
+
from datetime import date, datetime
|
|
2
|
+
from unittest.mock import Mock
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from xfintech.data.common.cache import Cache
|
|
8
|
+
from xfintech.data.common.coolant import Coolant
|
|
9
|
+
from xfintech.data.common.paginate import Paginate
|
|
10
|
+
from xfintech.data.common.params import Params
|
|
11
|
+
from xfintech.data.common.retry import Retry
|
|
12
|
+
from xfintech.data.source.baostock.job.job import BaostockJob
|
|
13
|
+
from xfintech.data.source.baostock.session.session import Session
|
|
14
|
+
|
|
15
|
+
# ============================================================================
|
|
16
|
+
# Helper Classes for Testing
|
|
17
|
+
# ============================================================================
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ConcreteBaostockJob(BaostockJob):
|
|
21
|
+
"""Concrete implementation for testing"""
|
|
22
|
+
|
|
23
|
+
def _run(self) -> pd.DataFrame:
|
|
24
|
+
return pd.DataFrame({"test": [1, 2, 3]})
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FetchAllJob(BaostockJob):
|
|
28
|
+
"""Job that uses _fetchall in _run"""
|
|
29
|
+
|
|
30
|
+
def _run(self) -> pd.DataFrame:
|
|
31
|
+
api = Mock(return_value=pd.DataFrame({"data": [1, 2, 3]}))
|
|
32
|
+
return self._fetchall(api, code="sh.600000")
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# ============================================================================
|
|
36
|
+
# Initialization Tests
|
|
37
|
+
# ============================================================================
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_baostockjob_init_basic():
|
|
41
|
+
"""Test BaostockJob basic initialization"""
|
|
42
|
+
mock_session = Mock(spec=Session)
|
|
43
|
+
mock_session.connection = Mock()
|
|
44
|
+
|
|
45
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
46
|
+
|
|
47
|
+
assert job.name == "test_job"
|
|
48
|
+
assert job.key == "test_key"
|
|
49
|
+
assert job.connection is not None
|
|
50
|
+
assert isinstance(job.params, Params)
|
|
51
|
+
assert isinstance(job.coolant, Coolant)
|
|
52
|
+
assert isinstance(job.paginate, Paginate)
|
|
53
|
+
assert isinstance(job.retry, Retry)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_baostockjob_init_with_params():
|
|
57
|
+
"""Test BaostockJob initialization with params dict"""
|
|
58
|
+
mock_session = Mock(spec=Session)
|
|
59
|
+
mock_session.connection = Mock()
|
|
60
|
+
|
|
61
|
+
job = ConcreteBaostockJob(
|
|
62
|
+
name="test_job", key="test_key", session=mock_session, params={"code": "sh.600000", "start_date": "2024-01-01"}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
assert job.params.to_dict()["code"] == "sh.600000"
|
|
66
|
+
assert job.params.to_dict()["start_date"] == "2024-01-01"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_baostockjob_init_with_params_object():
|
|
70
|
+
"""Test BaostockJob initialization with Params object"""
|
|
71
|
+
mock_session = Mock(spec=Session)
|
|
72
|
+
mock_session.connection = Mock()
|
|
73
|
+
params = Params(code="sh.600000", frequency="5")
|
|
74
|
+
|
|
75
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, params=params)
|
|
76
|
+
|
|
77
|
+
assert job.params is params
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_baostockjob_init_with_coolant_dict():
|
|
81
|
+
"""Test BaostockJob initialization with coolant dict"""
|
|
82
|
+
mock_session = Mock(spec=Session)
|
|
83
|
+
mock_session.connection = Mock()
|
|
84
|
+
|
|
85
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, coolant={"wait": 0.5})
|
|
86
|
+
|
|
87
|
+
# Coolant stores wait time, not interval
|
|
88
|
+
assert isinstance(job.coolant, Coolant)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def test_baostockjob_init_with_paginate_dict():
|
|
92
|
+
"""Test BaostockJob initialization with paginate dict"""
|
|
93
|
+
mock_session = Mock(spec=Session)
|
|
94
|
+
mock_session.connection = Mock()
|
|
95
|
+
|
|
96
|
+
job = ConcreteBaostockJob(
|
|
97
|
+
name="test_job", key="test_key", session=mock_session, paginate={"pagesize": 100, "pagelimit": 1000}
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
assert job.paginate.pagesize == 100
|
|
101
|
+
assert job.paginate.pagelimit == 1000
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_baostockjob_init_with_retry_dict():
|
|
105
|
+
"""Test BaostockJob initialization with retry dict"""
|
|
106
|
+
mock_session = Mock(spec=Session)
|
|
107
|
+
mock_session.connection = Mock()
|
|
108
|
+
|
|
109
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, retry={"retry": 3, "wait": 1.0})
|
|
110
|
+
|
|
111
|
+
assert job.retry.retry == 3
|
|
112
|
+
assert job.retry.wait == 1.0
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_baostockjob_init_with_cache_true():
|
|
116
|
+
"""Test BaostockJob initialization with cache enabled"""
|
|
117
|
+
mock_session = Mock(spec=Session)
|
|
118
|
+
mock_session.connection = Mock()
|
|
119
|
+
|
|
120
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=True)
|
|
121
|
+
|
|
122
|
+
assert job.cache is not None
|
|
123
|
+
assert isinstance(job.cache, Cache)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_baostockjob_init_with_cache_false():
|
|
127
|
+
"""Test BaostockJob initialization with cache disabled"""
|
|
128
|
+
mock_session = Mock(spec=Session)
|
|
129
|
+
mock_session.connection = Mock()
|
|
130
|
+
|
|
131
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=False)
|
|
132
|
+
|
|
133
|
+
assert job.cache is None
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def test_baostockjob_init_marks_checkpoints():
|
|
137
|
+
"""Test BaostockJob marks initialization checkpoints"""
|
|
138
|
+
mock_session = Mock(spec=Session)
|
|
139
|
+
mock_session.connection = Mock()
|
|
140
|
+
|
|
141
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
142
|
+
|
|
143
|
+
# Should have marked _resolve_connection[OK]
|
|
144
|
+
marks = job.metric.marks
|
|
145
|
+
assert "_resolve_connection[OK]" in marks
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# ============================================================================
|
|
149
|
+
# Connection Resolution Tests
|
|
150
|
+
# ============================================================================
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_resolve_connection_success():
|
|
154
|
+
"""Test successful connection resolution"""
|
|
155
|
+
mock_session = Mock(spec=Session)
|
|
156
|
+
mock_connection = Mock()
|
|
157
|
+
mock_session.connection = mock_connection
|
|
158
|
+
|
|
159
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
160
|
+
|
|
161
|
+
assert job.connection is mock_connection
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def test_resolve_connection_no_connection():
|
|
165
|
+
"""Test connection resolution when session has no connection"""
|
|
166
|
+
mock_session = Mock(spec=Session)
|
|
167
|
+
mock_session.connection = None
|
|
168
|
+
|
|
169
|
+
with pytest.raises(ConnectionError, match="No active connection found"):
|
|
170
|
+
ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
# ============================================================================
|
|
174
|
+
# Date Parsing Tests
|
|
175
|
+
# ============================================================================
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def test_parse_date_params_with_date_object():
|
|
179
|
+
"""Test _parse_date_params with date object"""
|
|
180
|
+
mock_session = Mock(spec=Session)
|
|
181
|
+
mock_session.connection = Mock()
|
|
182
|
+
|
|
183
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
184
|
+
|
|
185
|
+
payload = {"start_date": date(2024, 1, 1), "end_date": date(2024, 12, 31)}
|
|
186
|
+
result = job._parse_date_params(payload, ["start_date", "end_date"])
|
|
187
|
+
|
|
188
|
+
assert result["start_date"] == "2024-01-01"
|
|
189
|
+
assert result["end_date"] == "2024-12-31"
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def test_parse_date_params_with_datetime_object():
|
|
193
|
+
"""Test _parse_date_params with datetime object"""
|
|
194
|
+
mock_session = Mock(spec=Session)
|
|
195
|
+
mock_session.connection = Mock()
|
|
196
|
+
|
|
197
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
198
|
+
|
|
199
|
+
payload = {"start_date": datetime(2024, 1, 1, 10, 30), "end_date": datetime(2024, 12, 31, 15, 45)}
|
|
200
|
+
result = job._parse_date_params(payload, ["start_date", "end_date"])
|
|
201
|
+
|
|
202
|
+
assert result["start_date"] == "2024-01-01"
|
|
203
|
+
assert result["end_date"] == "2024-12-31"
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def test_parse_date_params_with_string_hyphen():
|
|
207
|
+
"""Test _parse_date_params with string in YYYY-MM-DD format"""
|
|
208
|
+
mock_session = Mock(spec=Session)
|
|
209
|
+
mock_session.connection = Mock()
|
|
210
|
+
|
|
211
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
212
|
+
|
|
213
|
+
payload = {"start_date": "2024-01-01", "end_date": "2024-12-31"}
|
|
214
|
+
result = job._parse_date_params(payload, ["start_date", "end_date"])
|
|
215
|
+
|
|
216
|
+
assert result["start_date"] == "2024-01-01"
|
|
217
|
+
assert result["end_date"] == "2024-12-31"
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def test_parse_date_params_with_string_yyyymmdd():
|
|
221
|
+
"""Test _parse_date_params with string in YYYYMMDD format"""
|
|
222
|
+
mock_session = Mock(spec=Session)
|
|
223
|
+
mock_session.connection = Mock()
|
|
224
|
+
|
|
225
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
226
|
+
|
|
227
|
+
payload = {"start_date": "20240101", "end_date": "20241231"}
|
|
228
|
+
result = job._parse_date_params(payload, ["start_date", "end_date"])
|
|
229
|
+
|
|
230
|
+
assert result["start_date"] == "2024-01-01"
|
|
231
|
+
assert result["end_date"] == "2024-12-31"
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def test_parse_date_params_preserves_other_keys():
|
|
235
|
+
"""Test _parse_date_params preserves non-date keys"""
|
|
236
|
+
mock_session = Mock(spec=Session)
|
|
237
|
+
mock_session.connection = Mock()
|
|
238
|
+
|
|
239
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
240
|
+
|
|
241
|
+
payload = {"start_date": "20240101", "code": "sh.600000", "frequency": "5"}
|
|
242
|
+
result = job._parse_date_params(payload, ["start_date"])
|
|
243
|
+
|
|
244
|
+
assert result["start_date"] == "2024-01-01"
|
|
245
|
+
assert result["code"] == "sh.600000"
|
|
246
|
+
assert result["frequency"] == "5"
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# ============================================================================
|
|
250
|
+
# String Parsing Tests
|
|
251
|
+
# ============================================================================
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def test_parse_string_params_basic():
|
|
255
|
+
"""Test _parse_string_params with string values"""
|
|
256
|
+
mock_session = Mock(spec=Session)
|
|
257
|
+
mock_session.connection = Mock()
|
|
258
|
+
|
|
259
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
260
|
+
|
|
261
|
+
payload = {"code": "sh.600000", "frequency": "5", "adjustflag": "3"}
|
|
262
|
+
result = job._parse_string_params(payload, ["code", "frequency"])
|
|
263
|
+
|
|
264
|
+
assert result["code"] == "sh.600000"
|
|
265
|
+
assert result["frequency"] == "5"
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def test_parse_string_params_preserves_other_types():
|
|
269
|
+
"""Test _parse_string_params preserves non-string types"""
|
|
270
|
+
mock_session = Mock(spec=Session)
|
|
271
|
+
mock_session.connection = Mock()
|
|
272
|
+
|
|
273
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
274
|
+
|
|
275
|
+
payload = {"code": "sh.600000", "pagesize": 100, "enabled": True}
|
|
276
|
+
result = job._parse_string_params(payload, ["code"])
|
|
277
|
+
|
|
278
|
+
assert result["code"] == "sh.600000"
|
|
279
|
+
assert result["pagesize"] == 100
|
|
280
|
+
assert result["enabled"] is True
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
# ============================================================================
|
|
284
|
+
# _fetchall Tests - Direct Mode
|
|
285
|
+
# ============================================================================
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def test_fetchall_direct_mode_success():
|
|
289
|
+
"""Test _fetchall in direct mode with successful response"""
|
|
290
|
+
mock_session = Mock(spec=Session)
|
|
291
|
+
mock_session.connection = Mock()
|
|
292
|
+
|
|
293
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
294
|
+
|
|
295
|
+
# Mock ResultSet
|
|
296
|
+
mock_rs = Mock()
|
|
297
|
+
mock_rs.error_code = "0"
|
|
298
|
+
mock_rs.get_data.return_value = pd.DataFrame({"date": ["2024-01-01"], "close": [100.0]})
|
|
299
|
+
|
|
300
|
+
# Mock API that returns ResultSet
|
|
301
|
+
mock_api = Mock(return_value=mock_rs)
|
|
302
|
+
|
|
303
|
+
result = job._fetchall(mock_api, code="sh.600000")
|
|
304
|
+
|
|
305
|
+
assert isinstance(result, pd.DataFrame)
|
|
306
|
+
assert len(result) == 1
|
|
307
|
+
assert "date" in result.columns
|
|
308
|
+
assert "_fetchall[direct_mode" in str(job.metric.marks)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def test_fetchall_direct_mode_error():
|
|
312
|
+
"""Test _fetchall in direct mode with error response"""
|
|
313
|
+
mock_session = Mock(spec=Session)
|
|
314
|
+
mock_session.connection = Mock()
|
|
315
|
+
|
|
316
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
317
|
+
|
|
318
|
+
# Mock ResultSet with error
|
|
319
|
+
mock_rs = Mock()
|
|
320
|
+
mock_rs.error_code = "10001001"
|
|
321
|
+
mock_rs.error_msg = "User not logged in"
|
|
322
|
+
|
|
323
|
+
# Mock API that returns ResultSet
|
|
324
|
+
mock_api = Mock(return_value=mock_rs)
|
|
325
|
+
|
|
326
|
+
result = job._fetchall(mock_api, code="sh.600000")
|
|
327
|
+
|
|
328
|
+
assert isinstance(result, pd.DataFrame)
|
|
329
|
+
assert result.empty
|
|
330
|
+
assert "_fetchall[ERROR" in str(job.metric.marks)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def test_fetchall_direct_mode_empty_data():
|
|
334
|
+
"""Test _fetchall in direct mode with empty data"""
|
|
335
|
+
mock_session = Mock(spec=Session)
|
|
336
|
+
mock_session.connection = Mock()
|
|
337
|
+
|
|
338
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
339
|
+
|
|
340
|
+
# Mock ResultSet with empty data
|
|
341
|
+
mock_rs = Mock()
|
|
342
|
+
mock_rs.error_code = "0"
|
|
343
|
+
mock_rs.get_data.return_value = pd.DataFrame()
|
|
344
|
+
|
|
345
|
+
# Mock API that returns ResultSet
|
|
346
|
+
mock_api = Mock(return_value=mock_rs)
|
|
347
|
+
|
|
348
|
+
result = job._fetchall(mock_api, code="sh.600000")
|
|
349
|
+
|
|
350
|
+
assert isinstance(result, pd.DataFrame)
|
|
351
|
+
assert result.empty
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
# ============================================================================
|
|
355
|
+
# _fetchall Tests - Relay Mode
|
|
356
|
+
# ============================================================================
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def test_fetchall_relay_mode_success():
|
|
360
|
+
"""Test _fetchall in relay mode (returns DataFrame directly)"""
|
|
361
|
+
mock_session = Mock(spec=Session)
|
|
362
|
+
mock_session.connection = Mock()
|
|
363
|
+
|
|
364
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
365
|
+
|
|
366
|
+
# Mock API that returns DataFrame (relay mode)
|
|
367
|
+
expected_df = pd.DataFrame({"date": ["2024-01-01", "2024-01-02"], "close": [100.0, 101.0]})
|
|
368
|
+
mock_api = Mock(return_value=expected_df)
|
|
369
|
+
|
|
370
|
+
result = job._fetchall(mock_api, code="sh.600000")
|
|
371
|
+
|
|
372
|
+
assert isinstance(result, pd.DataFrame)
|
|
373
|
+
assert len(result) == 2
|
|
374
|
+
pd.testing.assert_frame_equal(result, expected_df)
|
|
375
|
+
assert "_fetchall[relay_mode" in str(job.metric.marks)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def test_fetchall_relay_mode_empty_dataframe():
|
|
379
|
+
"""Test _fetchall in relay mode with empty DataFrame"""
|
|
380
|
+
mock_session = Mock(spec=Session)
|
|
381
|
+
mock_session.connection = Mock()
|
|
382
|
+
|
|
383
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
384
|
+
|
|
385
|
+
# Mock API that returns empty DataFrame (relay mode)
|
|
386
|
+
empty_df = pd.DataFrame()
|
|
387
|
+
mock_api = Mock(return_value=empty_df)
|
|
388
|
+
|
|
389
|
+
result = job._fetchall(mock_api, code="sh.600000")
|
|
390
|
+
|
|
391
|
+
assert isinstance(result, pd.DataFrame)
|
|
392
|
+
assert result.empty
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
# ============================================================================
|
|
396
|
+
# Cache Tests
|
|
397
|
+
# ============================================================================
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
def test_load_cache_success():
|
|
401
|
+
"""Test _load_cache when cache hit"""
|
|
402
|
+
mock_session = Mock(spec=Session)
|
|
403
|
+
mock_session.connection = Mock()
|
|
404
|
+
|
|
405
|
+
mock_cache = Mock(spec=Cache)
|
|
406
|
+
cached_data = pd.DataFrame({"test": [1, 2, 3]})
|
|
407
|
+
mock_cache.get.return_value = cached_data
|
|
408
|
+
|
|
409
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=mock_cache)
|
|
410
|
+
|
|
411
|
+
result = job._load_cache()
|
|
412
|
+
|
|
413
|
+
assert result is not None
|
|
414
|
+
pd.testing.assert_frame_equal(result, cached_data)
|
|
415
|
+
assert "load_cache[OK]" in job.metric.marks
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def test_load_cache_miss():
|
|
419
|
+
"""Test _load_cache when cache miss"""
|
|
420
|
+
mock_session = Mock(spec=Session)
|
|
421
|
+
mock_session.connection = Mock()
|
|
422
|
+
|
|
423
|
+
mock_cache = Mock(spec=Cache)
|
|
424
|
+
mock_cache.get.return_value = None
|
|
425
|
+
|
|
426
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=mock_cache)
|
|
427
|
+
|
|
428
|
+
result = job._load_cache()
|
|
429
|
+
|
|
430
|
+
assert result is None
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
def test_load_cache_no_cache():
|
|
434
|
+
"""Test _load_cache when cache is disabled"""
|
|
435
|
+
mock_session = Mock(spec=Session)
|
|
436
|
+
mock_session.connection = Mock()
|
|
437
|
+
|
|
438
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=False)
|
|
439
|
+
|
|
440
|
+
result = job._load_cache()
|
|
441
|
+
|
|
442
|
+
assert result is None
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def test_save_cache_success():
|
|
446
|
+
"""Test _save_cache saves data to cache"""
|
|
447
|
+
mock_session = Mock(spec=Session)
|
|
448
|
+
mock_session.connection = Mock()
|
|
449
|
+
|
|
450
|
+
mock_cache = Mock(spec=Cache)
|
|
451
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=mock_cache)
|
|
452
|
+
|
|
453
|
+
data = pd.DataFrame({"test": [1, 2, 3]})
|
|
454
|
+
job._save_cache(data)
|
|
455
|
+
|
|
456
|
+
mock_cache.set.assert_called_once()
|
|
457
|
+
assert "_save_cache[OK]" in job.metric.marks
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
def test_save_cache_no_cache():
|
|
461
|
+
"""Test _save_cache when cache is disabled"""
|
|
462
|
+
mock_session = Mock(spec=Session)
|
|
463
|
+
mock_session.connection = Mock()
|
|
464
|
+
|
|
465
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, cache=False)
|
|
466
|
+
|
|
467
|
+
data = pd.DataFrame({"test": [1, 2, 3]})
|
|
468
|
+
job._save_cache(data) # Should not raise error
|
|
469
|
+
|
|
470
|
+
# No checkpoint should be marked
|
|
471
|
+
assert "_save_cache[OK]" not in job.metric.marks
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
# ============================================================================
|
|
475
|
+
# Integration Tests
|
|
476
|
+
# ============================================================================
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def test_baostockjob_full_workflow_direct_mode():
|
|
480
|
+
"""Test complete BaostockJob workflow in direct mode"""
|
|
481
|
+
mock_session = Mock(spec=Session)
|
|
482
|
+
mock_session.connection = Mock()
|
|
483
|
+
|
|
484
|
+
# Create job with all features
|
|
485
|
+
job = FetchAllJob(
|
|
486
|
+
name="integration_test",
|
|
487
|
+
key="integration_key",
|
|
488
|
+
session=mock_session,
|
|
489
|
+
params={"code": "sh.600000"},
|
|
490
|
+
cache=True,
|
|
491
|
+
retry={"retry": 3, "wait": 1.0},
|
|
492
|
+
paginate={"pagesize": 100, "pagelimit": 1000},
|
|
493
|
+
)
|
|
494
|
+
|
|
495
|
+
# Run the job
|
|
496
|
+
result = job.run()
|
|
497
|
+
|
|
498
|
+
assert isinstance(result, pd.DataFrame)
|
|
499
|
+
assert not result.empty
|
|
500
|
+
assert job.metric.duration > 0
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
def test_baostockjob_with_date_conversion():
|
|
504
|
+
"""Test BaostockJob with date parameter conversion"""
|
|
505
|
+
mock_session = Mock(spec=Session)
|
|
506
|
+
mock_session.connection = Mock()
|
|
507
|
+
|
|
508
|
+
job = ConcreteBaostockJob(
|
|
509
|
+
name="date_test",
|
|
510
|
+
key="date_key",
|
|
511
|
+
session=mock_session,
|
|
512
|
+
params={"code": "sh.600000", "start_date": "20240101", "end_date": date(2024, 12, 31)},
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
# Parse dates
|
|
516
|
+
payload = job.get_params()
|
|
517
|
+
parsed = job._parse_date_params(payload, ["start_date", "end_date"])
|
|
518
|
+
|
|
519
|
+
assert parsed["start_date"] == "2024-01-01"
|
|
520
|
+
assert parsed["end_date"] == "2024-12-31"
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
# ============================================================================
|
|
524
|
+
# Edge Cases
|
|
525
|
+
# ============================================================================
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
def test_baostockjob_empty_params():
|
|
529
|
+
"""Test BaostockJob with empty parameters"""
|
|
530
|
+
mock_session = Mock(spec=Session)
|
|
531
|
+
mock_session.connection = Mock()
|
|
532
|
+
|
|
533
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session, params={})
|
|
534
|
+
|
|
535
|
+
assert job.params.to_dict() == {}
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def test_baostockjob_metric_tracking():
|
|
539
|
+
"""Test BaostockJob tracks metrics correctly"""
|
|
540
|
+
mock_session = Mock(spec=Session)
|
|
541
|
+
mock_session.connection = Mock()
|
|
542
|
+
|
|
543
|
+
job = ConcreteBaostockJob(name="test_job", key="test_key", session=mock_session)
|
|
544
|
+
job.run()
|
|
545
|
+
assert job.metric.duration > 0
|
|
546
|
+
assert job.metric.start_at is not None
|
|
547
|
+
assert job.metric.finish_at is not None
|