package declaration import ( "strings" "testing" ) // novox/hq issue 213: a process says what it takes the place of, so the host can keep the old one // answering until the new one does. What it may name is narrow, and each refusal is said here. const aReplacingProcess = `{"id":"m.controller","type":"process","name":"m","source":"https://store.invalid/m", "digest":"sha256:` + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + `","run":["./m","serve"]%s}` func replacing(extra string) string { return `{"declaration":1,"resources":[` + strings.Replace(aReplacingProcess, "%s", extra, 1) + `]}` } func TestAProcessMayNameWhatItReplaces(t *testing.T) { d, err := Parse([]byte(replacing(`,"replaces":["m.server"]`))) if err != nil { t.Fatalf("a process replacing an undeclared container was refused: %v", err) } if p := d.Resources[0].(*Process); len(p.Replaces) != 1 || p.Replaces[0] != "m.server" { t.Fatalf("replaces was not read: %+v", p) } } // What is replaced is what the declaration no longer says. A resource still declared is applied, // and handing it over as well would remove something the same declaration asks to keep. func TestAProcessMayNotReplaceSomethingStillDeclared(t *testing.T) { raw := `{"declaration":1,"resources":[ {"id":"m.server","type":"directory","path":"/tmp/x"}, ` + strings.Replace(aReplacingProcess, "%s", `,"replaces":["m.server"]`, 1) + `]}` if _, err := Parse([]byte(raw)); err == nil || !strings.Contains(err.Error(), "still declares") { t.Fatalf("a process replacing a declared resource was accepted: %v", err) } } func TestOnlyAProcessThatStaysUpReplacesAnything(t *testing.T) { for _, mode := range []string{`,"run-once":true`, `,"schedule":"0 3 * * *"`} { if _, err := Parse([]byte(replacing(mode + `,"replaces":["m.server"]`))); err == nil { t.Errorf("a process with %s was allowed to replace something", mode) } } } func TestAProcessCannotReplaceItselfOrNothing(t *testing.T) { for _, bad := range []string{`,"replaces":["m.controller"]`, `,"replaces":[""]`} { if _, err := Parse([]byte(replacing(bad))); err == nil { t.Errorf("replaces %s was accepted", bad) } } } func TestOneThingHasOneReplacement(t *testing.T) { second := strings.NewReplacer(`"id":"m.controller"`, `"id":"m.other"`, `"name":"m"`, `"name":"other"`). Replace(strings.Replace(aReplacingProcess, "%s", `,"replaces":["m.server"]`, 1)) raw := `{"declaration":1,"resources":[` + strings.Replace(aReplacingProcess, "%s", `,"replaces":["m.server"]`, 1) + "," + second + `]}` if _, err := Parse([]byte(raw)); err == nil { t.Fatal("two processes replacing one resource were accepted") } }