3
3
//! Provides secure Lua script execution with context injection, timeout enforcement,
4
4
//! and resource monitoring for test validation scenarios.
5
5
6
+ use crate :: script_engines:: memory_tracker:: { MemoryTracker , MemoryTrackingConfig } ;
6
7
use crate :: script_engines:: { ScriptConfig , ScriptContext , ScriptError , ScriptResult } ;
7
8
use mlua:: { Lua , LuaSerdeExt , Result as LuaResult , Value as LuaValue } ;
8
9
use std:: time:: { Duration , Instant } ;
@@ -183,6 +184,18 @@ impl LuaEngine {
183
184
let start_time = Instant :: now ( ) ;
184
185
let security_manager = SecurityManager :: new ( & self . config ) ;
185
186
187
+ // Initialize memory tracking
188
+ let memory_config = MemoryTrackingConfig :: default ( ) ;
189
+ let memory_tracker = MemoryTracker :: new ( memory_config) ;
190
+
191
+ // Take memory snapshot before execution
192
+ let memory_before =
193
+ memory_tracker
194
+ . snapshot ( )
195
+ . map_err ( |e| ScriptError :: MemoryTrackingError {
196
+ message : format ! ( "Failed to take initial memory snapshot: {}" , e) ,
197
+ } ) ?;
198
+
186
199
// Inject context into Lua environment
187
200
self . inject_context ( & context) ?;
188
201
@@ -194,19 +207,30 @@ impl LuaEngine {
194
207
)
195
208
. await ;
196
209
197
- let duration = start_time. elapsed ( ) ;
210
+ // Take memory snapshot after execution
211
+ let memory_after =
212
+ memory_tracker
213
+ . snapshot ( )
214
+ . map_err ( |e| ScriptError :: MemoryTrackingError {
215
+ message : format ! ( "Failed to take final memory snapshot: {}" , e) ,
216
+ } ) ?;
217
+
218
+ // Calculate memory usage
219
+ let memory_delta = memory_tracker. calculate_delta ( & memory_before, & memory_after) ;
220
+ let memory_used_mb = Some ( memory_tracker. delta_to_mb ( & memory_delta) ) ;
198
221
222
+ let duration = start_time. elapsed ( ) ;
199
223
let duration_ms = duration. as_millis ( ) as u64 ;
200
224
201
225
match lua_result {
202
- Ok ( Ok ( lua_value) ) => self . extract_result ( lua_value, duration_ms) ,
203
- Ok ( Err ( lua_error) ) => self . handle_lua_error ( lua_error, duration_ms) ,
226
+ Ok ( Ok ( lua_value) ) => self . extract_result ( lua_value, duration_ms, memory_used_mb ) ,
227
+ Ok ( Err ( lua_error) ) => self . handle_lua_error ( lua_error, duration_ms, memory_used_mb ) ,
204
228
Err ( _) => Ok ( ScriptResult {
205
229
success : false ,
206
230
output : serde_json:: Value :: Null ,
207
231
logs : vec ! [ ] ,
208
232
duration_ms,
209
- memory_used_mb : None ,
233
+ memory_used_mb,
210
234
error : Some ( ScriptError :: TimeoutError {
211
235
timeout_ms : self . config . timeout_ms ,
212
236
} ) ,
@@ -464,6 +488,7 @@ impl LuaEngine {
464
488
& self ,
465
489
lua_value : LuaValue ,
466
490
duration_ms : u64 ,
491
+ memory_used_mb : Option < f64 > ,
467
492
) -> Result < ScriptResult , ScriptError > {
468
493
let output =
469
494
self . lua
@@ -477,7 +502,7 @@ impl LuaEngine {
477
502
output,
478
503
logs : vec ! [ ] , // FUTURE(#300): Capture actual logs from Lua print statements
479
504
duration_ms,
480
- memory_used_mb : None , // FUTURE(#301): Implement memory tracking with platform-specific APIs
505
+ memory_used_mb,
481
506
error : None ,
482
507
} )
483
508
}
@@ -487,6 +512,7 @@ impl LuaEngine {
487
512
& self ,
488
513
lua_error : mlua:: Error ,
489
514
duration_ms : u64 ,
515
+ memory_used_mb : Option < f64 > ,
490
516
) -> Result < ScriptResult , ScriptError > {
491
517
let line_number = self . extract_line_number ( & lua_error) ;
492
518
let script_error = match lua_error {
@@ -505,7 +531,7 @@ impl LuaEngine {
505
531
output : serde_json:: Value :: Null ,
506
532
logs : vec ! [ ] ,
507
533
duration_ms,
508
- memory_used_mb : None ,
534
+ memory_used_mb,
509
535
error : Some ( script_error) ,
510
536
} )
511
537
}
@@ -1084,4 +1110,62 @@ mod tests {
1084
1110
. unwrap ( ) ;
1085
1111
assert ! ( nil_result. success) ; // Should handle nil result gracefully
1086
1112
}
1113
+
1114
+ #[ tokio:: test]
1115
+ async fn test_memory_tracking_integration ( ) {
1116
+ let engine = LuaEngine :: new ( & ScriptConfig :: new ( ) ) . unwrap ( ) ;
1117
+ let context = create_test_context ( ) ;
1118
+
1119
+ // Simple script that should show memory tracking
1120
+ let script = r#"
1121
+ result = {
1122
+ success = true,
1123
+ message = "Memory tracking test",
1124
+ data = "Some test data"
1125
+ }
1126
+ "# ;
1127
+
1128
+ let result = engine. execute_script ( script, context) . await . unwrap ( ) ;
1129
+
1130
+ assert ! ( result. success) ;
1131
+ assert ! (
1132
+ result. memory_used_mb. is_some( ) ,
1133
+ "Memory tracking should return a value"
1134
+ ) ;
1135
+
1136
+ // Memory usage should be a reasonable value (not negative, not extremely large)
1137
+ let memory_mb = result. memory_used_mb . unwrap ( ) ;
1138
+ assert ! (
1139
+ memory_mb >= -100.0 ,
1140
+ "Memory delta should not be extremely negative: {} MB" ,
1141
+ memory_mb
1142
+ ) ;
1143
+ assert ! (
1144
+ memory_mb <= 100.0 ,
1145
+ "Memory delta should not be extremely large: {} MB" ,
1146
+ memory_mb
1147
+ ) ;
1148
+
1149
+ debug ! ( "Memory tracking test - Memory used: {} MB" , memory_mb) ;
1150
+ }
1151
+
1152
+ #[ tokio:: test]
1153
+ async fn test_memory_tracking_error_handling ( ) {
1154
+ let engine = LuaEngine :: new ( & ScriptConfig :: new ( ) ) . unwrap ( ) ;
1155
+ let context = create_test_context ( ) ;
1156
+
1157
+ // Test that memory tracking errors are handled gracefully
1158
+ // Note: This test verifies the error handling structure exists
1159
+ // In practice, memory tracking errors should be rare
1160
+ let script = r#"
1161
+ result = { success = true, message = "Test completed" }
1162
+ "# ;
1163
+
1164
+ let result = engine. execute_script ( script, context) . await . unwrap ( ) ;
1165
+
1166
+ // Even if memory tracking fails, script execution should continue
1167
+ assert ! ( result. success) ;
1168
+ // Memory tracking might succeed or fail depending on platform
1169
+ // The important thing is that it doesn't crash the script execution
1170
+ }
1087
1171
}
0 commit comments