Skip to content
Open
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
56 changes: 56 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1180,3 +1180,59 @@ jobs:
fi

echo "No Python smoketest changes detected."

smoketests_mod_rs_complete:
name: Check smoketests/mod.rs is complete
runs-on: ubuntu-latest
permissions:
contents: read
env:
CARGO_TARGET_DIR: ${{ github.workspace }}/target
steps:
- name: Find Git ref
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
PR_NUMBER="${{ github.event.inputs.pr_number || null }}"
if test -n "${PR_NUMBER}"; then
GIT_REF="$( gh pr view --repo clockworklabs/SpacetimeDB $PR_NUMBER --json headRefName --jq .headRefName )"
else
GIT_REF="${{ github.ref }}"
fi
echo "GIT_REF=${GIT_REF}" >>"$GITHUB_ENV"
- name: Checkout sources
uses: actions/checkout@v4
with:
ref: ${{ env.GIT_REF }}
- uses: dsherret/rust-toolchain-file@v1
- name: Set default rust toolchain
run: rustup default $(rustup show active-toolchain | cut -d' ' -f1)
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
workspaces: ${{ github.workspace }}
shared-key: spacetimedb
cache-on-failure: false
cache-all-crates: true
cache-workspace-crates: true
prefix-key: v1

# This step shouldn't be needed, but somehow we end up with caches that are missing librusty_v8.a.
# ChatGPT suspects that this could be due to different build invocations using the same target dir,
# and this makes sense to me because we only see it in this job where we mix `cargo build -p` with
# `cargo build --manifest-path` (which apparently build different dependency trees).
# However, we've been unable to fix it so... /shrug
- name: Check v8 outputs
shell: bash
run: |
find "${CARGO_TARGET_DIR}"/ -type f | grep '[/_]v8' || true
if ! [ -f "${CARGO_TARGET_DIR}"/debug/gn_out/obj/librusty_v8.a ]; then
echo "Could not find v8 output file librusty_v8.a; rebuilding manually."
cargo clean -p v8 || true
cargo build -p v8
fi

- name: Verify crates/smoketests/tests/smoketests/mod.rs lists all entries
run: |
cargo ci smoketests check-mod-list
2 changes: 2 additions & 0 deletions crates/smoketests/tests/integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// Single test binary entry point - includes all smoketests
mod smoketests;
36 changes: 0 additions & 36 deletions crates/smoketests/tests/mod.rs

This file was deleted.

