Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
7789f2f
[bfops/fix-list-tests]: Fix running smoketests --list
bfops Nov 19, 2025
3d1d6b0
Merge branch 'master' into bfops/fix-list-tests
bfops Nov 19, 2025
8bd2b44
[bfops/share-python-deps]: Add smoketests/requirements.txt
bfops Nov 19, 2025
13ed948
[bfops/fix-list-tests]: Merge remote-tracking branch 'origin/bfops/sh…
bfops Nov 19, 2025
b8197eb
Merge branch 'master' into bfops/share-python-deps
bfops Nov 19, 2025
a4c3ca8
[bfops/share-python-deps]: fix
bfops Nov 19, 2025
fbc5e24
[bfops/fix-list-tests]: Merge remote-tracking branch 'origin/bfops/sh…
bfops Nov 19, 2025
db51dc7
[bfops/fix-list-tests]: restore
bfops Nov 19, 2025
fae85d5
[bfops/fix-list-tests]: print any failed
bfops Nov 19, 2025
e7f9f9f
[bfops/share-python-deps]: review
bfops Nov 19, 2025
9aca3b7
[bfops/share-python-deps]: review
bfops Nov 19, 2025
a8fee32
[bfops/fix-list-tests]: Merge remote-tracking branch 'origin/bfops/sh…
bfops Nov 19, 2025
5f1c35d
[bfops/parallel-smoketests]: empty
bfops Nov 19, 2025
972ee33
[bfops/parallel-smoketests]: Merge remote-tracking branch 'origin/mas…
bfops Nov 20, 2025
cd878b6
Merge branch 'master' into bfops/parallel-smoketests
bfops Nov 20, 2025
0dbf4a5
[bfops/parallel-smoketests]: Merge remote-tracking branch 'origin/add…
bfops Nov 20, 2025
2dc780c
[bfops/parallel-smoketests]: remove python parallel flags
bfops Nov 20, 2025
910f3f0
[bfops/parallel-smoketests]: Merge branch 'bfops/parallel-smoketests'…
bfops Nov 20, 2025
7fe19dd
[bfops/parallel-smoketests]: wip
bfops Nov 20, 2025
deb123a
[bfops/parallel-smoketests]: review
bfops Nov 20, 2025
282ece6
[bfops/parallel-smoketests]: Start server as part of running smoketests
bfops Nov 20, 2025
f095a1d
[bfops/parallel-smoketests]: WIP
bfops Nov 20, 2025
336337a
[bfops/parallel-smoketests]: review
bfops Nov 20, 2025
38859ab
[bfops/parallel-smoketests]: review
bfops Nov 20, 2025
5940d57
[bfops/parallel-smoketests]: Merge remote-tracking branch 'origin/add…
bfops Nov 20, 2025
8ae1971
[bfops/parallel-smoketests]: fix workflow file
bfops Nov 20, 2025
9bbe781
[bfops/parallel-smoketests]: maybe fix?
bfops Nov 20, 2025
3937768
[bfops/parallel-smoketests]: fix copy
bfops Nov 20, 2025
f7e7893
[bfops/parallel-smoketests]: fix
bfops Nov 20, 2025
680042e
[bfops/parallel-smoketests]: review
bfops Nov 21, 2025
60de57d
[bfops/ci-start-server]: revert
bfops Nov 21, 2025
e7443f4
[bfops/ci-start-server]: review
bfops Nov 21, 2025
5327956
[bfops/ci-start-server]: revert
bfops Nov 21, 2025
6fd17a0
[bfops/parallel-smoketests]: Merge remote-tracking branch 'origin/bfo…
bfops Nov 21, 2025
9afb403
[bfops/parallel-smoketests]: Revert "[bfops/ci-start-server]: revert"
bfops Nov 21, 2025
961d8ba
[bfops/parallel-smoketests]: WIP
bfops Nov 21, 2025
3516f69
[bfops/parallel-smoketests]: WIP
bfops Nov 21, 2025
a0ccb9e
[bfops/parallel-smoketests]: WIP
bfops Nov 21, 2025
cd2db36
[bfops/parallel-smoketests]: builds with random port selection / proj…
bfops Nov 21, 2025
0457534
[bfops/parallel-smoketests]: add --local-only
bfops Nov 21, 2025
9eef7cb
[bfops/parallel-smoketests]: add smoketests --list=json
bfops Nov 24, 2025
a514921
[bfops/parallel-smoketests]: WIP parallel logic
bfops Nov 24, 2025
45ee326
[bfops/parallel-smoketests]: custom python path option
bfops Nov 24, 2025
46793a4
[bfops/parallel-smoketests]: actual parallel
bfops Nov 24, 2025
f3944f3
[bfops/parallel-smoketests]: TODO
bfops Nov 24, 2025
e98d525
[bfops/parallel-smoketests]: review
bfops Nov 25, 2025
52e3f6e
[bfops/parallel-smoketests]: use parallel smoketests in CI
bfops Nov 25, 2025
40cb0de
[bfops/parallel-smoketests]: Don't build CLI in smoketests if we're a…
bfops Nov 25, 2025
83f3fff
[bfops/parallel-smoketests]: consolidate builds, and fix
bfops Nov 25, 2025
75b47ac
[bfops/parallel-smoketests]: todos
bfops Nov 25, 2025
73548c1
[bfops/parallel-smoketests]: Pre-build in non-parallel case too
bfops Nov 25, 2025
04eeb8c
[bfops/parallel-smoketests]: sanitize cargo env
bfops Nov 25, 2025
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
4 changes: 2 additions & 2 deletions .github/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ services:
context: ../
dockerfile: .github/Dockerfile
ports:
- "3000:3000"
- "${STDB_PORT:-3000}:3000"
# Postgres
- "5432:5432"
- "${STDB_PG_PORT:-5432}:5432"
entrypoint: spacetime start --pg-port 5432
privileged: true
environment:
Expand Down
36 changes: 16 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ jobs:
container: ${{ matrix.container }}
env:
CARGO_TARGET_DIR: ${{ github.workspace }}/target
# Note: clear_database and replication only work in private
SMOKETEST_ARGS: ${{ matrix.smoketest_args }} -x clear_database replication teams
steps:
- name: Find Git ref
env:
Expand Down Expand Up @@ -87,35 +89,29 @@ jobs:
if: runner.os == 'Linux'
run: /usr/local/bin/start-docker.sh

