@feltdb/core 0.5.7 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands.js +68 -1
- package/dist/cli/workspace-integration.js +96 -0
- package/dist/create/cli.js +1 -1
- package/dist/create/create.js +21 -0
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +10 -0
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +1 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +5 -1
- package/dist/create/server-source/crates/feltdb-server/src/authenticated_principal.rs +273 -0
- package/dist/create/server-source/crates/feltdb-server/src/certification_harness.rs +528 -0
- package/dist/create/server-source/crates/feltdb-server/src/delegation_token.rs +472 -0
- package/dist/create/server-source/crates/feltdb-server/src/durable_operations.rs +992 -0
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +9 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +157 -9
- package/dist/create/server-source/crates/feltdb-server/src/managed_diagnostics.rs +413 -0
- package/dist/create/server-source/crates/feltdb-server/src/membership_policy.rs +488 -0
- package/dist/create/server-source/crates/feltdb-server/src/snapshot_cursor.rs +378 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +49 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenant_policies.rs +525 -0
- package/dist/create/server-source/crates/feltdb-server/src/transaction_recovery.rs +461 -0
- package/dist/create/template/dot-feltdb-README.md +58 -0
- package/dist/create/workspace-initialization.js +77 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/studio-app/assets/{feltdb_wasm-h9mxesnH.js → feltdb_wasm-B4wq4mqp.js} +1 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-Ceyi7l21.wasm +0 -0
- package/dist/studio-app/assets/{index-B_EMnTaE.js → index-LQmvJSq6.js} +2 -2
- package/dist/studio-app/index.html +1 -1
- package/dist/telemetry.js +1 -1
- package/dist/wasm/feltdb_wasm_bg.wasm +0 -0
- package/dist/workspace/development-node.d.ts +42 -0
- package/dist/workspace/development-node.d.ts.map +1 -0
- package/dist/workspace/development-node.js +208 -0
- package/dist/workspace/index.d.ts +20 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +16 -0
- package/dist/workspace/workspace-connection.d.ts +174 -0
- package/dist/workspace/workspace-connection.d.ts.map +1 -0
- package/dist/workspace/workspace-connection.js +290 -0
- package/dist/workspace/workspace-identity.d.ts +13 -0
- package/dist/workspace/workspace-identity.d.ts.map +1 -0
- package/dist/workspace/workspace-identity.js +70 -0
- package/dist/workspace/workspace-types.d.ts +82 -0
- package/dist/workspace/workspace-types.d.ts.map +1 -0
- package/dist/workspace/workspace-types.js +7 -0
- package/package.json +5 -1
- package/dist/studio-app/assets/feltdb_wasm_bg-B8U4A1n1.wasm +0 -0
|
@@ -0,0 +1,528 @@
|
|
|
1
|
+
use serde::{Deserialize, Serialize};
|
|
2
|
+
use std::collections::HashMap;
|
|
3
|
+
use std::time::{SystemTime, UNIX_EPOCH};
|
|
4
|
+
|
|
5
|
+
/// Test category for certification harness.
|
|
6
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash)]
|
|
7
|
+
#[serde(rename_all = "lowercase")]
|
|
8
|
+
pub enum TestCategory {
|
|
9
|
+
Authentication,
|
|
10
|
+
Authorization,
|
|
11
|
+
Pagination,
|
|
12
|
+
Transactions,
|
|
13
|
+
Operations,
|
|
14
|
+
Diagnostics,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
impl TestCategory {
|
|
18
|
+
pub fn as_str(&self) -> &'static str {
|
|
19
|
+
match self {
|
|
20
|
+
TestCategory::Authentication => "authentication",
|
|
21
|
+
TestCategory::Authorization => "authorization",
|
|
22
|
+
TestCategory::Pagination => "pagination",
|
|
23
|
+
TestCategory::Transactions => "transactions",
|
|
24
|
+
TestCategory::Operations => "operations",
|
|
25
|
+
TestCategory::Diagnostics => "diagnostics",
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/// Environment for test execution.
|
|
31
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
32
|
+
#[serde(rename_all = "lowercase")]
|
|
33
|
+
pub enum TestEnvironment {
|
|
34
|
+
Local,
|
|
35
|
+
ManagedStaging,
|
|
36
|
+
ManagedProduction,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
impl TestEnvironment {
|
|
40
|
+
pub fn as_str(&self) -> &'static str {
|
|
41
|
+
match self {
|
|
42
|
+
TestEnvironment::Local => "local",
|
|
43
|
+
TestEnvironment::ManagedStaging => "managed_staging",
|
|
44
|
+
TestEnvironment::ManagedProduction => "managed_production",
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// Test result status.
|
|
50
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
|
51
|
+
#[serde(rename_all = "lowercase")]
|
|
52
|
+
pub enum TestStatus {
|
|
53
|
+
Passed,
|
|
54
|
+
Failed,
|
|
55
|
+
Skipped,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// Individual test result.
|
|
59
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
60
|
+
pub struct TestResult {
|
|
61
|
+
pub test_id: String,
|
|
62
|
+
pub category: TestCategory,
|
|
63
|
+
pub name: String,
|
|
64
|
+
pub status: TestStatus,
|
|
65
|
+
pub error_message: Option<String>,
|
|
66
|
+
pub duration_ms: u64,
|
|
67
|
+
pub timestamp: u64,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
impl TestResult {
|
|
71
|
+
pub fn new(test_id: String, category: TestCategory, name: String) -> Self {
|
|
72
|
+
Self {
|
|
73
|
+
test_id,
|
|
74
|
+
category,
|
|
75
|
+
name,
|
|
76
|
+
status: TestStatus::Passed,
|
|
77
|
+
error_message: None,
|
|
78
|
+
duration_ms: 0,
|
|
79
|
+
timestamp: now(),
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
pub fn passed(mut self, duration_ms: u64) -> Self {
|
|
84
|
+
self.status = TestStatus::Passed;
|
|
85
|
+
self.duration_ms = duration_ms;
|
|
86
|
+
self
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
pub fn failed(mut self, error: String, duration_ms: u64) -> Self {
|
|
90
|
+
self.status = TestStatus::Failed;
|
|
91
|
+
self.error_message = Some(error);
|
|
92
|
+
self.duration_ms = duration_ms;
|
|
93
|
+
self
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
pub fn skipped(mut self, reason: String, duration_ms: u64) -> Self {
|
|
97
|
+
self.status = TestStatus::Skipped;
|
|
98
|
+
self.error_message = Some(reason);
|
|
99
|
+
self.duration_ms = duration_ms;
|
|
100
|
+
self
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
pub fn is_passing(&self) -> bool {
|
|
104
|
+
self.status == TestStatus::Passed
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/// Certification harness report.
|
|
109
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
110
|
+
pub struct CertificationReport {
|
|
111
|
+
/// Report ID (unique per run).
|
|
112
|
+
pub report_id: String,
|
|
113
|
+
|
|
114
|
+
/// Environment where tests ran.
|
|
115
|
+
pub environment: TestEnvironment,
|
|
116
|
+
|
|
117
|
+
/// Test results grouped by category.
|
|
118
|
+
pub results_by_category: HashMap<TestCategory, Vec<TestResult>>,
|
|
119
|
+
|
|
120
|
+
/// Overall pass/fail status.
|
|
121
|
+
pub overall_status: TestStatus,
|
|
122
|
+
|
|
123
|
+
/// When report was generated.
|
|
124
|
+
pub generated_at: u64,
|
|
125
|
+
|
|
126
|
+
/// Total duration of all tests (ms).
|
|
127
|
+
pub total_duration_ms: u64,
|
|
128
|
+
|
|
129
|
+
/// Summary statistics.
|
|
130
|
+
pub summary: CertificationSummary,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/// Summary statistics for certification report.
|
|
134
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
135
|
+
pub struct CertificationSummary {
|
|
136
|
+
pub total_tests: usize,
|
|
137
|
+
pub passed_tests: usize,
|
|
138
|
+
pub failed_tests: usize,
|
|
139
|
+
pub skipped_tests: usize,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
impl CertificationSummary {
|
|
143
|
+
pub fn pass_rate(&self) -> f64 {
|
|
144
|
+
if self.total_tests == 0 {
|
|
145
|
+
0.0
|
|
146
|
+
} else {
|
|
147
|
+
self.passed_tests as f64 / self.total_tests as f64 * 100.0
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
pub fn is_passing(&self) -> bool {
|
|
152
|
+
self.failed_tests == 0
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/// Test suite runner for certification harness.
|
|
157
|
+
pub struct CertificationHarness {
|
|
158
|
+
report_id: String,
|
|
159
|
+
environment: TestEnvironment,
|
|
160
|
+
results: HashMap<TestCategory, Vec<TestResult>>,
|
|
161
|
+
#[allow(dead_code)]
|
|
162
|
+
start_time: u64,
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
impl CertificationHarness {
|
|
166
|
+
/// Creates a new certification harness.
|
|
167
|
+
pub fn new(environment: TestEnvironment) -> Self {
|
|
168
|
+
Self {
|
|
169
|
+
report_id: format!("cert_{}", uuid_short()),
|
|
170
|
+
environment,
|
|
171
|
+
results: HashMap::new(),
|
|
172
|
+
start_time: now(),
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/// Records a test result.
|
|
177
|
+
pub fn record_result(&mut self, result: TestResult) {
|
|
178
|
+
self.results
|
|
179
|
+
.entry(result.category)
|
|
180
|
+
.or_insert_with(Vec::new)
|
|
181
|
+
.push(result);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/// Generates the final certification report.
|
|
185
|
+
pub fn generate_report(&self) -> CertificationReport {
|
|
186
|
+
let mut passed = 0;
|
|
187
|
+
let mut failed = 0;
|
|
188
|
+
let mut skipped = 0;
|
|
189
|
+
let mut total_duration = 0;
|
|
190
|
+
|
|
191
|
+
for results in self.results.values() {
|
|
192
|
+
for result in results {
|
|
193
|
+
match result.status {
|
|
194
|
+
TestStatus::Passed => passed += 1,
|
|
195
|
+
TestStatus::Failed => failed += 1,
|
|
196
|
+
TestStatus::Skipped => skipped += 1,
|
|
197
|
+
}
|
|
198
|
+
total_duration += result.duration_ms;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
let total = passed + failed + skipped;
|
|
203
|
+
let overall_status = if failed == 0 {
|
|
204
|
+
TestStatus::Passed
|
|
205
|
+
} else {
|
|
206
|
+
TestStatus::Failed
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
CertificationReport {
|
|
210
|
+
report_id: self.report_id.clone(),
|
|
211
|
+
environment: self.environment,
|
|
212
|
+
results_by_category: self.results.clone(),
|
|
213
|
+
overall_status,
|
|
214
|
+
generated_at: now(),
|
|
215
|
+
total_duration_ms: total_duration,
|
|
216
|
+
summary: CertificationSummary {
|
|
217
|
+
total_tests: total,
|
|
218
|
+
passed_tests: passed,
|
|
219
|
+
failed_tests: failed,
|
|
220
|
+
skipped_tests: skipped,
|
|
221
|
+
},
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/// Gets the count of tests in a category.
|
|
226
|
+
pub fn test_count(&self, category: TestCategory) -> usize {
|
|
227
|
+
self.results
|
|
228
|
+
.get(&category)
|
|
229
|
+
.map(|v| v.len())
|
|
230
|
+
.unwrap_or(0)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/// Gets all failed tests.
|
|
234
|
+
pub fn failed_tests(&self) -> Vec<&TestResult> {
|
|
235
|
+
self.results
|
|
236
|
+
.values()
|
|
237
|
+
.flat_map(|v| v.iter())
|
|
238
|
+
.filter(|r| r.status == TestStatus::Failed)
|
|
239
|
+
.collect()
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/// Test suite definition.
|
|
244
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
245
|
+
pub struct TestSuiteDefinition {
|
|
246
|
+
pub name: String,
|
|
247
|
+
pub description: String,
|
|
248
|
+
pub categories: Vec<TestCategory>,
|
|
249
|
+
pub min_required_pass_rate: f64,
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
impl TestSuiteDefinition {
|
|
253
|
+
/// Standard certification test suite.
|
|
254
|
+
pub fn standard() -> Self {
|
|
255
|
+
Self {
|
|
256
|
+
name: "FeltDB Sherpa Certification".to_string(),
|
|
257
|
+
description: "Standard certification suite for FeltDB Sherpa enablement".to_string(),
|
|
258
|
+
categories: vec![
|
|
259
|
+
TestCategory::Authentication,
|
|
260
|
+
TestCategory::Authorization,
|
|
261
|
+
TestCategory::Pagination,
|
|
262
|
+
TestCategory::Transactions,
|
|
263
|
+
TestCategory::Operations,
|
|
264
|
+
TestCategory::Diagnostics,
|
|
265
|
+
],
|
|
266
|
+
min_required_pass_rate: 95.0,
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/// Minimal smoke test suite.
|
|
271
|
+
pub fn minimal() -> Self {
|
|
272
|
+
Self {
|
|
273
|
+
name: "FeltDB Sherpa Smoke Test".to_string(),
|
|
274
|
+
description: "Quick smoke test for basic functionality".to_string(),
|
|
275
|
+
categories: vec![
|
|
276
|
+
TestCategory::Authentication,
|
|
277
|
+
TestCategory::Authorization,
|
|
278
|
+
TestCategory::Transactions,
|
|
279
|
+
],
|
|
280
|
+
min_required_pass_rate: 100.0,
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/// Test execution plan.
|
|
286
|
+
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
287
|
+
pub struct TestExecutionPlan {
|
|
288
|
+
pub suite: TestSuiteDefinition,
|
|
289
|
+
pub environment: TestEnvironment,
|
|
290
|
+
pub parallel_execution: bool,
|
|
291
|
+
pub timeout_secs: u64,
|
|
292
|
+
pub retry_failed: bool,
|
|
293
|
+
pub max_retries: u32,
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
impl TestExecutionPlan {
|
|
297
|
+
pub fn new(suite: TestSuiteDefinition, environment: TestEnvironment) -> Self {
|
|
298
|
+
Self {
|
|
299
|
+
suite,
|
|
300
|
+
environment,
|
|
301
|
+
parallel_execution: false,
|
|
302
|
+
timeout_secs: 300,
|
|
303
|
+
retry_failed: false,
|
|
304
|
+
max_retries: 0,
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
pub fn with_parallel(mut self) -> Self {
|
|
309
|
+
self.parallel_execution = true;
|
|
310
|
+
self
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
pub fn with_timeout(mut self, secs: u64) -> Self {
|
|
314
|
+
self.timeout_secs = secs;
|
|
315
|
+
self
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
pub fn with_retry(mut self, max_retries: u32) -> Self {
|
|
319
|
+
self.retry_failed = true;
|
|
320
|
+
self.max_retries = max_retries;
|
|
321
|
+
self
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
fn now() -> u64 {
|
|
326
|
+
SystemTime::now()
|
|
327
|
+
.duration_since(UNIX_EPOCH)
|
|
328
|
+
.unwrap_or_default()
|
|
329
|
+
.as_secs()
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
fn uuid_short() -> String {
|
|
333
|
+
use std::collections::hash_map::RandomState;
|
|
334
|
+
use std::hash::{BuildHasher, Hash, Hasher};
|
|
335
|
+
|
|
336
|
+
let mut hasher = RandomState::new().build_hasher();
|
|
337
|
+
now().hash(&mut hasher);
|
|
338
|
+
format!("{:x}", hasher.finish()).chars().take(8).collect()
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
#[cfg(test)]
|
|
342
|
+
mod tests {
|
|
343
|
+
use super::*;
|
|
344
|
+
|
|
345
|
+
#[test]
|
|
346
|
+
fn create_test_result() {
|
|
347
|
+
let result = TestResult::new(
|
|
348
|
+
"test_1".into(),
|
|
349
|
+
TestCategory::Authentication,
|
|
350
|
+
"verify_principal_creation".into(),
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
assert_eq!(result.status, TestStatus::Passed);
|
|
354
|
+
assert!(result.is_passing());
|
|
355
|
+
assert_eq!(result.test_id, "test_1");
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
#[test]
|
|
359
|
+
fn mark_test_as_failed() {
|
|
360
|
+
let result = TestResult::new(
|
|
361
|
+
"test_2".into(),
|
|
362
|
+
TestCategory::Authorization,
|
|
363
|
+
"verify_tenant_isolation".into(),
|
|
364
|
+
)
|
|
365
|
+
.failed("cross-tenant access allowed".into(), 150);
|
|
366
|
+
|
|
367
|
+
assert_eq!(result.status, TestStatus::Failed);
|
|
368
|
+
assert!(!result.is_passing());
|
|
369
|
+
assert_eq!(result.duration_ms, 150);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
#[test]
|
|
373
|
+
fn certification_harness_records_results() {
|
|
374
|
+
let mut harness = CertificationHarness::new(TestEnvironment::Local);
|
|
375
|
+
|
|
376
|
+
let result1 = TestResult::new(
|
|
377
|
+
"test_1".into(),
|
|
378
|
+
TestCategory::Authentication,
|
|
379
|
+
"test_1".into(),
|
|
380
|
+
)
|
|
381
|
+
.passed(100);
|
|
382
|
+
|
|
383
|
+
let result2 = TestResult::new(
|
|
384
|
+
"test_2".into(),
|
|
385
|
+
TestCategory::Authentication,
|
|
386
|
+
"test_2".into(),
|
|
387
|
+
)
|
|
388
|
+
.failed("connection timeout".into(), 200);
|
|
389
|
+
|
|
390
|
+
harness.record_result(result1);
|
|
391
|
+
harness.record_result(result2);
|
|
392
|
+
|
|
393
|
+
assert_eq!(harness.test_count(TestCategory::Authentication), 2);
|
|
394
|
+
assert_eq!(harness.failed_tests().len(), 1);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
#[test]
|
|
398
|
+
fn generate_certification_report() {
|
|
399
|
+
let mut harness = CertificationHarness::new(TestEnvironment::ManagedStaging);
|
|
400
|
+
|
|
401
|
+
for i in 0..5 {
|
|
402
|
+
let result = TestResult::new(
|
|
403
|
+
format!("test_{}", i),
|
|
404
|
+
TestCategory::Transactions,
|
|
405
|
+
format!("test_{}", i),
|
|
406
|
+
)
|
|
407
|
+
.passed(50);
|
|
408
|
+
|
|
409
|
+
harness.record_result(result);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
let result_failed = TestResult::new(
|
|
413
|
+
"test_failed".into(),
|
|
414
|
+
TestCategory::Transactions,
|
|
415
|
+
"failed_test".into(),
|
|
416
|
+
)
|
|
417
|
+
.failed("assertion failed".into(), 100);
|
|
418
|
+
|
|
419
|
+
harness.record_result(result_failed);
|
|
420
|
+
|
|
421
|
+
let report = harness.generate_report();
|
|
422
|
+
|
|
423
|
+
assert_eq!(report.summary.total_tests, 6);
|
|
424
|
+
assert_eq!(report.summary.passed_tests, 5);
|
|
425
|
+
assert_eq!(report.summary.failed_tests, 1);
|
|
426
|
+
assert_eq!(report.overall_status, TestStatus::Failed);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
#[test]
|
|
430
|
+
fn test_suite_definitions() {
|
|
431
|
+
let standard = TestSuiteDefinition::standard();
|
|
432
|
+
assert_eq!(standard.categories.len(), 6);
|
|
433
|
+
assert_eq!(standard.min_required_pass_rate, 95.0);
|
|
434
|
+
|
|
435
|
+
let minimal = TestSuiteDefinition::minimal();
|
|
436
|
+
assert_eq!(minimal.categories.len(), 3);
|
|
437
|
+
assert_eq!(minimal.min_required_pass_rate, 100.0);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
#[test]
|
|
441
|
+
fn test_execution_plan_builder() {
|
|
442
|
+
let plan = TestExecutionPlan::new(
|
|
443
|
+
TestSuiteDefinition::standard(),
|
|
444
|
+
TestEnvironment::Local,
|
|
445
|
+
)
|
|
446
|
+
.with_parallel()
|
|
447
|
+
.with_timeout(600)
|
|
448
|
+
.with_retry(3);
|
|
449
|
+
|
|
450
|
+
assert!(plan.parallel_execution);
|
|
451
|
+
assert_eq!(plan.timeout_secs, 600);
|
|
452
|
+
assert!(plan.retry_failed);
|
|
453
|
+
assert_eq!(plan.max_retries, 3);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
#[test]
|
|
457
|
+
fn certification_summary_pass_rate() {
|
|
458
|
+
let summary = CertificationSummary {
|
|
459
|
+
total_tests: 10,
|
|
460
|
+
passed_tests: 9,
|
|
461
|
+
failed_tests: 1,
|
|
462
|
+
skipped_tests: 0,
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
assert_eq!(summary.pass_rate(), 90.0);
|
|
466
|
+
assert!(!summary.is_passing());
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
#[test]
|
|
470
|
+
fn test_category_strings() {
|
|
471
|
+
assert_eq!(TestCategory::Authentication.as_str(), "authentication");
|
|
472
|
+
assert_eq!(TestCategory::Authorization.as_str(), "authorization");
|
|
473
|
+
assert_eq!(TestCategory::Pagination.as_str(), "pagination");
|
|
474
|
+
assert_eq!(TestCategory::Transactions.as_str(), "transactions");
|
|
475
|
+
assert_eq!(TestCategory::Operations.as_str(), "operations");
|
|
476
|
+
assert_eq!(TestCategory::Diagnostics.as_str(), "diagnostics");
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
#[test]
|
|
480
|
+
fn test_environment_strings() {
|
|
481
|
+
assert_eq!(TestEnvironment::Local.as_str(), "local");
|
|
482
|
+
assert_eq!(TestEnvironment::ManagedStaging.as_str(), "managed_staging");
|
|
483
|
+
assert_eq!(TestEnvironment::ManagedProduction.as_str(), "managed_production");
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
#[test]
|
|
487
|
+
fn certification_report_serialization() {
|
|
488
|
+
let mut harness = CertificationHarness::new(TestEnvironment::Local);
|
|
489
|
+
|
|
490
|
+
let result = TestResult::new(
|
|
491
|
+
"test_1".into(),
|
|
492
|
+
TestCategory::Operations,
|
|
493
|
+
"test_1".into(),
|
|
494
|
+
)
|
|
495
|
+
.passed(50);
|
|
496
|
+
|
|
497
|
+
harness.record_result(result);
|
|
498
|
+
|
|
499
|
+
let report = harness.generate_report();
|
|
500
|
+
let json = serde_json::to_string(&report).expect("serialize failed");
|
|
501
|
+
let deserialized: CertificationReport =
|
|
502
|
+
serde_json::from_str(&json).expect("deserialize failed");
|
|
503
|
+
|
|
504
|
+
assert_eq!(deserialized.report_id, report.report_id);
|
|
505
|
+
assert_eq!(deserialized.summary.total_tests, 1);
|
|
506
|
+
assert_eq!(deserialized.summary.passed_tests, 1);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
#[test]
|
|
510
|
+
fn failed_tests_filter() {
|
|
511
|
+
let mut harness = CertificationHarness::new(TestEnvironment::Local);
|
|
512
|
+
|
|
513
|
+
for i in 0..3 {
|
|
514
|
+
let result = if i == 1 {
|
|
515
|
+
TestResult::new(format!("test_{}", i), TestCategory::Authorization, format!("test_{}", i))
|
|
516
|
+
.failed("test failed".into(), 50)
|
|
517
|
+
} else {
|
|
518
|
+
TestResult::new(format!("test_{}", i), TestCategory::Authorization, format!("test_{}", i))
|
|
519
|
+
.passed(50)
|
|
520
|
+
};
|
|
521
|
+
harness.record_result(result);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
let failed = harness.failed_tests();
|
|
525
|
+
assert_eq!(failed.len(), 1);
|
|
526
|
+
assert_eq!(failed[0].test_id, "test_1");
|
|
527
|
+
}
|
|
528
|
+
}
|