A test harness that builds a throwaway Postgres database, seeds awkward synthetic tickers, runs the backfill scripts against it and drops the database afterwards.
Open-Source Tools · How-To · Dev & ops tools
How to use ltm-warehouse-tests: test a Postgres price-history backfill without touching the real warehouse
Revised
· v1.0.0 · what changed
Code: github.com/herrrickshaw/ltm-warehouse-tests
Watch the walkthrough
Watch on YouTube: youtu.be/gA6xuLKGHZ4
Why it is useful
- Who benefits: anyone maintaining scripts that write into a price or fundamentals warehouse, who wants to re-check a change instead of trusting it.
- What it replaces: running backfill scripts against live data to see what happens.
- Evidence from the run: all three test files passed on a throwaway Postgres 17 on port 55432, the thin-history finder flagged 4 of 7 seeded symbols, and the dry run persisted 0 rows.
- Each seeded case encodes a real past bug: ticker already carrying a suffix, a symbol tagged under two countries, an NSE series switching mid-history.
- The database is created and dropped by the script, even when a test fails.
What it is for
The repo verifies four maintenance scripts for an LTM (long-term) warehouse: exchange resolution (exchange_map.py), thin-history detection (find_thin_history_tickers.py), exchange-list building, and the multi-tier backfill (Yahoo, then NSE, then SerpApi estimates) in backfill_missing_history.py.
run_tests.sh creates ltm_warehouse_test, applies a schema that mirrors the real tables, seeds synthetic symbols, generates a thin_history.csv fixture, runs test_backfill_logic.py, test_backfill_cli.py and test_nse_tier.py, then drops the database.
Tests check deduplication against existing dates, routing (Yahoo into the fact table, SerpApi into a separate low-fidelity estimate table), that a dry run never persists, and that the NSE tier fires only for India and collapses series switches to one row per date.
Who it is for
- Data engineers who maintain market-data backfills
- Anyone who wants a pattern for throwaway-database tests with Postgres
- Readers learning why exchange-qualified tickers matter
- Running against your real warehouse: the point is that it never does
- Testing live data quality: the data is synthetic
- Investment decisions: not investment advice
What you need
| Requirement | Why | How to get it |
|---|---|---|
| PostgreSQL server and psql | the harness creates a throwaway database | brew install postgresql@17 (or any local Postgres) |
| Python 3 packages | SQLAlchemy, psycopg2, pandas, yfinance, requests, jugaad-data | pip install -r requirements.txt, but see the SQLAlchemy note under limits |
| A Postgres admin connection | to create and drop the test database | default postgresql://localhost/postgres; override with PG_ADMIN_URL |
| No API keys | the tests do not call paid services | nothing to set up |
Get the code and an AI assistant
You do not have to be a programmer. Get the repository, give it to an AI assistant, and ask in plain language. Any of these routes works:
| Tool | What you need | Best for |
|---|---|---|
| GitHub | Free account to fork or star; git to clone, or the green Code button, then Download ZIP, or open in Codespaces | Getting the code and keeping up with updates |
| Claude Code | Claude subscription or API key; run claude inside the cloned folder | Letting the AI read and run the whole repo |
| Gemini CLI | Google account; run gemini inside the cloned folder | The same hands-on workflow with Gemini |
| Claude.ai, Gemini or ChatGPT in the browser | A chat account; upload README.md and the files you care about (or paste the output of git ls-files) | Understanding the project and asking questions without installing anything |
| Other tools (Copilot Chat, Cursor, Codex CLI) | Open the cloned folder in the tool and point it at README.md first | Editing and extending the code |
git clone https://github.com/herrrickshaw/ltm-warehouse-tests.git
cd ltm-warehouse-tests
claude # or: gemini
Install
- Clone the repo
git clone https://github.com/herrrickshaw/ltm-warehouse-tests.git cd ltm-warehouse-tests - Create a virtual environment and install requirements, pinning SQLAlchemy below 2.1
python3 -m venv .venv && . .venv/bin/activate pip install -r requirements.txt "sqlalchemy<2.1" - Optional: start a disposable Postgres of your own on another port so nothing shared is touched
initdb -D ./pgdata -A trust -U tester pg_ctl -D ./pgdata -o "-p 55432 -k /tmp/pgsock" -l pg.log start
Quick start: commands and what you should see
Run the whole suite (default local Postgres)
./run_tests.sh
Creates the test database, applies the schema, seeds data, runs three test files and ends with 'All tests passed.' then drops the database.
Run against a throwaway server on port 55432
export PGPORT=55432 PGHOST=127.0.0.1 PGUSER=tester
PG_ADMIN_URL=postgresql://tester@127.0.0.1:55432/postgres ./run_tests.sh
Same output. Note that run_tests.sh builds TEST_DB as postgresql://localhost/<name> with no port, so on a non-default port you must set the PG* variables or edit that line.
Use another database name
TEST_DB_NAME=my_ltm_test ./run_tests.sh
The same flow with your name.
Sample outputs
Real output from a run on the date shown in the sources line; trimmed to fit.
Seeding and the thin-history finder (run 19 Oct 2026)
./run_tests.sh
Seeded 6975 rows across 7 symbols
Checked 7 symbols. Flagged 4 with < 5.0y history or < 85% day-coverage within their span.
SYMBOL COUNTRY REASON SPAN(y) COVERAGE MISSING(y)
NEWCO US short_history 0.49 100.0 4.51
OLDIN IN short_history 3.0 100.0 2.0
BARC GB short_history 4.49 100.0 0.51
GAPCO US gappy 5.98 20.1 0.0
Synthetic symbols, not real market data.
Backfill logic tests
python3 tests/test_backfill_logic.py
OK dedup_and_insert_yahoo: added 1435 new rows, rerun added 0
OK dry_run_does_not_persist: reported 2 rows, actually persisted 0
OK serpapi_fallback: added 2 estimate rows (overlap correctly skipped); fact table untouched (still 783 real rows)
OK no_source_available: note='no yahoo/nse data; no --serpapi-key given for fallback'
Run inside run_tests.sh.
NSE tier tests
python3 tests/test_nse_tier.py
OK nse_tier_used_only_for_india_and_dedups_series_switch: added 2 rows (expected 2)
OK non_india_country_skips_nse_tier: source='none'
OK india_symbol_with_no_data_anywhere: note='no yahoo/nse data; no --serpapi-key given for fallback'
All NSE-tier tests passed.
All tests passed.
Final lines of the same run, ending with the throwaway database being dropped.
Ways to use it
| Method | How it works |
|---|---|
| Command line | ./run_tests.sh before and after any change to scripts/*.py. |
| Colab | The README links a notebook, notebooks/colab_test.ipynb (not run for this post). |
| Add a case | When the real warehouse exposes a new edge case, add a seeded symbol in tests/seed_test_data.py and an assertion in the matching test file. |
| Via an AI assistant | Ask Claude Code or Gemini CLI to run the suite and explain any failure. |
Sample prompts for your AI assistant
Copy, paste and edit the parts in [brackets].
- Explain the ltm-warehouse-tests repository in plain English: what problem it solves, what the main files do, and what I need installed.
- Run ./run_tests.sh against a throwaway Postgres on port 55432 and summarise which checks passed.
- Explain what the four seeded edge cases in tests/seed_test_data.py are and which past bug each one prevents.
- Add a test where a symbol already carries a .HK suffix and show me the assertion you would write.
- Why does run_tests.sh build TEST_DB without a port, and how would you change it to honour PG_ADMIN_URL's port?
- Read exchange_map.py and explain how a bare ticker is resolved to an exchange-qualified one.
Limits and honest caveats
- Not investment advice. Test data is synthetic.
- Bug found: with requirements.txt as written (sqlalchemy>=1.4, no upper bound) a fresh install picked SQLAlchemy 2.1.5, whose default driver for postgresql:// is psycopg 3. Seeding failed with ModuleNotFoundError: No module named 'psycopg'. Installing sqlalchemy<2.1 (2.0.55) fixed it.
- run_tests.sh hardcodes postgresql://localhost/<name> for the test database, so a server on a non-default port needs PGPORT/PGHOST set; the PG_ADMIN_URL port is not reused.
- Postgres 17 from Homebrew also needed LC_ALL=en_US.UTF-8 for initdb and start on the test machine.
- Observed, not investigated: in test_backfill_cli.py the dry run listed 1 row for NEWCO but the following --apply showed 0 for NEWCO.
- Network-dependent tiers (live Yahoo, NSE, SerpApi) are not exercised; those tests use seeded data or stubs.
- A temporary edit to run_tests.sh was made in the scratch clone for the run only; nothing was pushed.
Sources: ltm-warehouse-tests README, run_tests.sh, tests/ and scripts/; run_tests.sh run on 19 October 2026 on a fresh clone against a throwaway Postgres 17 on port 55432 in a scratch directory (stopped and deleted afterwards), with SQLAlchemy 2.0.55 in a throwaway virtual environment. The Colab notebook was not run.
- v1.0.0 — 26 October 2026 — first published.
About this article: Researched, written and edited by Umashankar Triplicane Dwarakanathan, with AI research assistance; every figure is meant to trace to the primary source cited. See the Editorial Policy for how sourcing, AI use and corrections work.