package engine import ( "io/fs" "path" "reflect" "testing" "testing/fstest" ) func TestSequenceUpsertProjectsIncomingOrigins(t *testing.T) { t.Parallel() type details struct { Label string `yaml:"label"` Resource string `yaml:"resource"` } type item struct { ID string `yaml:"id"` Details details `yaml:"details"` } type catalog struct { Items []item `yaml:"items"` } type family struct { Base catalog `yaml:"base"` Child catalog `yaml:"child"` } for _, inheritance := range []bool{false, true} { name := "layered" destination := "[items]" if inheritance { name, destination = "inheritance", "[child, items]" } t.Run(name, func(t *testing.T) { files := fstest.MapFS{} for _, id := range []string{"a", "b", "c"} { files[id+"/record.yml"] = &fstest.MapFile{Data: []byte("configkit: {imports: [{path: helper.yml}]}\nid: " + id + "\ndetails: {label: " + id + "}\n")} files[id+"/helper.yml"] = &fstest.MapFile{Data: []byte("details: {resource: asset.txt}\n")} files[id+"/asset.txt"] = &fstest.MapFile{Data: []byte(id + " asset")} } main := "configkit:\n sequences:\n - destination: " + destination + "\n key: id\n imports:\n - glob: '*/record.yml'\n destination: " + destination + "\n placement: sequence-item\n" if inheritance { main += "base:\n items: [{id: b}, {id: a}, {id: keep}]\nchild:\n extends: base\n" } files["main.yml"] = &fstest.MapFile{Data: []byte(main)} source := NewFilesystem("catalog", files).File("main.yml") var inspection *Inspection var items []item collection := Keys("items") if inheritance { loaded, err := testLoad(source, Options[family]{Imports: true}) if err != nil { t.Fatal(err) } inspection, items, collection = loaded.Inspection, loaded.Config.Child.Items, Keys("child", "items") } else { loaded, err := testGroupedLoad(loadRequest[catalog]{ main: loadInput{source: source, imports: true}, underlays: []loadGroup{{inputs: []loadInput{{source: Bytes("lower", []byte("items: [{id: b}, {id: a}, {id: keep}]\n"))}}}}, }) if err != nil { t.Fatal(err) } inspection, items = loaded.Inspection, loaded.Config.Items } ids := make([]string, len(items)) for index, item := range items { ids[index] = item.ID } if !reflect.DeepEqual(ids, []string{"b", "a", "keep", "c"}) { t.Fatalf("upsert order = %v", ids) } for _, index := range []int{0, 1, 3} { item := items[index] info, ok := inspection.Metadata().Lookup(collection.Index(index).Key("details")) if !ok || len(info.Origin.Locations) != 2 { t.Fatalf("%s composite origin = %#v, %v", item.ID, info, ok) } for _, location := range info.Origin.Locations { context, ok := inspection.SourceContext(location.SourceID) if !ok || context.BaseDir != item.ID { t.Errorf("%s origin context = %#v, %v", item.ID, context, ok) } } resource, ok := inspection.Metadata().Lookup(collection.Index(index).Key("details").Key("resource")) if !ok || len(resource.Origin.Locations) != 1 { t.Fatalf("%s resource origin = %#v", item.ID, resource) } context, ok := inspection.SourceContext(resource.Origin.Locations[0].SourceID) if !ok { t.Fatal("resource source context missing") } data, err := fs.ReadFile(context.FS, path.Join(context.BaseDir, item.Details.Resource)) if err != nil || string(data) != item.ID+" asset" { t.Errorf("%s declaring resource = %q, %v", item.ID, data, err) } } }) } }