Procházet zdrojové kódy

fix(jsonl): stop swallowing mid-stream errors as end-of-stream — the tracker's catch logged a warning and returned false, so an I/O failure or a malformed line mid-file silently truncated enumeration with the consumer none the wiser (same lie class as Invercargill-Sql's BUSY-as-empty-rows); the Invercargill tracker channel cannot propagate GLib errors, so the failure is now fatal per the family's iteration-error convention, naming the underlying parse/IO error. Regression test: a JSONL stream with a valid line followed by garbage used to enumerate one element and complete cleanly; a spawned child now aborts with 'JsonlInputStream iteration failed' and the parent asserts the signal death, the stderr marker, and that no element count was produced

clanker před 1 měsícem
rodič
revize
327532e031

+ 1 - 3
src/lib/Jsonl.vala

@@ -24,9 +24,7 @@ namespace InvercargillJson {
                     return i != null;
                 }
                 catch (Error e) {
-                    warning (@"Premature end of JsonlInputStream due to error: $(e.message)");
-                    i = null;
-                    return false;
+                    error (@"JsonlInputStream iteration failed: $(e.message) — treated as a hard read failure, not end-of-stream");
                 }
             });
         }

+ 33 - 0
src/tests/Integration/Jsonl.vala

@@ -0,0 +1,33 @@
+using GLib;
+
+void jsonl_swallowed_error_tests() {
+
+    Test.add_func("/invercargill/json/jsonl/midstream_error_is_fatal_not_truncation", () => {
+        string exe;
+        if (Path.is_absolute(args_holder[0])) {
+            exe = args_holder[0];
+        }
+        else {
+            exe = Path.build_filename(Environment.get_current_dir(), args_holder[0]);
+        }
+        assert_true(File.new_for_path(exe).query_exists());
+
+        try {
+            string[] argv = { exe, "--jsonl-child" };
+            int status;
+            string child_stdout;
+            string child_stderr;
+            Process.spawn_sync(
+                null, argv, Environ.get(),
+                SpawnFlags.SEARCH_PATH,
+                null, out child_stdout, out child_stderr, out status);
+
+            assert_true(Process.if_signaled(status));
+            assert_true(child_stderr.contains("JsonlInputStream iteration failed"));
+            assert_false(child_stdout.contains("elements="));
+        }
+        catch (Error e) {
+            assert_no_error(e);
+        }
+    });
+}

+ 22 - 1
src/tests/TestRunner.vala

@@ -1,15 +1,36 @@
 
+string[] args_holder;
+
 public static int main(string[] args) {
 
+    if (args.length > 1 && args[1] == "--jsonl-child") {
+        run_jsonl_child();
+        printerr("jsonl-child completed without hitting the mid-stream failure\n");
+        return 1;
+    }
+
+    args_holder = args;
     Test.init(ref args);
 
     promotion_tests();
     property_mapper_tests();
     json_tests();
     from_element_scalar_tests();
-    
+    jsonl_swallowed_error_tests();
+
     Test.run();
 
 
     return 0;
+}
+
+void run_jsonl_child() {
+    uint8[] data = "{\"a\": 1}\nthis is not json\n".data;
+    var stream = new InvercargillJson.JsonlInputStream(
+        new MemoryInputStream.from_data(data));
+    uint count = 0;
+    foreach (var element in stream) {
+        count++;
+    }
+    print("elements=%u\n", count);
 }

+ 1 - 0
src/tests/meson.build

@@ -4,5 +4,6 @@ sources += files('Integration/Promotion.vala')
 sources += files('Integration/PropertyMapper.vala')
 sources += files('Integration/Json.vala')
 sources += files('Integration/FromElement.vala')
+sources += files('Integration/Jsonl.vala')
 
 executable('invercargill-json-test-suite', sources, dependencies: dependencies, install: true)