37 changes: 37 additions & 0 deletions crates/smoketests/tests/smoketests/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// All smoketest modules
mod add_remove_index;
mod auto_inc;
mod auto_migration;
mod call;
mod cli;
mod client_connection_errors;
mod confirmed_reads;
mod connect_disconnect_from_cli;
mod create_project;
mod csharp_module;
mod default_module_clippy;
mod delete_database;
mod describe;
mod detect_wasm_bindgen;
mod dml;
mod domains;
mod energy;
mod fail_initial_publish;
mod filtering;
mod http_egress;
mod module_nested_op;
mod modules;
mod namespaces;
mod new_user_flow;
mod panic;
mod permissions;
mod pg_wire;
mod publish_upgrade_prompt;
mod quickstart;
mod restart;
mod rls;
mod schedule_reducer;
mod servers;
mod sql;
mod timestamp_route;
mod views;
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fn test_st_view_tables() {
fn test_fail_publish_namespace_collision() {
let mut test = Smoketest::builder()
// Can't be precompiled because the code is intentionally broken
.module_code(include_str!("../modules/views-broken-namespace/src/lib.rs"))
.module_code(include_str!("../../modules/views-broken-namespace/src/lib.rs"))
.autopublish(false)
.build();

Expand All @@ -75,7 +75,7 @@ fn test_fail_publish_namespace_collision() {
fn test_fail_publish_wrong_return_type() {
let mut test = Smoketest::builder()
// Can't be precompiled because the code is intentionally broken
.module_code(include_str!("../modules/views-broken-return-type/src/lib.rs"))
.module_code(include_str!("../../modules/views-broken-return-type/src/lib.rs"))
.autopublish(false)
.build();

Expand Down
11 changes: 11 additions & 0 deletions tools/ci/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,17 @@ Usage: prepare

- `--help`: Print help (see a summary with '-h')

#### `check-mod-list`

**Usage:**
```bash
Usage: check-mod-list
```

**Options:**

- `--help`:

#### `help`

**Usage:**
Expand Down
10 changes: 3 additions & 7 deletions tools/ci/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const README_PATH: &str = "tools/ci/README.md";

mod ci_docs;
mod smoketest;
mod util;

use util::ensure_repo_root;

/// SpacetimeDB CI tasks
///
Expand All @@ -35,13 +38,6 @@ struct Cli {
skip: Vec<String>,
}

fn ensure_repo_root() -> Result<()> {
if !Path::new("Cargo.toml").exists() {
bail!("You must execute this command from the SpacetimeDB repository root (where Cargo.toml is located)");
}
Ok(())
}

fn check_global_json_policy() -> Result<()> {
ensure_repo_root()?;

Expand Down
76 changes: 74 additions & 2 deletions tools/ci/src/smoketest.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
#![allow(clippy::disallowed_macros)]
use anyhow::{ensure, Result};
use anyhow::{bail, ensure, Result};
use clap::{Args, Subcommand};
use std::env;
use duct::cmd;
use std::ffi::OsStr;
use std::path::Path;
use std::process::{Command, Stdio};
use std::{env, fs};

use crate::util;

#[derive(Args)]
/// This command first builds the spacetimedb-cli and spacetimedb-standalone binaries,
Expand Down Expand Up @@ -35,6 +40,7 @@ enum SmoketestCmd {
///
/// Use this before running `cargo test --all` to ensure binaries are built.
Prepare,
CheckModList,
}

pub fn run(args: SmoketestsArgs) -> Result<()> {
Expand All @@ -44,6 +50,11 @@ pub fn run(args: SmoketestsArgs) -> Result<()> {
eprintln!("Binaries ready. You can now run `cargo test --all`.");
Ok(())
}
Some(SmoketestCmd::CheckModList) => {
check_smoketests_mod_rs_complete()?;
eprintln!("smoketests/mod.rs is up to date.");
Ok(())
}
None => run_smoketest(args.server, args.dotnet, args.args),
}
}
Expand Down Expand Up @@ -177,3 +188,64 @@ fn set_env(cmd: &mut Command, server: Option<String>, dotnet: bool) {
}
cmd.env("SMOKETESTS_DOTNET", if dotnet { "1" } else { "0" });
}

fn check_smoketests_mod_rs_complete() -> Result<()> {
util::ensure_repo_root()?;

let expected_dir = Path::new("crates/smoketests/tests/smoketests");
let mut expected = std::collections::BTreeSet::<String>::new();
for entry in fs::read_dir(expected_dir)? {
let entry = entry?;
let path = entry.path();
let name = entry.file_name();
let name = name.to_string_lossy();
if name == "mod.rs" {
continue;
}
if name.starts_with('.') {
continue;
}

let ft = entry.file_type()?;
if ft.is_dir() {
expected.insert(name.to_string());
} else if ft.is_file() && path.extension() == Some(OsStr::new("rs")) {
if let Some(stem) = path.file_stem() {
expected.insert(stem.to_string_lossy().to_string());
}
}
}

let out = cmd!("cargo", "test", "-p", "spacetimedb-smoketests", "--", "--list",).read()?;

let mut present = std::collections::BTreeSet::<String>::new();
for line in out.lines() {
let line = line.trim();
let parts: Vec<&str> = line.split("::").collect();
if parts.len() < 2 {
continue;
}
if parts[0] != "smoketests" {
continue;
}
present.insert(parts[1].to_string());
}

let missing = expected
.into_iter()
.filter(|m| !present.contains(m))
.collect::<Vec<_>>();

if !missing.is_empty() {
bail!(
"crates/smoketests/tests/smoketests/mod.rs appears incomplete; missing modules (not present in `cargo test -- --list`):\n{}",
missing
.iter()
.map(|m| format!("- mod {m};"))
.collect::<Vec<_>>()
.join("\n")
);
}

Ok(())
}
11 changes: 11 additions & 0 deletions tools/ci/src/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#![allow(clippy::disallowed_macros)]

use anyhow::{bail, Result};
use std::path::Path;

pub fn ensure_repo_root() -> Result<()> {
if !Path::new("Cargo.toml").exists() {
bail!("You must execute this command from the SpacetimeDB repository root (where Cargo.toml is located)");
}
Ok(())
}