Skip to content

Commit 6964fb2

Browse files
authored
Adds testoperator dispatch infrastructure for CH-BenCHmark (HTAP) workloads. (spiceai#10868)
1 parent 082cb74 commit 6964fb2

10 files changed

Lines changed: 311 additions & 1 deletion

File tree

.github/workflows/testoperator_dispatch.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ on:
2626
- 'text-to-sql'
2727
- 'streaming-bench'
2828
- 'streaming-correctness'
29+
- 'htap'
2930
update_snapshots:
3031
description: 'Update snapshots?'
3132
required: false
@@ -115,6 +116,14 @@ jobs:
115116
"$SPICEPOD_VALIDATOR" "$file"
116117
done
117118
119+
- name: Validate spicepods - CH-BenCHmark - SF1
120+
run: |
121+
shopt -s globstar nullglob
122+
for file in ./test/spicepods/chbench/sf1/**/*.yaml; do
123+
echo "Validating $file"
124+
"$SPICEPOD_VALIDATOR" "$file"
125+
done
126+
118127
- name: Validate spicepods - TPCH - SF100
119128
run: |
120129
shopt -s globstar nullglob
@@ -195,6 +204,14 @@ jobs:
195204
SPICED_COMMIT: ${{ steps.setup-spiced.outputs.SPICED_COMMIT }}
196205
WORKFLOW_COMMIT: ${{ matrix.branch }}
197206

207+
- name: Dispatch Testoperator - Scheduled CH-BenCHmark - SF1
208+
run: |
209+
testoperator dispatch ./tools/testoperator/dispatch/chbench/sf1 --workflow htap
210+
env:
211+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
212+
SPICED_COMMIT: ${{ steps.setup-spiced.outputs.SPICED_COMMIT }}
213+
WORKFLOW_COMMIT: ${{ matrix.branch }}
214+
198215
dispatch-input:
199216
name: Dispatch tests - Input
200217
runs-on: spiceai-dev-runners
@@ -266,6 +283,15 @@ jobs:
266283
"$SPICEPOD_VALIDATOR" "$file"
267284
done
268285
286+
- name: Validate spicepods - CH-BenCHmark - SF1
287+
if: ${{ github.event.inputs.workflow_type == 'htap' }}
288+
run: |
289+
shopt -s globstar nullglob
290+
for file in ./test/spicepods/chbench/sf1/**/*.yaml; do
291+
echo "Validating $file"
292+
"$SPICEPOD_VALIDATOR" "$file"
293+
done
294+
269295
- name: Validate spicepods - TPCH - SF100
270296
run: |
271297
shopt -s globstar nullglob
@@ -351,3 +377,13 @@ jobs:
351377
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
352378
SPICED_COMMIT: ${{ steps.setup-spiced.outputs.SPICED_COMMIT }}
353379
WORKFLOW_COMMIT: ${{ github.event.ref }}
380+
381+
- name: Dispatch Testoperator - ${{ github.event.inputs.workflow_type }} - CH-BenCHmark - SF1
382+
run: |
383+
testoperator dispatch ./tools/testoperator/dispatch/chbench/sf1 \
384+
--workflow ${{ github.event.inputs.workflow_type }} \
385+
--update-snapshots ${{ github.event.inputs.update_snapshots }}
386+
env:
387+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
388+
SPICED_COMMIT: ${{ steps.setup-spiced.outputs.SPICED_COMMIT }}
389+
WORKFLOW_COMMIT: ${{ github.event.ref }}

crates/test-framework/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pub enum TestType {
6464
Streaming,
6565
StreamingCorrectness,
6666
Schema,
67+
Htap,
6768
}
6869

6970
impl TestType {
@@ -80,6 +81,7 @@ impl TestType {
8081
TestType::Streaming => "testoperator_run_streaming_bench.yml",
8182
TestType::StreamingCorrectness => "testoperator_run_streaming_correctness.yml",
8283
TestType::Schema => "testoperator_run_schema.yml",
84+
TestType::Htap => "testoperator_run_htap.yml",
8385
}
8486
}
8587
}
@@ -97,6 +99,7 @@ impl Display for TestType {
9799
TestType::Streaming => write!(f, "streaming"),
98100
TestType::StreamingCorrectness => write!(f, "streaming_correctness"),
99101
TestType::Schema => write!(f, "schema"),
102+
TestType::Htap => write!(f, "htap"),
100103
}
101104
}
102105
}
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
version: v1
2+
kind: Spicepod
3+
name: postgres-cayenne[file]-cdc-tuned
4+
5+
6+
runtime:
7+
params:
8+
cdc_prefetch_buffer: "1024"
9+
cdc_max_coalesced_envelopes: "1024"
10+
cdc_max_coalesced_bytes: "268435456" # 256 MB
11+
12+
datasets:
13+
# ---- TPC-C core tables (mutated by OLTP workload) ----
14+
15+
- from: postgres:warehouse
16+
name: warehouse
17+
params: &postgres_params
18+
pg_host: 127.0.0.1
19+
pg_port: 5432
20+
pg_db: chbench
21+
pg_user: bench
22+
pg_pass: bench
23+
pg_sslmode: disable
24+
pg_replication_slot: spice_warehouse
25+
pg_replication_initial_snapshot: "true"
26+
acceleration: &cayenne_accel
27+
enabled: true
28+
engine: cayenne
29+
mode: file
30+
refresh_mode: changes
31+
primary_key: w_id
32+
on_conflict:
33+
w_id: upsert
34+
params:
35+
cayenne_write_concurrency: "4"
36+
cayenne_upload_concurrency: "4"
37+
38+
- from: postgres:district
39+
name: district
40+
params:
41+
<<: *postgres_params
42+
pg_replication_slot: spice_district
43+
acceleration:
44+
<<: *cayenne_accel
45+
primary_key: (d_w_id, d_id)
46+
on_conflict:
47+
(d_w_id, d_id): upsert
48+
params:
49+
cayenne_write_concurrency: "4"
50+
cayenne_upload_concurrency: "4"
51+
52+
- from: postgres:customer
53+
name: customer
54+
params:
55+
<<: *postgres_params
56+
pg_replication_slot: spice_customer
57+
acceleration:
58+
<<: *cayenne_accel
59+
primary_key: (c_w_id, c_d_id, c_id)
60+
on_conflict:
61+
(c_w_id, c_d_id, c_id): upsert
62+
params:
63+
cayenne_write_concurrency: "4"
64+
cayenne_upload_concurrency: "4"
65+
66+
- from: postgres:new_order
67+
name: new_order
68+
params:
69+
<<: *postgres_params
70+
pg_replication_slot: spice_new_order
71+
acceleration:
72+
<<: *cayenne_accel
73+
primary_key: (no_w_id, no_d_id, no_o_id)
74+
on_conflict:
75+
(no_w_id, no_d_id, no_o_id): upsert
76+
params:
77+
cayenne_write_concurrency: "4"
78+
cayenne_upload_concurrency: "4"
79+
80+
- from: postgres:orders
81+
name: orders
82+
params:
83+
<<: *postgres_params
84+
pg_replication_slot: spice_orders
85+
acceleration:
86+
<<: *cayenne_accel
87+
primary_key: (o_w_id, o_d_id, o_id)
88+
on_conflict:
89+
(o_w_id, o_d_id, o_id): upsert
90+
params:
91+
cayenne_write_concurrency: "4"
92+
cayenne_upload_concurrency: "4"
93+
94+
- from: postgres:order_line
95+
name: order_line
96+
params:
97+
<<: *postgres_params
98+
pg_replication_slot: spice_order_line
99+
acceleration:
100+
<<: *cayenne_accel
101+
primary_key: (ol_w_id, ol_d_id, ol_o_id, ol_number)
102+
on_conflict:
103+
(ol_w_id, ol_d_id, ol_o_id, ol_number): upsert
104+
params:
105+
cayenne_write_concurrency: "4"
106+
cayenne_upload_concurrency: "4"
107+
108+
- from: postgres:item
109+
name: item
110+
params:
111+
<<: *postgres_params
112+
pg_replication_slot: spice_item
113+
acceleration:
114+
<<: *cayenne_accel
115+
primary_key: i_id
116+
on_conflict:
117+
i_id: upsert
118+
params:
119+
cayenne_write_concurrency: "4"
120+
cayenne_upload_concurrency: "4"
121+
122+
- from: postgres:stock
123+
name: stock
124+
params:
125+
<<: *postgres_params
126+
pg_replication_slot: spice_stock
127+
acceleration:
128+
<<: *cayenne_accel
129+
primary_key: (s_w_id, s_i_id)
130+
on_conflict:
131+
(s_w_id, s_i_id): upsert
132+
params:
133+
cayenne_write_concurrency: "4"
134+
cayenne_upload_concurrency: "4"
135+
136+
- from: postgres:region
137+
name: region
138+
params:
139+
<<: *postgres_params
140+
pg_replication_slot: spice_region
141+
acceleration:
142+
<<: *cayenne_accel
143+
primary_key: r_regionkey
144+
on_conflict:
145+
r_regionkey: upsert
146+
params:
147+
cayenne_write_concurrency: "4"
148+
cayenne_upload_concurrency: "4"
149+
150+
- from: postgres:nation
151+
name: nation
152+
params:
153+
<<: *postgres_params
154+
pg_replication_slot: spice_nation
155+
acceleration:
156+
<<: *cayenne_accel
157+
primary_key: n_nationkey
158+
on_conflict:
159+
n_nationkey: upsert
160+
params:
161+
cayenne_write_concurrency: "4"
162+
cayenne_upload_concurrency: "4"
163+
164+
- from: postgres:supplier
165+
name: supplier
166+
params:
167+
<<: *postgres_params
168+
pg_replication_slot: spice_supplier
169+
acceleration:
170+
<<: *cayenne_accel
171+
primary_key: s_suppkey
172+
on_conflict:
173+
s_suppkey: upsert
174+
params:
175+
cayenne_write_concurrency: "4"
176+
cayenne_upload_concurrency: "4"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
tests:
2+
htap:
3+
spicepod_path: accelerated/postgres-arrow.yaml
4+
runner_type: spiceai-dev-runners
5+
scale_factor: 1
6+
duration: 300
7+
ready_wait: 60
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
tests:
2+
htap:
3+
spicepod_path: accelerated/postgres-cayenne[file]-cdc-tuned.yaml
4+
runner_type: spiceai-dev-runners
5+
scale_factor: 1
6+
duration: 300
7+
ready_wait: 60
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
tests:
2+
htap:
3+
spicepod_path: accelerated/postgres-cayenne[file].yaml
4+
runner_type: spiceai-dev-runners
5+
scale_factor: 1
6+
duration: 300
7+
ready_wait: 60
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
tests:
2+
htap:
3+
spicepod_path: accelerated/postgres-duckdb[file].yaml
4+
runner_type: spiceai-dev-runners
5+
scale_factor: 1
6+
duration: 300
7+
ready_wait: 60

