Initial D-InSAR bundle restore tool
This commit is contained in:
+242
@@ -0,0 +1,242 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRunRestoresPair(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
input := filepath.Join(root, "bundle")
|
||||
output := filepath.Join(root, "out")
|
||||
|
||||
writeTestFile(t, filepath.Join(input, "data", "scene_master", "m.txt"), "master")
|
||||
writeTestFile(t, filepath.Join(input, "data", "scene_slave", "s.txt"), "slave")
|
||||
writeTestFile(t, filepath.Join(input, "orbit", "master.txt"), "master orbit")
|
||||
|
||||
doc := pairsDocument{
|
||||
Schema: "dinsar_source_bundle_pairs.v1",
|
||||
Pairs: []pair{{
|
||||
PairID: "pair_0001",
|
||||
TaskName: "Task_20250101_20250113",
|
||||
TaskAlias: "Task_20250101_20250113",
|
||||
MasterData: "data/scene_master",
|
||||
SlaveData: "data/scene_slave",
|
||||
MasterOrbit: "orbit/master.txt",
|
||||
SlaveOrbit: "orbit/missing.txt",
|
||||
MasterImagingDate: "20250101",
|
||||
SlaveImagingDate: "20250113",
|
||||
TimeBaselineDays: 12,
|
||||
}},
|
||||
}
|
||||
writeTestJSON(t, filepath.Join(input, pairsFileName), doc)
|
||||
|
||||
result, err := run(config{inputRoot: input, outputRoot: output, skipExisting: true})
|
||||
if err != nil {
|
||||
t.Fatalf("run failed: %v", err)
|
||||
}
|
||||
if result.report.Restored != 1 {
|
||||
t.Fatalf("restored = %d, want 1", result.report.Restored)
|
||||
}
|
||||
if len(result.report.Warnings) != 1 {
|
||||
t.Fatalf("warnings = %d, want 1", len(result.report.Warnings))
|
||||
}
|
||||
|
||||
for _, path := range []string{
|
||||
filepath.Join(output, "Task_20250101_20250113", "master", "m.txt"),
|
||||
filepath.Join(output, "Task_20250101_20250113", "slave", "s.txt"),
|
||||
filepath.Join(output, "Task_20250101_20250113", "orbit", "master.txt"),
|
||||
filepath.Join(output, "Task_20250101_20250113", pairMetaName),
|
||||
filepath.Join(output, reportFileName),
|
||||
filepath.Join(output, logFileName),
|
||||
} {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
t.Fatalf("expected %s to exist: %v", path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunSkipsExistingCompleteTask(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
input := filepath.Join(root, "bundle")
|
||||
output := filepath.Join(root, "out")
|
||||
task := filepath.Join(output, "Task_20250101_20250113")
|
||||
|
||||
writeTestFile(t, filepath.Join(input, "data", "scene_master", "m.txt"), "master")
|
||||
writeTestFile(t, filepath.Join(input, "data", "scene_slave", "s.txt"), "slave")
|
||||
writeTestFile(t, filepath.Join(task, "master", "old.txt"), "old master")
|
||||
writeTestFile(t, filepath.Join(task, "slave", "old.txt"), "old slave")
|
||||
|
||||
writeTestJSON(t, filepath.Join(input, pairsFileName), pairsDocument{
|
||||
Pairs: []pair{{
|
||||
PairID: "pair_0001",
|
||||
TaskName: "Task_20250101_20250113",
|
||||
MasterData: "data/scene_master",
|
||||
SlaveData: "data/scene_slave",
|
||||
}},
|
||||
})
|
||||
|
||||
result, err := run(config{inputRoot: input, outputRoot: output, skipExisting: true})
|
||||
if err != nil {
|
||||
t.Fatalf("run failed: %v", err)
|
||||
}
|
||||
if result.report.Skipped != 1 {
|
||||
t.Fatalf("skipped = %d, want 1", result.report.Skipped)
|
||||
}
|
||||
if result.report.Restored != 0 {
|
||||
t.Fatalf("restored = %d, want 0", result.report.Restored)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunLimitContinuesAfterExistingTasks(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
input := filepath.Join(root, "bundle")
|
||||
output := filepath.Join(root, "out")
|
||||
|
||||
var pairs []pair
|
||||
for i := 1; i <= 4; i++ {
|
||||
taskName := "Task_20250101_202501" + string(rune('0'+i))
|
||||
masterDir := filepath.Join(input, "data", "scene_master_"+string(rune('0'+i)))
|
||||
slaveDir := filepath.Join(input, "data", "scene_slave_"+string(rune('0'+i)))
|
||||
writeTestFile(t, filepath.Join(masterDir, "m.txt"), "master")
|
||||
writeTestFile(t, filepath.Join(slaveDir, "s.txt"), "slave")
|
||||
pairs = append(pairs, pair{
|
||||
PairID: "pair_000" + string(rune('0'+i)),
|
||||
TaskName: taskName,
|
||||
MasterData: filepath.ToSlash(filepath.Join("data", "scene_master_"+string(rune('0'+i)))),
|
||||
SlaveData: filepath.ToSlash(filepath.Join("data", "scene_slave_"+string(rune('0'+i)))),
|
||||
})
|
||||
}
|
||||
writeTestJSON(t, filepath.Join(input, pairsFileName), pairsDocument{Pairs: pairs})
|
||||
|
||||
first, err := run(config{inputRoot: input, outputRoot: output, skipExisting: true, limit: 2, logWriter: io.Discard})
|
||||
if err != nil {
|
||||
t.Fatalf("first run failed: %v", err)
|
||||
}
|
||||
if first.report.Restored != 2 {
|
||||
t.Fatalf("first restored = %d, want 2", first.report.Restored)
|
||||
}
|
||||
|
||||
second, err := run(config{inputRoot: input, outputRoot: output, skipExisting: true, limit: 2, logWriter: io.Discard})
|
||||
if err != nil {
|
||||
t.Fatalf("second run failed: %v", err)
|
||||
}
|
||||
if second.report.Restored != 2 {
|
||||
t.Fatalf("second restored = %d, want 2", second.report.Restored)
|
||||
}
|
||||
if second.report.Skipped != 2 {
|
||||
t.Fatalf("second skipped = %d, want 2", second.report.Skipped)
|
||||
}
|
||||
for _, p := range pairs {
|
||||
if _, err := os.Stat(filepath.Join(output, p.TaskName, pairMetaName)); err != nil {
|
||||
t.Fatalf("expected %s metadata to exist: %v", p.TaskName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCheckReportsMissingSlaveData(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
input := filepath.Join(root, "bundle")
|
||||
|
||||
writeTestFile(t, filepath.Join(input, "data", "scene_master", "m.txt"), "master")
|
||||
writeTestJSON(t, filepath.Join(input, pairsFileName), pairsDocument{
|
||||
Pairs: []pair{{
|
||||
PairID: "pair_0001",
|
||||
TaskName: "Task_20250101_20250113",
|
||||
MasterData: "data/scene_master",
|
||||
SlaveData: "data/scene_missing",
|
||||
}},
|
||||
})
|
||||
|
||||
result, err := runCheck(config{inputRoot: input, logWriter: io.Discard})
|
||||
if err != nil {
|
||||
t.Fatalf("runCheck failed: %v", err)
|
||||
}
|
||||
if result.report.Failed != 1 {
|
||||
t.Fatalf("failed = %d, want 1", result.report.Failed)
|
||||
}
|
||||
if result.report.Valid != 0 {
|
||||
t.Fatalf("valid = %d, want 0", result.report.Valid)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCheckTreatsMissingOrbitAsWarning(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
input := filepath.Join(root, "bundle")
|
||||
|
||||
writeTestFile(t, filepath.Join(input, "data", "scene_master", "m.txt"), "master")
|
||||
writeTestFile(t, filepath.Join(input, "data", "scene_slave", "s.txt"), "slave")
|
||||
writeTestJSON(t, filepath.Join(input, pairsFileName), pairsDocument{
|
||||
Pairs: []pair{{
|
||||
PairID: "pair_0001",
|
||||
TaskName: "Task_20250101_20250113",
|
||||
MasterData: "data/scene_master",
|
||||
SlaveData: "data/scene_slave",
|
||||
MasterOrbit: "orbit/missing.txt",
|
||||
}},
|
||||
})
|
||||
|
||||
result, err := runCheck(config{inputRoot: input, logWriter: io.Discard})
|
||||
if err != nil {
|
||||
t.Fatalf("runCheck failed: %v", err)
|
||||
}
|
||||
if result.report.Failed != 0 {
|
||||
t.Fatalf("failed = %d, want 0", result.report.Failed)
|
||||
}
|
||||
if result.report.Valid != 1 {
|
||||
t.Fatalf("valid = %d, want 1", result.report.Valid)
|
||||
}
|
||||
if len(result.report.Warnings) != 1 {
|
||||
t.Fatalf("warnings = %d, want 1", len(result.report.Warnings))
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFlagsRejectsSkipExistingWithOverwrite(t *testing.T) {
|
||||
_, err := parseFlags([]string{"--input", "in", "--output", "out", "--skip-existing", "--overwrite"})
|
||||
if err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFlagsAllowsOverwriteByItself(t *testing.T) {
|
||||
cfg, err := parseFlags([]string{"--input", "in", "--output", "out", "--overwrite"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if cfg.skipExisting {
|
||||
t.Fatal("skipExisting = true, want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeJoinRejectsEscapingPath(t *testing.T) {
|
||||
if _, err := safeJoin(t.TempDir(), "../outside"); err == nil {
|
||||
t.Fatal("expected escaping path error")
|
||||
}
|
||||
}
|
||||
|
||||
func writeTestFile(t *testing.T, path string, content string) {
|
||||
t.Helper()
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func writeTestJSON(t *testing.T, path string, value any) {
|
||||
t.Helper()
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bytes, err := json.MarshalIndent(value, "", " ")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(path, bytes, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user