Files
LocalAI/pkg/addons/packaging/platforms_test.go
T
Ettore Di Giacinto 02a707558e feat(addons): ship Studio and Talk as add-ons instead of built-in pages
Studio and Talk were compiled into the web bundle and always listed in
the Add-ons drawer. They are add-ons now, like Voice, Face, fine-tuning
and quantization: a person installs and removes them, the drawer lists
them only while they are installed, and they are packaged the same way.

Move the pages, their components, hooks and helpers into addons/studio
and addons/talk. Each has a manifest, a UI bundle, a release platform
matrix and a catalog template, and is built by the compat mode of the
shared builder. The core API stays where it is: the pages call it with
the signed-in person's session. The history keeps its browser storage
keys. The unit tests of the moved helpers move with them.

In the core, drop the two pages, the Create group of the sidebar (Chat
joins Home and Models in the old layout), the built-in catalog entries
(the catalog is empty) and the talk locale namespace. The old addresses
(/app/studio, /app/talk and the generator links) redirect to the add-on
pages, with the model as ?model=. The Home /studio command is offered
only while the Studio add-on is installed and opens it.

The release workflow and its tests now list seven add-ons.

Assisted-by: Claude Code:claude-sonnet-5-5 go node
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
2026-10-20 21:40:00 +00:00

98 lines
3.1 KiB
Go

// SPDX-License-Identifier: MIT
package packaging
import (
"os"
"path/filepath"
"sort"
"strings"
"testing"
)
// The release platforms of the packaged first-party add-ons, with the runner
// that builds and checks each one natively.
var releasePlatforms = map[string]string{
"linux/amd64": "ubuntu-24.04",
"linux/arm64": "ubuntu-24.04-arm",
"darwin/arm64": "macos-14",
"darwin/amd64": "macos-15-intel",
}
// nativeChecked records the platforms whose native check has passed on a runner
// of that platform. A task of group G adds a platform here in the same change
// that enables it in the five files and shows the passing legs in its pull
// request. Enabling without this record, or recording without enabling, fails.
var nativeChecked = map[string]bool{"linux/amd64": true, "linux/arm64": true, "darwin/arm64": true, "darwin/amd64": true}
var packagedAddons = []string{"voice", "face", "fine-tuning", "quantization", "studio", "talk"}
func TestEveryPackagedAddonListsEveryReleasePlatformWithItsRunner(t *testing.T) {
for _, id := range packagedAddons {
p, err := loadPlatforms(filepath.Join("..", "..", "..", "addons", id, "package", "platforms.yaml"))
if err != nil {
t.Fatalf("%s: %v", id, err)
}
if p.Addon != id || p.Executable != id {
t.Fatalf("%s: addon %q executable %q", id, p.Addon, p.Executable)
}
got := map[string]string{}
for _, e := range p.Platforms {
got[e.Platform] = e.Runner
if e.NativeCheck != NativeCheckKind {
t.Fatalf("%s %s: native check %q", id, e.Platform, e.NativeCheck)
}
}
if len(got) != len(releasePlatforms) {
t.Fatalf("%s lists %d platforms, want %d", id, len(got), len(releasePlatforms))
}
for platform, runner := range releasePlatforms {
if got[platform] != runner {
t.Fatalf("%s: platform %s has runner %q, want %q", id, platform, got[platform], runner)
}
}
}
}
func TestAPlatformIsEnabledExactlyWhenItsNativeCheckIsRecorded(t *testing.T) {
for _, id := range packagedAddons {
p, err := loadPlatforms(filepath.Join("..", "..", "..", "addons", id, "package", "platforms.yaml"))
if err != nil {
t.Fatal(err)
}
var enabled []string
for _, e := range p.Platforms {
if e.Enabled {
enabled = append(enabled, e.Platform)
}
}
var recorded []string
for platform := range nativeChecked {
recorded = append(recorded, platform)
}
sort.Strings(enabled)
sort.Strings(recorded)
if len(enabled) != len(recorded) {
t.Fatalf("%s: enabled %v, native check recorded for %v", id, enabled, recorded)
}
for i := range enabled {
if enabled[i] != recorded[i] {
t.Fatalf("%s: enabled %v, native check recorded for %v", id, enabled, recorded)
}
}
}
}
func TestEveryPackagedAddonHasACatalogTemplate(t *testing.T) {
for _, id := range packagedAddons {
b, err := os.ReadFile(filepath.Join("..", "..", "..", "gallery", "addons", id+".yaml.tmpl"))
if err != nil {
t.Fatalf("%s: %v", id, err)
}
for _, want := range []string{`addonId: "{{addon}}"`, "requireSignature: true"} {
if !strings.Contains(string(b), want) {
t.Fatalf("%s template lacks %q", id, want)
}
}
}
}