Skip to content

Commit 440cc19

Browse files
Added C++ smoketest for quickstart-chat + updated chat doc (#4109)
# Description of Changes - Updated the chat tutorial to include blocks for C++ server code - Updated the Python smoketests to allow C++ with the quickstart check # API and ABI breaking changes N/A # Expected complexity level and risk 1 - Small changes to get the C++ modules to be tested through quickstart # Testing - [x] Ran the tests locally
1 parent e50b5f3 commit 440cc19

4 files changed

Lines changed: 293 additions & 6 deletions

File tree

.github/workflows/ci.yml

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,25 @@ jobs:
7979
with:
8080
run_install: true
8181

82+
# Install emscripten for C++ module compilation tests.
83+
- name: Install emscripten (Linux)
84+
if: runner.os == 'Linux'
85+
shell: bash
86+
run: |
87+
git clone https://github.com/emscripten-core/emsdk.git ~/emsdk
88+
cd ~/emsdk
89+
./emsdk install 4.0.21
90+
./emsdk activate 4.0.21
91+
92+
- name: Install emscripten (Windows)
93+
if: runner.os == 'Windows'
94+
shell: pwsh
95+
run: |
96+
git clone https://github.com/emscripten-core/emsdk.git $env:USERPROFILE\emsdk
97+
cd $env:USERPROFILE\emsdk
98+
.\emsdk install 4.0.21
99+
.\emsdk activate 4.0.21
100+
82101
- name: Install psql (Windows)
83102
if: runner.os == 'Windows'
84103
run: choco install psql -y --no-progress
@@ -122,11 +141,27 @@ jobs:
122141
- name: Install cargo-nextest
123142
uses: taiki-e/install-action@nextest
124143

125-
- name: Run smoketests
126-
# --test-threads=1 eliminates contention in the C# tests where they fight over bindings
127-
# build artifacts.
128-
# It also seemed to improve performance a fair amount (11m -> 6m)
129-
run: cargo ci smoketests -- --test-threads=1
144+
# --test-threads=1 eliminates contention in the C# tests where they fight over bindings
145+
# build artifacts.
146+
# It also seemed to improve performance a fair amount (11m -> 6m)
147+
- name: Run smoketests (Linux)
148+
if: runner.os == 'Linux'
149+
shell: bash
150+
run: |
151+
if [ -f ~/emsdk/emsdk_env.sh ]; then
152+
source ~/emsdk/emsdk_env.sh
153+
fi
154+
cargo ci smoketests -- --test-threads=1
155+
156+
# Due to Emscripten PATH issues this was separated to make sure OpenSSL still builds correctly
157+
- name: Run smoketests (Windows)
158+
if: runner.os == 'Windows'
159+
shell: pwsh
160+
run: |
161+
if (Test-Path "$env:USERPROFILE\emsdk\emsdk_env.ps1") {
162+
& "$env:USERPROFILE\emsdk\emsdk_env.ps1" | Out-Null
163+
}
164+
cargo ci smoketests -- --test-threads=1
130165
131166
smoketests-python:
132167
needs: [lints]

crates/smoketests/src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,15 @@ macro_rules! require_pnpm {
139139
};
140140
}
141141

142+
#[macro_export]
143+
macro_rules! require_emscripten {
144+
() => {
145+
if !$crate::have_emscripten() {
146+
panic!("emcc (Emscripten) not found");
147+
}
148+
};
149+
}
150+
142151
/// Helper macro for timing operations and printing results
143152
macro_rules! timed {
144153
($label:expr, $expr:expr) => {{
@@ -242,6 +251,12 @@ pub fn pnpm_path() -> Option<PathBuf> {
242251
PNPM_PATH.get_or_init(|| which("pnpm").ok()).clone()
243252
}
244253

254+
/// Returns true if Emscripten (emcc) is available on the system.
255+
pub fn have_emscripten() -> bool {
256+
static HAVE_EMSCRIPTEN: OnceLock<bool> = OnceLock::new();
257+
*HAVE_EMSCRIPTEN.get_or_init(|| which("emcc").is_ok() || which("emcc.bat").is_ok())
258+
}
259+
245260
/// A smoketest instance that manages a SpacetimeDB server and module project.
246261
pub struct Smoketest {
247262
/// The SpacetimeDB server guard (stops server on drop).

crates/smoketests/tests/quickstart.rs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
use anyhow::{bail, Context, Result};
66
use regex::Regex;
7-
use spacetimedb_smoketests::{pnpm_path, require_dotnet, require_pnpm, workspace_root, Smoketest};
7+
use spacetimedb_smoketests::{pnpm_path, require_dotnet, require_emscripten, require_pnpm, workspace_root, Smoketest};
88
use std::fs;
99
use std::path::{Path, PathBuf};
1010
use std::process::{Command, Stdio};
@@ -438,6 +438,37 @@ fn user_input_direct(ctx: &DbConnection) {
438438
std::thread::sleep(std::time::Duration::from_secs(1));
439439
std::process::exit(0);
440440
}
441+
"#,
442+
connected_str: "connected",
443+
}
444+
}
445+
446+
fn cpp() -> Self {
447+
// C++ server uses Rust client (same as TypeScript pattern)
448+
Self {
449+
lang: "cpp",
450+
client_lang: "rust",
451+
server_file: "src/lib.cpp",
452+
client_file: "src/main.rs",
453+
module_bindings: "src/module_bindings",
454+
run_cmd: &["cargo", "run"],
455+
build_cmd: &["cargo", "build"],
456+
replacements: &[
457+
("user_input_loop(&ctx)", "user_input_direct(&ctx)"),
458+
(".with_token(creds_store()", "//.with_token(creds_store()"),
459+
],
460+
extra_code: r#"
461+
fn user_input_direct(ctx: &DbConnection) {
462+
let mut line = String::new();
463+
std::io::stdin().read_line(&mut line).expect("Failed to read from stdin.");
464+
if let Some(name) = line.strip_prefix("/name ") {
465+
ctx.reducers.set_name(name.to_string()).unwrap();
466+
} else {
467+
ctx.reducers.send_message(line).unwrap();
468+
}
469+
std::thread::sleep(std::time::Duration::from_secs(1));
470+
std::process::exit(0);
471+
}
441472
"#,
442473
connected_str: "connected",
443474
}
@@ -782,3 +813,12 @@ fn test_quickstart_typescript() {
782813
let mut qt = QuickstartTest::new(QuickstartConfig::typescript());
783814
qt.run_quickstart().expect("TypeScript quickstart test failed");
784815
}
816+
817+
/// Run the C++ quickstart for server (with Rust client).
818+
#[test]
819+
fn test_quickstart_cpp() {
820+
require_emscripten!();
821+
822+
let mut qt = QuickstartTest::new(QuickstartConfig::cpp());
823+
qt.run_quickstart().expect("C++ quickstart test failed");
824+
}

0 commit comments

Comments
 (0)