tools/testoperator/src/args/dispatch.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ pub enum Workflow {
6363
StreamingBench,
6464
StreamingCorrectness,
6565
Schema,
66+
Htap,
6667
}
6768

6869
impl From<Workflow> for TestType {
@@ -77,6 +78,7 @@ impl From<Workflow> for TestType {
7778
Workflow::StreamingBench => TestType::Streaming,
7879
Workflow::StreamingCorrectness => TestType::StreamingCorrectness,
7980
Workflow::Schema => TestType::Schema,
81+
Workflow::Htap => TestType::Htap,
8082
}
8183
}
8284
}
@@ -109,6 +111,8 @@ pub struct DispatchTests {
109111
pub streaming_correctness: Vec<StreamingCorrectnessDispatchArgs>,
110112
#[serde(deserialize_with = "deserialize_single_or_vec", default)]
111113
pub schema: Vec<SchemaArgs>,
114+
#[serde(deserialize_with = "deserialize_single_or_vec", default)]
115+
pub htap: Vec<HtapDispatchArgs>,
112116
}
113117

114118
/// Benchmark and throughput workflow arguments, defined in the test files
@@ -413,6 +417,24 @@ pub struct StreamingCorrectnessDispatchArgs {
413417
pub mutation_seed: Option<u64>,
414418
}
415419

