package updates import ( "encoding/json" "fmt" "os" "path/filepath" "testing" "time" "github.com/safing/portmaster/base/notifications" "github.com/safing/portmaster/service/mgr" ) type testInstance struct{} func (i *testInstance) Restart() {} func (i *testInstance) Shutdown() {} func (i *testInstance) Notifications() *notifications.Notifications { return nil } func (i *testInstance) Ready() bool { return true } func (i *testInstance) SetCmdLineOperation(f func() error) {} func TestPerformUpdate(t *testing.T) { t.Parallel() // Initialize mock instance stub := &testInstance{} // Make tmp dirs installedDir, err := os.MkdirTemp("", "updates_current_") if err != nil { t.Fatal(err) } defer func() { _ = os.RemoveAll(installedDir) }() updateDir, err := os.MkdirTemp("", "updates_new_") if err != nil { t.Fatal(err) } defer func() { _ = os.RemoveAll(updateDir) }() purgeDir, err := os.MkdirTemp("", "updates_purge_") if err != nil { t.Fatal(err) } defer func() { _ = os.RemoveAll(purgeDir) }() // Generate mock files now := time.Now() if err := GenerateMockFolder(installedDir, "Test", "1.0.0", now); err != nil { t.Fatal(err) } if err := GenerateMockFolder(updateDir, "Test", "1.0.1", now.Add(1*time.Minute)); err != nil { t.Fatal(err) } // Create updater (loads index). updater, err := New(stub, "Test", Config{ Name: "Test", Directory: installedDir, DownloadDirectory: updateDir, PurgeDirectory: purgeDir, IndexFile: "index.json", AutoDownload: true, AutoApply: true, }) if err != nil { t.Fatal(err) } // Try to apply the updates m := mgr.New("updates test") _ = m.Do("test update and upgrade", func(w *mgr.WorkerCtx) error { if err := updater.updateAndUpgrade(w, nil, false, false); err != nil { if data, err := os.ReadFile(filepath.Join(installedDir, "index.json")); err == nil { fmt.Println(string(data)) fmt.Println(updater.index.Version) fmt.Println(updater.index.versionNum) } if data, err := os.ReadFile(filepath.Join(updateDir, "index.json")); err == nil { fmt.Println(string(data)) idx, err := ParseIndex(data, updater.cfg.Platform, nil) if err == nil { fmt.Println(idx.Version) fmt.Println(idx.versionNum) } } t.Fatal(err) } return nil }) // Check if the current version is now the new. newIndex, err := LoadIndex(filepath.Join(installedDir, "index.json"), updater.cfg.Platform, nil) if err != nil { t.Fatal(err) } if newIndex.Version != "1.0.1" { t.Fatalf("expected version 1.0.1 found %s", newIndex.Version) } } // GenerateMockFolder generates mock index folder for testing. func GenerateMockFolder(dir, name, version string, published time.Time) error { // Make sure dir exists _ = os.MkdirAll(dir, defaultDirMode) // Create empty files file, err := os.Create(filepath.Join(dir, "portmaster")) if err != nil { return err } _ = file.Close() file, err = os.Create(filepath.Join(dir, "portmaster-core")) if err != nil { return err } _ = file.Close() file, err = os.Create(filepath.Join(dir, "portmaster.zip")) if err != nil { return err } _ = file.Close() file, err = os.Create(filepath.Join(dir, "assets.zip")) if err != nil { return err } _ = file.Close() index, err := GenerateIndexFromDir(dir, IndexScanConfig{ Name: name, Version: version, }) if err != nil { return err } index.Published = published indexJSON, err := json.MarshalIndent(index, "", " ") if err != nil { fmt.Fprintf(os.Stderr, "failed to marshal index: %s\n", err) } err = os.WriteFile(filepath.Join(dir, "index.json"), indexJSON, defaultFileMode) if err != nil { return err } return nil }