test_transformer.rs
1 #![allow(dead_code)] 2 use std::fs; 3 4 use apibara_script::{Script, ScriptOptions}; 5 use serde_json::json; 6 use tempfile::NamedTempFile; 7 8 fn write_source(ext: &str, code: &str) -> NamedTempFile { 9 let tempfile = tempfile::Builder::new() 10 .suffix(&format!(".{}", ext)) 11 .tempfile() 12 .unwrap(); 13 fs::write(tempfile.path(), code).unwrap(); 14 tempfile 15 } 16 17 async fn new_script_with_code_and_options( 18 ext: &str, 19 code: &str, 20 options: ScriptOptions, 21 ) -> (NamedTempFile, Script) { 22 let file = write_source(ext, code); 23 let script = Script::from_file( 24 file.path().to_str().unwrap(), 25 std::env::current_dir().unwrap(), 26 options, 27 ) 28 .unwrap(); 29 (file, script) 30 } 31 32 async fn new_script_with_code(ext: &str, code: &str) -> (NamedTempFile, Script) { 33 new_script_with_code_and_options(ext, code, Default::default()).await 34 } 35 36 // #[tokio::test] 37 async fn test_identity() { 38 let (_file, mut script) = new_script_with_code( 39 "js", 40 r#" 41 export default function (data) { 42 console.log('data', data); 43 return data; 44 } 45 "#, 46 ) 47 .await; 48 let input = vec![json!({ 49 "foo": "bar", 50 "baz": 42, 51 })]; 52 let result = script.transform(input.clone()).await.unwrap(); 53 assert_eq!(result.as_array().unwrap(), &input); 54 } 55 56 // #[tokio::test] 57 async fn test_return_data_is_different() { 58 let (_file, mut script) = new_script_with_code( 59 "js", 60 r#" 61 export default function ({ foo }) { 62 return { foo } 63 } 64 "#, 65 ) 66 .await; 67 let input = vec![ 68 json!({ 69 "foo": "bar", 70 "baz": 42, 71 }), 72 json!({ 73 "foo": "bux", 74 }), 75 ]; 76 let result = script.transform(input).await.unwrap(); 77 let expected = vec![ 78 json!({ 79 "foo": "bar", 80 }), 81 json!({ 82 "foo": "bux", 83 }), 84 ]; 85 assert_eq!(result.as_array().unwrap(), &expected); 86 } 87 88 // #[tokio::test] 89 async fn test_return_data_is_flattened() { 90 let (_file, mut script) = new_script_with_code( 91 "js", 92 r#" 93 export default function ({ foo }) { 94 return [{ foo }, { foo }] 95 } 96 "#, 97 ) 98 .await; 99 let input = vec![ 100 json!({ 101 "foo": "bar", 102 "baz": 42, 103 }), 104 json!({ 105 "foo": "bux", 106 }), 107 ]; 108 let result = script.transform(input).await.unwrap(); 109 let expected = vec![ 110 json!({ 111 "foo": "bar", 112 }), 113 json!({ 114 "foo": "bar", 115 }), 116 json!({ 117 "foo": "bux", 118 }), 119 json!({ 120 "foo": "bux", 121 }), 122 ]; 123 assert_eq!(result.as_array().unwrap(), &expected); 124 } 125 126 // #[tokio::test] 127 async fn test_async_return_data_is_flattened() { 128 let (_file, mut script) = new_script_with_code( 129 "js", 130 r#" 131 export default async function ({ foo }) { 132 return [{ foo }, { foo }] 133 } 134 "#, 135 ) 136 .await; 137 let input = vec![ 138 json!({ 139 "foo": "bar", 140 "baz": 42, 141 }), 142 json!({ 143 "foo": "bux", 144 }), 145 ]; 146 let result = script.transform(input).await.unwrap(); 147 let expected = vec![ 148 json!({ 149 "foo": "bar", 150 }), 151 json!({ 152 "foo": "bar", 153 }), 154 json!({ 155 "foo": "bux", 156 }), 157 json!({ 158 "foo": "bux", 159 }), 160 ]; 161 assert_eq!(result.as_array().unwrap(), &expected); 162 } 163 164 // #[tokio::test] 165 async fn test_import_library_over_http() { 166 let (_file, mut script) = new_script_with_code( 167 "js", 168 r#" 169 import capitalizeKeys from 'https://cdn.jsdelivr.net/gh/stdlib-js/utils-capitalize-keys@deno/mod.js'; 170 // 171 export default function (block) { 172 return capitalizeKeys(block); 173 } 174 "#, 175 ) 176 .await; 177 let input = vec![ 178 json!({ 179 "foo": "bar", 180 "baz": 42, 181 }), 182 json!({ 183 "foo": "bux", 184 }), 185 ]; 186 let result = script.transform(input).await.unwrap(); 187 let expected = vec![ 188 json!({ 189 "Foo": "bar", 190 "Baz": 42, 191 }), 192 json!({ 193 "Foo": "bux", 194 }), 195 ]; 196 assert_eq!(result.as_array().unwrap(), &expected); 197 } 198 199 // #[tokio::test] 200 async fn test_typescript() { 201 let (_file, mut script) = new_script_with_code( 202 "ts", 203 r#" 204 interface Data { 205 foo: string; 206 bar: number; 207 } 208 209 export default function (data: Data): Data { 210 return data; 211 } 212 "#, 213 ) 214 .await; 215 let input = vec![json!({ 216 "foo": "bar", 217 "baz": 42, 218 })]; 219 let result = script.transform(input.clone()).await.unwrap(); 220 assert_eq!(result.as_array().unwrap(), &input); 221 } 222 223 // #[tokio::test] 224 async fn test_import_data() { 225 let json_file = write_source( 226 "json", 227 r#"{ 228 "is_json": true 229 }"#, 230 ); 231 232 let code = r#" 233 import data from "<JSON_FILE>" assert { type: "json" }; 234 235 export default function (event: Event): Data { 236 return data; 237 } 238 "# 239 .replace("<JSON_FILE>", json_file.path().to_str().unwrap()); 240 241 let (_file, mut script) = new_script_with_code("ts", &code).await; 242 let input = vec![json!({ 243 "key": vec!["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], 244 "data": vec![ 245 "0x4391e7c963a1dced0d206278464778711f2ad480b34f22e1d658fb3f6ac81f3", 246 "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", 247 "0x1df635bc07855", 248 "0x0" 249 ], 250 })]; 251 let result = script.transform(input).await.unwrap(); 252 let expected = vec![json!({ 253 "is_json": true 254 })]; 255 assert_eq!(result.as_array().unwrap(), &expected); 256 } 257 258 // #[tokio::test] 259 async fn test_use_starknet_js() { 260 let (_file, mut script) = new_script_with_code( 261 "js", 262 r#" 263 import { hash } from 'https://esm.sh/starknet'; 264 265 export default function ({ key }) { 266 const result = hash.getSelectorFromName(key); 267 return { result }; 268 } 269 "#, 270 ) 271 .await; 272 let input = vec![json!({ 273 "key": "Transfer", 274 })]; 275 let result = script.transform(input).await.unwrap(); 276 let expected = vec![json!({ 277 "result": "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9", 278 })]; 279 assert_eq!(result.as_array().unwrap(), &expected); 280 } 281 282 // #[tokio::test] 283 async fn test_net_is_denied() { 284 let (_file, mut script) = new_script_with_code( 285 "js", 286 r#" 287 export default function (data) { 288 const result = fetch('https://httpbin.org/get'); 289 return { result }; 290 } 291 "#, 292 ) 293 .await; 294 let input = vec![json!({})]; 295 let result = script.transform(input).await; 296 assert!(result.is_err()); 297 } 298 299 // #[tokio::test] 300 async fn test_read_is_denied() { 301 let (_file, mut script) = new_script_with_code( 302 "js", 303 r#" 304 export default function (data) { 305 const result = Deno.readDir('.'); 306 return { result }; 307 } 308 "#, 309 ) 310 .await; 311 let input = vec![json!({})]; 312 let result = script.transform(input).await; 313 assert!(result.is_err()); 314 } 315 316 // #[tokio::test] 317 async fn test_write_is_denied() { 318 let (_file, mut script) = new_script_with_code( 319 "js", 320 r#" 321 export default function (data) { 322 const result = Deno.writeTextFile('test.txt', 'test failed'); 323 return { result }; 324 } 325 "#, 326 ) 327 .await; 328 let input = vec![json!({})]; 329 let result = script.transform(input).await; 330 assert!(result.is_err()); 331 } 332 333 // #[tokio::test] 334 async fn test_run_is_denied() { 335 let (_file, mut script) = new_script_with_code( 336 "js", 337 r#" 338 export default function (data) { 339 const result = Deno.run({ cmd: ['ls'] }); 340 return { result }; 341 } 342 "#, 343 ) 344 .await; 345 let input = vec![json!({})]; 346 let result = script.transform(input).await; 347 assert!(result.is_err()); 348 } 349 350 // #[tokio::test] 351 async fn test_sys_is_denied() { 352 let (_file, mut script) = new_script_with_code( 353 "js", 354 r#" 355 export default function (data) { 356 const result = Deno.osRelease(); 357 return { result }; 358 } 359 "#, 360 ) 361 .await; 362 let input = vec![json!({})]; 363 let result = script.transform(input).await; 364 assert!(result.is_err()); 365 } 366 367 // #[tokio::test] 368 async fn test_env_is_denied_by_default() { 369 let (_file, mut script) = new_script_with_code( 370 "js", 371 r#" 372 export default function (data) { 373 const result = Deno.env.toObject(); 374 return { result }; 375 } 376 "#, 377 ) 378 .await; 379 let input = vec![json!({})]; 380 let result = script.transform(input).await; 381 assert!(result.is_err()); 382 } 383 384 // #[tokio::test] 385 async fn test_env_can_access_some_variables() { 386 let (_file, mut script) = new_script_with_code_and_options( 387 "js", 388 r#" 389 export default function (data) { 390 const result = Deno.env.get('CARGO'); 391 return { result }; 392 } 393 "#, 394 ScriptOptions { 395 allow_env: Some(vec!["CARGO".to_string()]), 396 ..Default::default() 397 }, 398 ) 399 .await; 400 let input = vec![json!({})]; 401 script.transform(input).await.unwrap(); 402 }