1use std::fmt;
25use std::time::Duration;
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29pub enum WorkerLifecycleState {
30 NotCreated,
32 Loading,
34 Initializing,
36 Ready,
38 Processing,
40 Error,
42 Terminated,
44}
45
46impl Default for WorkerLifecycleState {
47 fn default() -> Self {
48 Self::NotCreated
49 }
50}
51
52impl fmt::Display for WorkerLifecycleState {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 Self::NotCreated => write!(f, "NotCreated"),
56 Self::Loading => write!(f, "Loading"),
57 Self::Initializing => write!(f, "Initializing"),
58 Self::Ready => write!(f, "Ready"),
59 Self::Processing => write!(f, "Processing"),
60 Self::Error => write!(f, "Error"),
61 Self::Terminated => write!(f, "Terminated"),
62 }
63 }
64}
65
66#[derive(Debug, Clone)]
68pub struct WorkerTestConfig {
69 pub init_timeout: Duration,
71 pub command_timeout: Duration,
73 pub max_messages: usize,
75 pub test_error_recovery: bool,
77 pub test_memory_leaks: bool,
79 pub stress_iterations: usize,
81 pub verify_lamport_ordering: bool,
83 pub test_shared_memory: bool,
85 pub ring_buffer_size: usize,
87}
88
89impl Default for WorkerTestConfig {
90 fn default() -> Self {
91 Self {
92 init_timeout: Duration::from_secs(10),
93 command_timeout: Duration::from_secs(30),
94 max_messages: 1000,
95 test_error_recovery: true,
96 test_memory_leaks: true,
97 stress_iterations: 100,
98 verify_lamport_ordering: true,
99 test_shared_memory: true,
100 ring_buffer_size: 16384, }
102 }
103}
104
105impl WorkerTestConfig {
106 #[must_use]
108 pub fn minimal() -> Self {
109 Self {
110 init_timeout: Duration::from_secs(5),
111 command_timeout: Duration::from_secs(5),
112 max_messages: 100,
113 test_error_recovery: false,
114 test_memory_leaks: false,
115 stress_iterations: 10,
116 verify_lamport_ordering: true,
117 test_shared_memory: false,
118 ring_buffer_size: 4096,
119 }
120 }
121
122 #[must_use]
124 pub fn comprehensive() -> Self {
125 Self {
126 init_timeout: Duration::from_secs(30),
127 command_timeout: Duration::from_secs(60),
128 max_messages: 10000,
129 test_error_recovery: true,
130 test_memory_leaks: true,
131 stress_iterations: 1000,
132 verify_lamport_ordering: true,
133 test_shared_memory: true,
134 ring_buffer_size: 65536, }
136 }
137}
138
139#[derive(Debug, Clone, Default)]
141pub struct WorkerTestResult {
142 pub passed: bool,
144 pub lifecycle_passed: bool,
146 pub ordering_passed: bool,
148 pub shared_memory_passed: bool,
150 pub ring_buffer_passed: bool,
152 pub error_recovery_passed: bool,
154 pub memory_leak_passed: bool,
156 pub failures: Vec<WorkerTestFailure>,
158 pub metrics: WorkerMetrics,
160}
161
162impl WorkerTestResult {
163 #[must_use]
165 pub fn is_passed(&self) -> bool {
166 self.passed && self.failures.is_empty()
167 }
168
169 #[must_use]
171 pub fn failure_count(&self) -> usize {
172 self.failures.len()
173 }
174}
175
176impl fmt::Display for WorkerTestResult {
177 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178 if self.is_passed() {
179 writeln!(f, "Worker Tests: PASSED")?;
180 } else {
181 writeln!(
182 f,
183 "Worker Tests: FAILED ({} failures)",
184 self.failure_count()
185 )?;
186 for failure in &self.failures {
187 writeln!(f, " - {failure}")?;
188 }
189 }
190
191 writeln!(f, "\nMetrics:")?;
192 writeln!(f, " Init time: {:?}", self.metrics.initialization_time)?;
193 writeln!(
194 f,
195 " Avg message latency: {:?}",
196 self.metrics.average_message_latency
197 )?;
198 writeln!(
199 f,
200 " Messages processed: {}",
201 self.metrics.messages_processed
202 )?;
203
204 Ok(())
205 }
206}
207
208#[derive(Debug, Clone)]
210pub struct WorkerTestFailure {
211 pub category: WorkerTestCategory,
213 pub description: String,
215 pub expected: String,
217 pub actual: String,
219}
220
221impl fmt::Display for WorkerTestFailure {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 write!(
224 f,
225 "[{:?}] {}: expected '{}', got '{}'",
226 self.category, self.description, self.expected, self.actual
227 )
228 }
229}
230
231#[derive(Debug, Clone, Copy, PartialEq, Eq)]
233pub enum WorkerTestCategory {
234 Lifecycle,
236 Ordering,
238 SharedMemory,
240 RingBuffer,
242 ErrorRecovery,
244 Memory,
246 Performance,
248}
249
250#[derive(Debug, Clone, Default)]
252pub struct WorkerMetrics {
253 pub initialization_time: Duration,
255 pub average_message_latency: Duration,
257 pub max_message_latency: Duration,
259 pub messages_processed: u64,
261 pub messages_dropped: u64,
263 pub memory_start: u64,
265 pub memory_end: u64,
267 pub error_recoveries: u32,
269}
270
271impl WorkerMetrics {
272 #[must_use]
274 pub fn has_memory_leak(&self) -> bool {
275 if self.memory_start == 0 {
276 return false;
277 }
278 let growth = self.memory_end.saturating_sub(self.memory_start);
279 let threshold = self.memory_start / 10; growth > threshold
281 }
282
283 #[must_use]
285 pub fn memory_growth(&self) -> i64 {
286 self.memory_end as i64 - self.memory_start as i64
287 }
288}
289
290#[derive(Debug, Clone)]
292pub struct RingBufferTestConfig {
293 pub buffer_size: usize,
295 pub sample_size: usize,
297 pub num_samples: usize,
299 pub test_overflow: bool,
301 pub test_underrun: bool,
303 pub test_concurrent: bool,
305}
306
307impl Default for RingBufferTestConfig {
308 fn default() -> Self {
309 Self {
310 buffer_size: 16384, sample_size: 512, num_samples: 1000,
313 test_overflow: true,
314 test_underrun: true,
315 test_concurrent: true,
316 }
317 }
318}
319
320#[derive(Debug, Clone, Default)]
322pub struct RingBufferTestResult {
323 pub passed: bool,
325 pub writes_succeeded: u64,
327 pub writes_failed: u64,
329 pub reads_succeeded: u64,
331 pub reads_failed: u64,
333 pub overflows_detected: u32,
335 pub underruns_detected: u32,
337 pub corruption_detected: bool,
339 pub failures: Vec<String>,
341}
342
343impl RingBufferTestResult {
344 #[must_use]
346 pub fn is_passed(&self) -> bool {
347 self.passed && !self.corruption_detected && self.failures.is_empty()
348 }
349}
350
351#[derive(Debug, Clone)]
353pub struct SharedMemoryTestConfig {
354 pub buffer_size: usize,
356 pub num_atomic_ops: usize,
358 pub test_wait_notify: bool,
360 pub test_concurrent_writes: bool,
362 pub wait_timeout: Duration,
364}
365
366impl Default for SharedMemoryTestConfig {
367 fn default() -> Self {
368 Self {
369 buffer_size: 4096,
370 num_atomic_ops: 1000,
371 test_wait_notify: true,
372 test_concurrent_writes: true,
373 wait_timeout: Duration::from_millis(100),
374 }
375 }
376}
377
378#[derive(Debug, Clone, Default)]
380pub struct SharedMemoryTestResult {
381 pub passed: bool,
383 pub atomics_correct: bool,
385 pub wait_notify_correct: bool,
387 pub visibility_correct: bool,
389 pub race_conditions_detected: u32,
391 pub failures: Vec<String>,
393}
394
395impl SharedMemoryTestResult {
396 #[must_use]
398 pub fn is_passed(&self) -> bool {
399 self.passed && self.race_conditions_detected == 0 && self.failures.is_empty()
400 }
401}
402
403#[derive(Debug, Clone)]
405pub struct WorkerTestHarness {
406 config: WorkerTestConfig,
407}
408
409impl Default for WorkerTestHarness {
410 fn default() -> Self {
411 Self::new()
412 }
413}
414
415impl WorkerTestHarness {
416 #[must_use]
418 pub fn new() -> Self {
419 Self {
420 config: WorkerTestConfig::default(),
421 }
422 }
423
424 #[must_use]
426 pub fn with_config(config: WorkerTestConfig) -> Self {
427 Self { config }
428 }
429
430 #[must_use]
432 pub fn config(&self) -> &WorkerTestConfig {
433 &self.config
434 }
435
436 #[must_use]
438 pub fn test_lifecycle_transitions(&self) -> Vec<WorkerTestFailure> {
439 let mut failures = Vec::new();
440
441 let valid_transitions: &[(WorkerLifecycleState, &[WorkerLifecycleState])] = &[
443 (
444 WorkerLifecycleState::NotCreated,
445 &[WorkerLifecycleState::Loading],
446 ),
447 (
448 WorkerLifecycleState::Loading,
449 &[
450 WorkerLifecycleState::Initializing,
451 WorkerLifecycleState::Error,
452 ],
453 ),
454 (
455 WorkerLifecycleState::Initializing,
456 &[WorkerLifecycleState::Ready, WorkerLifecycleState::Error],
457 ),
458 (
459 WorkerLifecycleState::Ready,
460 &[
461 WorkerLifecycleState::Processing,
462 WorkerLifecycleState::Error,
463 WorkerLifecycleState::Terminated,
464 ],
465 ),
466 (
467 WorkerLifecycleState::Processing,
468 &[
469 WorkerLifecycleState::Ready,
470 WorkerLifecycleState::Error,
471 WorkerLifecycleState::Terminated,
472 ],
473 ),
474 (
475 WorkerLifecycleState::Error,
476 &[
477 WorkerLifecycleState::Ready,
478 WorkerLifecycleState::Terminated,
479 ],
480 ),
481 (WorkerLifecycleState::Terminated, &[]),
482 ];
483
484 for (state, transitions) in valid_transitions {
486 if *state != WorkerLifecycleState::Terminated && transitions.is_empty() {
487 failures.push(WorkerTestFailure {
488 category: WorkerTestCategory::Lifecycle,
489 description: format!("State {} has no valid transitions", state),
490 expected: "at least one valid transition".to_string(),
491 actual: "no transitions".to_string(),
492 });
493 }
494 }
495
496 failures
497 }
498
499 #[must_use]
503 pub fn verify_message_ordering(&self, timestamps: &[u64]) -> Vec<WorkerTestFailure> {
504 let mut failures = Vec::new();
505
506 if !self.config.verify_lamport_ordering {
507 return failures;
508 }
509
510 let mut last_time = 0u64;
511 for (i, &time) in timestamps.iter().enumerate() {
512 if time < last_time {
513 failures.push(WorkerTestFailure {
514 category: WorkerTestCategory::Ordering,
515 description: format!("Message {} violates Lamport ordering", i),
516 expected: format!("timestamp > {last_time}"),
517 actual: format!("timestamp = {time}"),
518 });
519 }
520 last_time = time;
521 }
522
523 failures
524 }
525
526 #[must_use]
528 pub fn test_ring_buffer(&self, config: &RingBufferTestConfig) -> RingBufferTestResult {
529 let mut result = RingBufferTestResult {
530 passed: true,
531 ..Default::default()
532 };
533
534 let capacity = config.buffer_size / config.sample_size;
536
537 for i in 0..config.num_samples {
539 if i < capacity {
540 result.writes_succeeded += 1;
541 } else if config.test_overflow {
542 result.overflows_detected += 1;
544 if result.overflows_detected == 1 {
545 result.writes_succeeded += 1;
547 } else {
548 result.writes_failed += 1;
549 }
550 } else {
551 result.writes_failed += 1;
552 }
553 }
554
555 for i in 0..config.num_samples {
557 if (i as u64) < result.writes_succeeded {
558 result.reads_succeeded += 1;
559 } else if config.test_underrun {
560 result.underruns_detected += 1;
561 result.reads_failed += 1;
562 } else {
563 result.reads_failed += 1;
564 }
565 }
566
567 if result.writes_failed > 0 && !config.test_overflow {
569 result.failures.push(format!(
570 "Write failures without overflow testing: {}",
571 result.writes_failed
572 ));
573 result.passed = false;
574 }
575
576 result
577 }
578
579 #[must_use]
581 pub fn test_shared_memory(&self, config: &SharedMemoryTestConfig) -> SharedMemoryTestResult {
582 if !self.config.test_shared_memory {
583 return SharedMemoryTestResult {
584 passed: true,
585 atomics_correct: true,
586 wait_notify_correct: true,
587 visibility_correct: true,
588 ..Default::default()
589 };
590 }
591
592 let mut result = SharedMemoryTestResult {
593 passed: true,
594 atomics_correct: true,
595 wait_notify_correct: config.test_wait_notify,
596 visibility_correct: true,
597 ..Default::default()
598 };
599
600 let mut counter = 0i64;
603 for _ in 0..config.num_atomic_ops {
604 counter += 1;
606 }
607
608 if counter != config.num_atomic_ops as i64 {
610 result.atomics_correct = false;
611 result.race_conditions_detected += 1;
612 result.failures.push(format!(
613 "Atomic counter mismatch: expected {}, got {}",
614 config.num_atomic_ops, counter
615 ));
616 result.passed = false;
617 }
618
619 result
620 }
621
622 #[must_use]
624 pub fn lifecycle_test_js() -> &'static str {
625 r#"
626(function() {
627 const states = [];
628 const transitions = [];
629
630 window.__PROBAR_WORKER_STATES__ = states;
631 window.__PROBAR_WORKER_TRANSITIONS__ = transitions;
632
633 function recordState(workerId, state) {
634 const timestamp = performance.now();
635 states.push({ workerId, state, timestamp });
636 }
637
638 function recordTransition(workerId, from, to) {
639 const timestamp = performance.now();
640 transitions.push({ workerId, from, to, timestamp });
641 }
642
643 // Intercept Worker construction
644 const originalWorker = window.Worker;
645 window.Worker = function(url, options) {
646 const worker = new originalWorker(url, options);
647 const workerId = states.filter(s => s.state === 'NotCreated').length;
648
649 recordState(workerId, 'NotCreated');
650 recordTransition(workerId, 'NotCreated', 'Loading');
651 recordState(workerId, 'Loading');
652
653 worker.addEventListener('message', function(e) {
654 const data = e.data;
655 if (data && data.type) {
656 const type = data.type.toLowerCase();
657 const currentState = states.filter(s => s.workerId === workerId).pop()?.state || 'Loading';
658
659 if (type === 'ready' || type === 'initialized') {
660 recordTransition(workerId, currentState, 'Ready');
661 recordState(workerId, 'Ready');
662 } else if (type === 'error') {
663 recordTransition(workerId, currentState, 'Error');
664 recordState(workerId, 'Error');
665 } else if (type === 'processing' || type === 'busy') {
666 recordTransition(workerId, currentState, 'Processing');
667 recordState(workerId, 'Processing');
668 } else if (type === 'complete' || type === 'done') {
669 recordTransition(workerId, currentState, 'Ready');
670 recordState(workerId, 'Ready');
671 }
672 }
673 });
674
675 worker.addEventListener('error', function(e) {
676 const currentState = states.filter(s => s.workerId === workerId).pop()?.state || 'Loading';
677 recordTransition(workerId, currentState, 'Error');
678 recordState(workerId, 'Error');
679 });
680
681 return worker;
682 };
683
684 return { success: true };
685})();
686"#
687 }
688
689 #[must_use]
691 pub fn ring_buffer_test_js(buffer_size: usize) -> String {
692 format!(
693 r#"
694(function() {{
695 const BUFFER_SIZE = {buffer_size};
696 const HEADER_SIZE = 64; // Cache-line aligned header
697 const DATA_OFFSET = HEADER_SIZE;
698
699 // Create SharedArrayBuffer
700 const sab = new SharedArrayBuffer(BUFFER_SIZE + HEADER_SIZE);
701 const header = new Int32Array(sab, 0, 4);
702 const data = new Float32Array(sab, DATA_OFFSET);
703
704 // Initialize header
705 // [0] = write_idx, [1] = read_idx, [2] = capacity, [3] = flags
706 Atomics.store(header, 0, 0);
707 Atomics.store(header, 1, 0);
708 Atomics.store(header, 2, data.length);
709 Atomics.store(header, 3, 0);
710
711 window.__PROBAR_RING_BUFFER__ = {{
712 sab: sab,
713 header: header,
714 data: data,
715 write: function(samples) {{
716 const writeIdx = Atomics.load(header, 0);
717 const readIdx = Atomics.load(header, 1);
718 const capacity = Atomics.load(header, 2);
719 const available = capacity - (writeIdx - readIdx);
720
721 if (samples.length > available) {{
722 return {{ success: false, error: 'overflow', available: available }};
723 }}
724
725 for (let i = 0; i < samples.length; i++) {{
726 data[(writeIdx + i) % capacity] = samples[i];
727 }}
728
729 Atomics.store(header, 0, writeIdx + samples.length);
730 return {{ success: true, written: samples.length }};
731 }},
732 read: function(count) {{
733 const writeIdx = Atomics.load(header, 0);
734 const readIdx = Atomics.load(header, 1);
735 const available = writeIdx - readIdx;
736
737 if (count > available) {{
738 return {{ success: false, error: 'underrun', available: available }};
739 }}
740
741 const capacity = Atomics.load(header, 2);
742 const result = new Float32Array(count);
743 for (let i = 0; i < count; i++) {{
744 result[i] = data[(readIdx + i) % capacity];
745 }}
746
747 Atomics.store(header, 1, readIdx + count);
748 return {{ success: true, data: Array.from(result) }};
749 }},
750 getStats: function() {{
751 return {{
752 writeIdx: Atomics.load(header, 0),
753 readIdx: Atomics.load(header, 1),
754 capacity: Atomics.load(header, 2),
755 available: Atomics.load(header, 2) - (Atomics.load(header, 0) - Atomics.load(header, 1))
756 }};
757 }}
758 }};
759
760 return {{ success: true, bufferSize: BUFFER_SIZE }};
761}})();
762"#
763 )
764 }
765
766 #[must_use]
768 pub fn shared_memory_test_js(buffer_size: usize) -> String {
769 format!(
770 r#"
771(function() {{
772 const BUFFER_SIZE = {buffer_size};
773
774 // Create SharedArrayBuffer for atomic operations
775 const sab = new SharedArrayBuffer(BUFFER_SIZE);
776 const int32View = new Int32Array(sab);
777
778 window.__PROBAR_SHARED_MEMORY__ = {{
779 sab: sab,
780 int32View: int32View,
781
782 // Test Atomics.add
783 testAtomicAdd: function(index, count) {{
784 let result = 0;
785 for (let i = 0; i < count; i++) {{
786 result = Atomics.add(int32View, index, 1);
787 }}
788 return {{ finalValue: Atomics.load(int32View, index), lastResult: result }};
789 }},
790
791 // Test Atomics.compareExchange
792 testCompareExchange: function(index, expected, replacement) {{
793 const oldValue = Atomics.compareExchange(int32View, index, expected, replacement);
794 return {{ oldValue: oldValue, newValue: Atomics.load(int32View, index) }};
795 }},
796
797 // Test Atomics.wait/notify (must be called from worker)
798 testWaitNotify: function(index) {{
799 return {{
800 info: 'Atomics.wait must be called from a worker thread',
801 canUseWait: typeof SharedArrayBuffer !== 'undefined'
802 }};
803 }},
804
805 // Get memory stats
806 getStats: function() {{
807 return {{
808 bufferSize: BUFFER_SIZE,
809 int32Length: int32View.length
810 }};
811 }},
812
813 // Reset all values
814 reset: function() {{
815 for (let i = 0; i < int32View.length; i++) {{
816 Atomics.store(int32View, i, 0);
817 }}
818 return {{ success: true }};
819 }}
820 }};
821
822 return {{ success: true, bufferSize: BUFFER_SIZE }};
823}})();
824"#
825 )
826 }
827
828 #[must_use]
830 pub fn validate_results(&self, result: &WorkerTestResult) -> bool {
831 if !result.lifecycle_passed {
832 return false;
833 }
834
835 if self.config.verify_lamport_ordering && !result.ordering_passed {
836 return false;
837 }
838
839 if self.config.test_shared_memory && !result.shared_memory_passed {
840 return false;
841 }
842
843 if self.config.test_error_recovery && !result.error_recovery_passed {
844 return false;
845 }
846
847 if self.config.test_memory_leaks && !result.memory_leak_passed {
848 return false;
849 }
850
851 result.failures.is_empty()
852 }
853}
854
855#[derive(Debug, Clone)]
857pub enum WorkerTestError {
858 InitializationFailed(String),
860 Timeout(String),
862 ProtocolError(String),
864 CdpError(String),
866}
867
868impl fmt::Display for WorkerTestError {
869 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
870 match self {
871 Self::InitializationFailed(msg) => write!(f, "Initialization failed: {msg}"),
872 Self::Timeout(msg) => write!(f, "Timeout: {msg}"),
873 Self::ProtocolError(msg) => write!(f, "Protocol error: {msg}"),
874 Self::CdpError(msg) => write!(f, "CDP error: {msg}"),
875 }
876 }
877}
878
879impl std::error::Error for WorkerTestError {}
880
881#[cfg(test)]
882#[allow(clippy::unwrap_used, clippy::expect_used)]
883mod tests {
884 use super::*;
885
886 #[test]
891 fn h0_wh_01_lifecycle_state_display() {
892 assert_eq!(
893 format!("{}", WorkerLifecycleState::NotCreated),
894 "NotCreated"
895 );
896 assert_eq!(format!("{}", WorkerLifecycleState::Loading), "Loading");
897 assert_eq!(format!("{}", WorkerLifecycleState::Ready), "Ready");
898 assert_eq!(
899 format!("{}", WorkerLifecycleState::Processing),
900 "Processing"
901 );
902 assert_eq!(format!("{}", WorkerLifecycleState::Error), "Error");
903 assert_eq!(
904 format!("{}", WorkerLifecycleState::Terminated),
905 "Terminated"
906 );
907 assert_eq!(
908 format!("{}", WorkerLifecycleState::Initializing),
909 "Initializing"
910 );
911 }
912
913 #[test]
914 fn h0_wh_02_lifecycle_state_default() {
915 let state = WorkerLifecycleState::default();
916 assert_eq!(state, WorkerLifecycleState::NotCreated);
917 }
918
919 #[test]
924 fn h0_wh_03_default_config() {
925 let config = WorkerTestConfig::default();
926 assert_eq!(config.init_timeout, Duration::from_secs(10));
927 assert!(config.test_error_recovery);
928 assert!(config.verify_lamport_ordering);
929 }
930
931 #[test]
932 fn h0_wh_04_minimal_config() {
933 let config = WorkerTestConfig::minimal();
934 assert_eq!(config.stress_iterations, 10);
935 assert!(!config.test_error_recovery);
936 assert!(!config.test_memory_leaks);
937 }
938
939 #[test]
940 fn h0_wh_05_comprehensive_config() {
941 let config = WorkerTestConfig::comprehensive();
942 assert_eq!(config.stress_iterations, 1000);
943 assert!(config.test_error_recovery);
944 assert!(config.test_memory_leaks);
945 }
946
947 #[test]
952 fn h0_wh_06_harness_creation() {
953 let harness = WorkerTestHarness::new();
954 assert!(harness.config().verify_lamport_ordering);
955 }
956
957 #[test]
958 fn h0_wh_07_harness_with_config() {
959 let config = WorkerTestConfig::minimal();
960 let harness = WorkerTestHarness::with_config(config);
961 assert_eq!(harness.config().stress_iterations, 10);
962 }
963
964 #[test]
965 fn h0_wh_08_harness_default() {
966 let harness = WorkerTestHarness::default();
967 assert!(harness.config().test_shared_memory);
968 }
969
970 #[test]
975 fn h0_wh_09_valid_lifecycle_transitions() {
976 let harness = WorkerTestHarness::new();
977 let failures = harness.test_lifecycle_transitions();
978 assert!(failures.is_empty());
980 }
981
982 #[test]
987 fn h0_wh_10_valid_ordering() {
988 let harness = WorkerTestHarness::new();
989 let timestamps = vec![1, 2, 3, 4, 5];
990 let failures = harness.verify_message_ordering(×tamps);
991 assert!(failures.is_empty());
992 }
993
994 #[test]
995 fn h0_wh_11_invalid_ordering() {
996 let harness = WorkerTestHarness::new();
997 let timestamps = vec![1, 2, 5, 3, 6]; let failures = harness.verify_message_ordering(×tamps);
999 assert!(!failures.is_empty());
1000 assert_eq!(failures[0].category, WorkerTestCategory::Ordering);
1001 }
1002
1003 #[test]
1004 fn h0_wh_12_ordering_disabled() {
1005 let config = WorkerTestConfig {
1006 verify_lamport_ordering: false,
1007 ..Default::default()
1008 };
1009 let harness = WorkerTestHarness::with_config(config);
1010 let timestamps = vec![5, 3, 1]; let failures = harness.verify_message_ordering(×tamps);
1012 assert!(failures.is_empty());
1013 }
1014
1015 #[test]
1020 fn h0_wh_13_ring_buffer_basic() {
1021 let harness = WorkerTestHarness::new();
1022 let config = RingBufferTestConfig::default();
1023 let result = harness.test_ring_buffer(&config);
1024 assert!(result.writes_succeeded > 0);
1025 assert!(result.reads_succeeded > 0);
1026 }
1027
1028 #[test]
1029 fn h0_wh_14_ring_buffer_overflow() {
1030 let harness = WorkerTestHarness::new();
1031 let config = RingBufferTestConfig {
1032 buffer_size: 1024,
1033 sample_size: 512,
1034 num_samples: 100, test_overflow: true,
1036 ..Default::default()
1037 };
1038 let result = harness.test_ring_buffer(&config);
1039 assert!(result.overflows_detected > 0);
1040 }
1041
1042 #[test]
1043 fn h0_wh_15_ring_buffer_underrun() {
1044 let harness = WorkerTestHarness::new();
1045 let config = RingBufferTestConfig {
1046 buffer_size: 16384,
1047 sample_size: 512,
1048 num_samples: 100,
1049 test_underrun: true,
1050 ..Default::default()
1051 };
1052 let result = harness.test_ring_buffer(&config);
1053 assert!(result.underruns_detected > 0 || result.reads_failed > 0);
1055 }
1056
1057 #[test]
1062 fn h0_wh_16_shared_memory_basic() {
1063 let harness = WorkerTestHarness::new();
1064 let config = SharedMemoryTestConfig::default();
1065 let result = harness.test_shared_memory(&config);
1066 assert!(result.atomics_correct);
1067 }
1068
1069 #[test]
1070 fn h0_wh_17_shared_memory_disabled() {
1071 let config = WorkerTestConfig {
1072 test_shared_memory: false,
1073 ..Default::default()
1074 };
1075 let harness = WorkerTestHarness::with_config(config);
1076 let sm_config = SharedMemoryTestConfig::default();
1077 let result = harness.test_shared_memory(&sm_config);
1078 assert!(result.is_passed());
1079 }
1080
1081 #[test]
1086 fn h0_wh_18_metrics_memory_leak_detection() {
1087 let mut metrics = WorkerMetrics::default();
1088 metrics.memory_start = 1000;
1089 metrics.memory_end = 1200; assert!(metrics.has_memory_leak());
1091 }
1092
1093 #[test]
1094 fn h0_wh_19_metrics_no_memory_leak() {
1095 let mut metrics = WorkerMetrics::default();
1096 metrics.memory_start = 1000;
1097 metrics.memory_end = 1050; assert!(!metrics.has_memory_leak());
1099 }
1100
1101 #[test]
1102 fn h0_wh_20_metrics_memory_growth() {
1103 let mut metrics = WorkerMetrics::default();
1104 metrics.memory_start = 1000;
1105 metrics.memory_end = 1500;
1106 assert_eq!(metrics.memory_growth(), 500);
1107 }
1108
1109 #[test]
1110 fn h0_wh_21_metrics_memory_shrink() {
1111 let mut metrics = WorkerMetrics::default();
1112 metrics.memory_start = 1000;
1113 metrics.memory_end = 800;
1114 assert_eq!(metrics.memory_growth(), -200);
1115 }
1116
1117 #[test]
1118 fn h0_wh_22_metrics_zero_start() {
1119 let metrics = WorkerMetrics::default();
1120 assert!(!metrics.has_memory_leak());
1121 }
1122
1123 #[test]
1128 fn h0_wh_23_result_is_passed() {
1129 let result = WorkerTestResult {
1130 passed: true,
1131 lifecycle_passed: true,
1132 ordering_passed: true,
1133 shared_memory_passed: true,
1134 ring_buffer_passed: true,
1135 error_recovery_passed: true,
1136 memory_leak_passed: true,
1137 failures: vec![],
1138 ..Default::default()
1139 };
1140 assert!(result.is_passed());
1141 }
1142
1143 #[test]
1144 fn h0_wh_24_result_with_failures() {
1145 let result = WorkerTestResult {
1146 passed: false,
1147 failures: vec![WorkerTestFailure {
1148 category: WorkerTestCategory::Lifecycle,
1149 description: "test".to_string(),
1150 expected: "a".to_string(),
1151 actual: "b".to_string(),
1152 }],
1153 ..Default::default()
1154 };
1155 assert!(!result.is_passed());
1156 assert_eq!(result.failure_count(), 1);
1157 }
1158
1159 #[test]
1160 fn h0_wh_25_result_display() {
1161 let result = WorkerTestResult {
1162 passed: true,
1163 metrics: WorkerMetrics {
1164 initialization_time: Duration::from_millis(100),
1165 average_message_latency: Duration::from_micros(500),
1166 messages_processed: 1000,
1167 ..Default::default()
1168 },
1169 ..Default::default()
1170 };
1171 let display = format!("{result}");
1172 assert!(display.contains("PASSED"));
1173 assert!(display.contains("Messages processed: 1000"));
1174 }
1175
1176 #[test]
1181 fn h0_wh_26_failure_display() {
1182 let failure = WorkerTestFailure {
1183 category: WorkerTestCategory::Ordering,
1184 description: "Out of order".to_string(),
1185 expected: "5".to_string(),
1186 actual: "3".to_string(),
1187 };
1188 let display = format!("{failure}");
1189 assert!(display.contains("Ordering"));
1190 assert!(display.contains("Out of order"));
1191 assert!(display.contains("expected '5'"));
1192 }
1193
1194 #[test]
1199 fn h0_wh_27_lifecycle_test_js() {
1200 let js = WorkerTestHarness::lifecycle_test_js();
1201 assert!(js.contains("__PROBAR_WORKER_STATES__"));
1202 assert!(js.contains("recordState"));
1203 assert!(js.contains("recordTransition"));
1204 }
1205
1206 #[test]
1207 fn h0_wh_28_ring_buffer_test_js() {
1208 let js = WorkerTestHarness::ring_buffer_test_js(16384);
1209 assert!(js.contains("__PROBAR_RING_BUFFER__"));
1210 assert!(js.contains("SharedArrayBuffer"));
1211 assert!(js.contains("Atomics.load"));
1212 assert!(js.contains("16384"));
1213 }
1214
1215 #[test]
1216 fn h0_wh_29_shared_memory_test_js() {
1217 let js = WorkerTestHarness::shared_memory_test_js(4096);
1218 assert!(js.contains("__PROBAR_SHARED_MEMORY__"));
1219 assert!(js.contains("testAtomicAdd"));
1220 assert!(js.contains("testCompareExchange"));
1221 assert!(js.contains("4096"));
1222 }
1223
1224 #[test]
1229 fn h0_wh_30_validate_results_passed() {
1230 let harness = WorkerTestHarness::new();
1231 let result = WorkerTestResult {
1232 passed: true,
1233 lifecycle_passed: true,
1234 ordering_passed: true,
1235 shared_memory_passed: true,
1236 ring_buffer_passed: true,
1237 error_recovery_passed: true,
1238 memory_leak_passed: true,
1239 failures: vec![],
1240 ..Default::default()
1241 };
1242 assert!(harness.validate_results(&result));
1243 }
1244
1245 #[test]
1246 fn h0_wh_31_validate_results_lifecycle_failed() {
1247 let harness = WorkerTestHarness::new();
1248 let result = WorkerTestResult {
1249 lifecycle_passed: false,
1250 ..Default::default()
1251 };
1252 assert!(!harness.validate_results(&result));
1253 }
1254
1255 #[test]
1256 fn h0_wh_32_validate_results_ordering_failed() {
1257 let harness = WorkerTestHarness::new();
1258 let result = WorkerTestResult {
1259 lifecycle_passed: true,
1260 ordering_passed: false,
1261 ..Default::default()
1262 };
1263 assert!(!harness.validate_results(&result));
1264 }
1265
1266 #[test]
1271 fn h0_wh_33_error_display() {
1272 let err = WorkerTestError::InitializationFailed("worker failed".to_string());
1273 assert!(err.to_string().contains("Initialization"));
1274
1275 let err = WorkerTestError::Timeout("10s".to_string());
1276 assert!(err.to_string().contains("Timeout"));
1277
1278 let err = WorkerTestError::ProtocolError("bad message".to_string());
1279 assert!(err.to_string().contains("Protocol"));
1280
1281 let err = WorkerTestError::CdpError("connection lost".to_string());
1282 assert!(err.to_string().contains("CDP"));
1283 }
1284
1285 #[test]
1290 fn h0_wh_34_ring_buffer_result_passed() {
1291 let result = RingBufferTestResult {
1292 passed: true,
1293 corruption_detected: false,
1294 failures: vec![],
1295 ..Default::default()
1296 };
1297 assert!(result.is_passed());
1298 }
1299
1300 #[test]
1301 fn h0_wh_35_ring_buffer_result_corruption() {
1302 let result = RingBufferTestResult {
1303 passed: true,
1304 corruption_detected: true,
1305 ..Default::default()
1306 };
1307 assert!(!result.is_passed());
1308 }
1309
1310 #[test]
1315 fn h0_wh_36_shared_memory_result_passed() {
1316 let result = SharedMemoryTestResult {
1317 passed: true,
1318 race_conditions_detected: 0,
1319 failures: vec![],
1320 ..Default::default()
1321 };
1322 assert!(result.is_passed());
1323 }
1324
1325 #[test]
1326 fn h0_wh_37_shared_memory_result_race_condition() {
1327 let result = SharedMemoryTestResult {
1328 passed: true,
1329 race_conditions_detected: 1,
1330 ..Default::default()
1331 };
1332 assert!(!result.is_passed());
1333 }
1334
1335 #[test]
1340 fn h0_wh_38_ring_buffer_config_default() {
1341 let config = RingBufferTestConfig::default();
1342 assert_eq!(config.buffer_size, 16384);
1343 assert!(config.test_overflow);
1344 assert!(config.test_underrun);
1345 }
1346
1347 #[test]
1348 fn h0_wh_39_shared_memory_config_default() {
1349 let config = SharedMemoryTestConfig::default();
1350 assert_eq!(config.buffer_size, 4096);
1351 assert!(config.test_wait_notify);
1352 assert!(config.test_concurrent_writes);
1353 }
1354}