package release import ( "crypto/ed25519" "crypto/rand" "encoding/json" "os" "path/filepath" "strings" "testing" "testing/fstest" "time" ) func stageNPR(t *testing.T, priv ed25519.PrivateKey, req string) string { t.Helper() staging := t.TempDir() bin := filepath.Join(staging, "bj-npr") if err := os.WriteFile(bin, []byte("npr 0.1.0"), 0o644); err != nil { t.Fatal(err) } sha, size, err := HashFile(bin) if err != nil { t.Fatal(err) } m := &Manifest{Version: "2026.09.2", Channel: "beta", ReleasedAt: time.Now().UTC().Truncate(time.Second), Artifacts: []Artifact{{Name: "bj-npr", File: "bj-npr", Version: "0.1.0", SHA256: sha, Size: size, Exec: true}}} sm, err := Sign(m, priv, "main") if err != nil { t.Fatal(err) } b, _ := json.Marshal(sm) if err := os.WriteFile(filepath.Join(staging, "manifest.json"), b, 0o644); err != nil { t.Fatal(err) } if err := os.WriteFile(filepath.Join(staging, "request.json"), []byte(req), 0o644); err != nil { t.Fatal(err) } return staging } // Выделенный из ядра модуль ставится впервые только по явному запросу (new) — вместе с unit-файлом. func TestInstallSplitModuleWithUnit(t *testing.T) { pub, priv, err := ed25519.GenerateKey(rand.Reader) if err != nil { t.Fatal(err) } units := fstest.MapFS{"systemd/bj-npr.service": {Data: []byte("[Service]\nExecStart=/opt/bj/bj-npr\n")}} root := t.TempDir() res := InstallStaged(stageNPR(t, priv, `{"names":["bj-npr"]}`), InstallOptions{Root: root, PubKey: pub, Units: units}) if res.OK || !strings.Contains(res.Error, "не установлен") { t.Fatalf("без new модуль не должен ставиться: %+v", res) } res = InstallStaged(stageNPR(t, priv, `{"names":["bj-npr"],"new":["bj-npr"]}`), InstallOptions{Root: root, PubKey: pub, Units: units}) if !res.OK { t.Fatalf("установка: %+v", res) } if fi, err := os.Stat(filepath.Join(root, "/opt/bj/bj-npr")); err != nil || fi.Mode().Perm() != 0o755 { t.Fatalf("файл модуля: %v %v", fi, err) } if b, err := os.ReadFile(filepath.Join(root, "/etc/systemd/system/bj-npr.service")); err != nil || !strings.Contains(string(b), "ExecStart=/opt/bj/bj-npr") { t.Fatalf("unit-файл: %q %v", b, err) } if inst := LoadInstalled(filepath.Join(root, InstalledFile)); inst["bj-npr"].Version != "0.1.0" { t.Fatalf("components.json: %+v", inst) } // Самостоятельный модуль (не FromCore) по new не ставится. c, _ := ComponentByName("bj-lk") if c.FromCore { t.Fatal("bj-lk не выделялся из ядра") } }