package main import ( "fmt" "net/http" "net/http/httptest" "os" "path/filepath" "runtime" "strings" "testing" ) // The test binary doubles as the "downloaded agent": started with -version and this variable it prints a version. func init() { if os.Getenv("WXCH_FAKE_AGENT") == "1" && len(os.Args) > 1 && os.Args[1] == "-version" { fmt.Println("9.9.9") os.Exit(0) } } func updateFixture(t *testing.T, handler http.HandlerFunc) (wsURL, exe string) { t.Setenv("WXCH_FAKE_AGENT", "1") srv := httptest.NewServer(handler) t.Cleanup(srv.Close) exe = filepath.Join(t.TempDir(), "wxch-agent") os.WriteFile(exe, []byte("old agent"), 0755) old := updateExe updateExe = func() (string, error) { return exe, nil } t.Cleanup(func() { updateExe = old }) return "ws" + strings.TrimPrefix(srv.URL, "http") + "/ws/agent", exe } func TestSelfUpdateReplacesTheFileAndSaysWhatItNowIs(t *testing.T) { self, _ := os.ReadFile(os.Args[0]) var asked string ws, exe := updateFixture(t, func(w http.ResponseWriter, r *http.Request) { asked = r.URL.Path; w.Write(self) }) v, err := selfUpdate(ws) if err != nil { t.Fatal(err) } if v != "9.9.9" || asked != "/dl/wxch-agent-"+runtime.GOARCH { t.Fatalf("version %q, asked %q", v, asked) } if b, _ := os.ReadFile(exe); len(b) != len(self) { t.Error("the file was not replaced") } if _, err := os.Stat(exe + ".new"); err == nil { t.Error("the temporary file was left behind") } } func TestSelfUpdateLeavesTheOldFileWhenSomethingIsWrong(t *testing.T) { self, _ := os.ReadFile(os.Args[0]) cases := map[string]http.HandlerFunc{ "not found": func(w http.ResponseWriter, r *http.Request) { http.NotFound(w, r) }, "not a program": func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("login page")) }, "cut short": func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Length", fmt.Sprint(len(self))) w.Write(self[:len(self)/2]) }, } for name, h := range cases { ws, exe := updateFixture(t, h) if _, err := selfUpdate(ws); err == nil { t.Errorf("%s: no error", name) } if b, _ := os.ReadFile(exe); string(b) != "old agent" { t.Errorf("%s: the old file was damaged", name) } if _, err := os.Stat(exe + ".new"); err == nil { t.Errorf("%s: the temporary file was left behind", name) } } }