Skip to content
19 changes: 18 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,18 @@ jobs:
with:
run_install: true

# Install cmake and emscripten for C++ module compilation tests.
- name: Install cmake and emscripten (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y cmake
git clone https://github.com/emscripten-core/emsdk.git ~/emsdk
cd ~/emsdk
./emsdk install 4.0.21
./emsdk activate 4.0.21

- name: Install psql (Windows)
if: runner.os == 'Windows'
run: choco install psql -y --no-progress
Expand Down Expand Up @@ -124,7 +136,12 @@ jobs:
# --test-threads=1 eliminates contention in the C# tests where they fight over bindings
# build artifacts.
# It also seemed to improve performance a fair amount (11m -> 6m)
run: cargo ci smoketests -- --test-threads=1
shell: bash
run: |
if [ "${{ runner.os }}" = "Linux" ]; then
source ~/emsdk/emsdk_env.sh
fi
cargo ci smoketests -- --test-threads=1

smoketests-python:
needs: [lints]
Expand Down
15 changes: 15 additions & 0 deletions crates/smoketests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,15 @@ macro_rules! require_pnpm {
};
}

#[macro_export]
macro_rules! require_emscripten {
() => {
if !$crate::have_emscripten() {
panic!("emcc (Emscripten) not found");
}
};
}

/// Helper macro for timing operations and printing results
macro_rules! timed {
($label:expr, $expr:expr) => {{
Expand Down Expand Up @@ -242,6 +251,12 @@ pub fn pnpm_path() -> Option<PathBuf> {
PNPM_PATH.get_or_init(|| which("pnpm").ok()).clone()
}

/// Returns true if Emscripten (emcc) is available on the system.
pub fn have_emscripten() -> bool {
static HAVE_EMSCRIPTEN: OnceLock<bool> = OnceLock::new();
*HAVE_EMSCRIPTEN.get_or_init(|| which("emcc").is_ok() || which("emcc.bat").is_ok())
}

/// A smoketest instance that manages a SpacetimeDB server and module project.
pub struct Smoketest {
/// The SpacetimeDB server guard (stops server on drop).
Expand Down
42 changes: 41 additions & 1 deletion crates/smoketests/tests/smoketests/quickstart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use anyhow::{bail, Context, Result};
use regex::Regex;
use spacetimedb_smoketests::{pnpm_path, require_dotnet, require_pnpm, workspace_root, Smoketest};
use spacetimedb_smoketests::{pnpm_path, require_dotnet, require_emscripten, require_pnpm, workspace_root, Smoketest};
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
Expand Down Expand Up @@ -438,6 +438,37 @@ fn user_input_direct(ctx: &DbConnection) {
std::thread::sleep(std::time::Duration::from_secs(1));
std::process::exit(0);
}
"#,
connected_str: "connected",
}
}

fn cpp() -> Self {
// C++ server uses Rust client (same as TypeScript pattern)
Self {
lang: "cpp",
client_lang: "rust",
server_file: "src/lib.cpp",
client_file: "src/main.rs",
module_bindings: "src/module_bindings",
run_cmd: &["cargo", "run"],
build_cmd: &["cargo", "build"],
replacements: &[
("user_input_loop(&ctx)", "user_input_direct(&ctx)"),
(".with_token(creds_store()", "//.with_token(creds_store()"),
],
extra_code: r#"
fn user_input_direct(ctx: &DbConnection) {
let mut line = String::new();
std::io::stdin().read_line(&mut line).expect("Failed to read from stdin.");
if let Some(name) = line.strip_prefix("/name ") {
ctx.reducers.set_name(name.to_string()).unwrap();
} else {
ctx.reducers.send_message(line).unwrap();
}
std::thread::sleep(std::time::Duration::from_secs(1));
std::process::exit(0);
}
"#,
connected_str: "connected",
}
Expand Down Expand Up @@ -782,3 +813,12 @@ fn test_quickstart_typescript() {
let mut qt = QuickstartTest::new(QuickstartConfig::typescript());
qt.run_quickstart().expect("TypeScript quickstart test failed");
}

/// Run the C++ quickstart for server (with Rust client).
#[test]
fn test_quickstart_cpp() {
require_emscripten!();

let mut qt = QuickstartTest::new(QuickstartConfig::cpp());
qt.run_quickstart().expect("C++ quickstart test failed");
}
Loading
Loading