- name: Build and start database (Linux)
if: runner.os == 'Linux'
run: |
# Our .dockerignore omits `target`, which our CI Dockerfile needs.
rm .dockerignore
docker compose -f .github/docker-compose.yml up -d
- name: Build and start database (Windows)
# the sdk-manifests on windows-latest are messed up, so we need to update them
- name: Fix sdk-manifests
if: runner.os == 'Windows'
working-directory: modules
# Powershell doesn't early-exit properly from a multi-line command if one fails
shell: bash
run: |
# Fail properly if any individual command fails
$ErrorActionPreference = 'Stop'
$PSNativeCommandUseErrorActionPreference = $true

Start-Process target/debug/spacetimedb-cli.exe -ArgumentList 'start --pg-port 5432'
cd modules
# the sdk-manifests on windows-latest are messed up, so we need to update them
dotnet workload config --update-mode manifests
dotnet workload update
- uses: actions/setup-python@v5
with: { python-version: '3.12' }
if: runner.os == 'Windows'
- name: Install python deps
run: python -m pip install -r smoketests/requirements.txt
- name: Run smoketests
# Note: clear_database and replication only work in private
run: cargo ci smoketests -- ${{ matrix.smoketest_args }} -x clear_database replication teams
- name: Stop containers (Linux)
if: always() && runner.os == 'Linux'
run: docker compose -f .github/docker-compose.yml down
- name: Run smoketests (Linux)
if: runner.os == 'Linux'
run: |
# Our .dockerignore omits `target`, which our CI Dockerfile needs.
rm .dockerignore
cargo ci smoketests --docker .github/docker-compose.yml --parallel -- ${SMOKETEST_ARGS}
- name: Run smoketests (Windows)
if: runner.os == 'Windows'
run: cargo ci smoketests --parallel -- ${SMOKETEST_ARGS}

test:
name: Test Suite
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ services:
- key_files:/etc/spacetimedb
- /stdb
ports:
- "3000:3000"
- "${STDB_PORT:-3000}:3000"
# Postgres
- "5432:5432"
- "${STDB_PG_PORT:-5432}:5432"
# Tracy
- "8086:8086"
- "${STDB_TRACY_PORT:-8086}:8086"
entrypoint: cargo watch -i flamegraphs -i log.conf --why -C crates/standalone -x 'run start --data-dir=/stdb/data --jwt-pub-key-path=/etc/spacetimedb/id_ecdsa.pub --jwt-priv-key-path=/etc/spacetimedb/id_ecdsa --pg-port 5432'
privileged: true
environment:
Expand Down
1 change: 1 addition & 0 deletions smoketests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ def requires_anonymous_login(item):
return item