420+
/// HTAP workflow arguments.
421+
///
422+
/// Mirrors the inputs of `testoperator_run_htap.yml`.
423+
#[derive(Debug, Clone, Deserialize, Serialize)]
424+
pub struct HtapDispatchArgs {
425+
pub spicepod_path: PathBuf,
426+
pub runner_type: RunnerType,
427+
#[serde(
428+
skip_serializing_if = "Option::is_none",
429+
serialize_with = "serialize_scale_factor"
430+
)]
431+
pub scale_factor: Option<f64>,
432+
#[serde(skip_serializing_if = "Option::is_none")]
433+
pub duration: Option<u64>,
434+
#[serde(skip_serializing_if = "Option::is_none")]
435+
pub ready_wait: Option<u64>,
436+
}
437+
416438
fn default_queryset() -> String {
417439
"tpch".to_string()
418440
}
@@ -575,5 +597,39 @@ tests: {}
575597
assert_eq!(test_file.tests.bench.len(), 0);
576598
assert_eq!(test_file.tests.throughput.len(), 0);
577599
assert_eq!(test_file.tests.load.len(), 0);
600+
assert_eq!(test_file.tests.htap.len(), 0);
601+
}
602+
603+
#[test]
604+
fn test_htap_section_deserialization() {
605+
let yaml = "
606+
tests:
607+
htap:
608+
spicepod_path: accelerated/postgres-cayenne[file].yaml
609+
runner_type: spiceai-dev-runners
610+
scale_factor: 1
611+
duration: 300
612+
ready_wait: 60
613+
";
614+
615+
let test_file: DispatchTestFile = yaml::from_str(yaml).expect("Failed to deserialize");
616+
617+
assert_eq!(test_file.tests.htap.len(), 1);
618+
assert_eq!(
619+
test_file.tests.htap[0].spicepod_path.to_string_lossy(),
620+
"accelerated/postgres-cayenne[file].yaml"
621+
);
622+
assert!(matches!(
623+
test_file.tests.htap[0].runner_type,
624+
RunnerType::Dev
625+
));
626+
assert_eq!(test_file.tests.htap[0].scale_factor, Some(1.0));
627+
assert_eq!(test_file.tests.htap[0].duration, Some(300));
628+
assert_eq!(test_file.tests.htap[0].ready_wait, Some(60));
629+
630+
// Verify scale_factor serializes as integer 1 (not 1.0) for GitHub workflow inputs
631+
let serialized =
632+
serde_json::to_value(&test_file.tests.htap[0]).expect("Failed to serialize");
633+
assert_eq!(serialized["scale_factor"], 1);
578634
}
579635
}

0 commit comments

Comments
 (0)