def requires_local_server(item):
setattr(item, "_requires_local_server", True)
if REMOTE_SERVER:
return unittest.skip("running against a remote server")(item)
return item
Expand Down
68 changes: 49 additions & 19 deletions smoketests/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,15 @@ def main():
parser.add_argument("--no-docker-logs", action="store_true")
parser.add_argument("--skip-dotnet", action="store_true", help="ignore tests which require dotnet")
parser.add_argument("--show-all-output", action="store_true", help="show all stdout/stderr from the tests as they're running")
parser.add_argument("--parallel", action="store_true", help="run test classes in parallel")
parser.add_argument("-j", dest='jobs', help="Set number of jobs for parallel test runs. Default is `nproc`", type=int, default=0)
parser.add_argument('-k', dest='testNamePatterns',
action='append', type=_convert_select_pattern,
help='Only run tests which match the given substring')
parser.add_argument("-x", dest="exclude", nargs="*", default=[])
parser.add_argument("--no-build-cli", action="store_true", help="don't cargo build the cli")
parser.add_argument("--list", action="store_true", help="list the tests that would be run, but don't run them")
parser.add_argument("--list", nargs="?", const="text", choices=("text", "json"), default=None, help="list the tests that would be run (optionally as 'text' or 'json'), but don't run them")
parser.add_argument("--remote-server", action="store", help="Run against a remote server")
parser.add_argument("--spacetime-login", action="store_true", help="Use `spacetime login` for these tests (and disable tests that don't work with that)")
parser.add_argument("--local-only", action="store_true", help="Only run tests that require a local server")
args = parser.parse_args()

if args.docker:
Expand Down Expand Up @@ -116,22 +115,58 @@ def main():
loader.testNamePatterns = args.testNamePatterns

tests = loader.loadTestsFromNames(testlist)
if args.list:

if args.local_only:
def _is_local_only(test_case):
method_name = getattr(test_case, "_testMethodName", None)
if method_name is not None and hasattr(test_case, method_name):
method = getattr(test_case, method_name)
if getattr(method, "_requires_local_server", False):
return True
# Also allow class-level decoration
if getattr(test_case.__class__, "_requires_local_server", False):
return True
return False

filtered = unittest.TestSuite()
for t in _iter_all_tests(tests):
if _is_local_only(t):
filtered.addTest(t)
tests = filtered

if args.list is not None:
failed_cls = getattr(unittest.loader, "_FailedTest", None)
any_failed = False
test_names = []
failed_tests = []
for test in _iter_all_tests(tests):
name = test.id()
if isinstance(test, failed_cls):
any_failed = True
print('')
print("Failed to construct %s:" % test.id())
exc = getattr(test, "_exception", None)
if exc is not None:
tb = ''.join(traceback.format_exception(exc))
print(tb.rstrip())
print('')
tb = ''.join(traceback.format_exception(exc)) if exc is not None else None
failed_tests.append({
"test_id": name,
"error": tb.rstrip() if tb is not None else None,
})
if args.list == "text":
print('')
print("Failed to construct %s:" % name)
if tb is not None:
print(tb.rstrip())
print('')
else:
print(f"{name}")
test_names.append(name)
if args.list == "text":
print(f"{name}")

if args.list == "json":
output = {
"tests": test_names,
"errors": failed_tests,
}
print(json.dumps(output))

exit(1 if any_failed else 0)

if not args.no_build_cli:
Expand Down Expand Up @@ -176,14 +211,9 @@ def main():
buffer = not args.show_all_output
verbosity = 2

if args.parallel:
print("parallel test running is under construction, this will probably not work correctly")
from . import unittest_parallel
unittest_parallel.main(buffer=buffer, verbose=verbosity, level="class", discovered_tests=tests, jobs=args.jobs)
else:
result = unittest.TextTestRunner(buffer=buffer, verbosity=verbosity).run(tests)
if not result.wasSuccessful():
parser.exit(status=1)
result = unittest.TextTestRunner(buffer=buffer, verbosity=verbosity).run(tests)
if not result.wasSuccessful():
parser.exit(status=1)


if __name__ == '__main__':
Expand Down
1 change: 1 addition & 0 deletions tools/ci/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ chrono = { workspace = true, features=["clock"] }
clap.workspace = true
regex.workspace = true
duct.workspace = true
serde_json.workspace = true
Loading
Loading