|
|
package services_test |
|
|
|
|
|
import ( |
|
|
"context" |
|
|
"os" |
|
|
"path/filepath" |
|
|
|
|
|
"github.com/mudler/LocalAI/core/config" |
|
|
"github.com/mudler/LocalAI/core/services" |
|
|
"github.com/mudler/LocalAI/pkg/model" |
|
|
"github.com/mudler/LocalAI/pkg/system" |
|
|
|
|
|
. "github.com/onsi/ginkgo/v2" |
|
|
. "github.com/onsi/gomega" |
|
|
"gopkg.in/yaml.v2" |
|
|
) |
|
|
|
|
|
var _ = Describe("InstallExternalBackend", func() { |
|
|
var ( |
|
|
tempDir string |
|
|
galleries []config.Gallery |
|
|
ml *model.ModelLoader |
|
|
systemState *system.SystemState |
|
|
) |
|
|
|
|
|
BeforeEach(func() { |
|
|
var err error |
|
|
tempDir, err = os.MkdirTemp("", "backends-service-test-*") |
|
|
Expect(err).NotTo(HaveOccurred()) |
|
|
|
|
|
systemState, err = system.GetSystemState(system.WithBackendPath(tempDir)) |
|
|
Expect(err).NotTo(HaveOccurred()) |
|
|
ml = model.NewModelLoader(systemState) |
|
|
|
|
|
|
|
|
galleries = []config.Gallery{ |
|
|
{ |
|
|
Name: "test-gallery", |
|
|
URL: "file://" + filepath.Join(tempDir, "test-gallery.yaml"), |
|
|
}, |
|
|
} |
|
|
}) |
|
|
|
|
|
AfterEach(func() { |
|
|
os.RemoveAll(tempDir) |
|
|
}) |
|
|
|
|
|
Context("with gallery backend name", func() { |
|
|
BeforeEach(func() { |
|
|
|
|
|
testBackend := []map[string]interface{}{ |
|
|
{ |
|
|
"name": "test-backend", |
|
|
"uri": "https://gist.githubusercontent.com/mudler/71d5376bc2aa168873fa519fa9f4bd56/raw/testbackend/run.sh", |
|
|
}, |
|
|
} |
|
|
data, err := yaml.Marshal(testBackend) |
|
|
Expect(err).NotTo(HaveOccurred()) |
|
|
err = os.WriteFile(filepath.Join(tempDir, "test-gallery.yaml"), data, 0644) |
|
|
Expect(err).NotTo(HaveOccurred()) |
|
|
}) |
|
|
|
|
|
It("should fail when name or alias is provided for gallery backend", func() { |
|
|
err := services.InstallExternalBackend( |
|
|
context.Background(), |
|
|
galleries, |
|
|
systemState, |
|
|
ml, |
|
|
nil, |
|
|
"test-backend", |
|
|
"custom-name", |
|
|
"", |
|
|
) |
|
|
Expect(err).To(HaveOccurred()) |
|
|
Expect(err.Error()).To(ContainSubstring("specifying a name or alias is not supported for gallery backends")) |
|
|
}) |
|
|
|
|
|
It("should fail when backend is not found in gallery", func() { |
|
|
err := services.InstallExternalBackend( |
|
|
context.Background(), |
|
|
galleries, |
|
|
systemState, |
|
|
ml, |
|
|
nil, |
|
|
"non-existent-backend", |
|
|
"", |
|
|
"", |
|
|
) |
|
|
Expect(err).To(HaveOccurred()) |
|
|
}) |
|
|
}) |
|
|
|
|
|
Context("with OCI image", func() { |
|
|
It("should fail when name is not provided for OCI image", func() { |
|
|
err := services.InstallExternalBackend( |
|
|
context.Background(), |
|
|
galleries, |
|
|
systemState, |
|
|
ml, |
|
|
nil, |
|
|
"oci://quay.io/mudler/tests:localai-backend-test", |
|
|
"", |
|
|
"", |
|
|
) |
|
|
Expect(err).To(HaveOccurred()) |
|
|
Expect(err.Error()).To(ContainSubstring("specifying a name is required for OCI images")) |
|
|
}) |
|
|
}) |
|
|
|
|
|
Context("with directory path", func() { |
|
|
var testBackendPath string |
|
|
|
|
|
BeforeEach(func() { |
|
|
|
|
|
testBackendPath = filepath.Join(tempDir, "source-backend") |
|
|
err := os.MkdirAll(testBackendPath, 0750) |
|
|
Expect(err).NotTo(HaveOccurred()) |
|
|
|
|
|
|
|
|
err = os.WriteFile(filepath.Join(testBackendPath, "run.sh"), []byte("#!/bin/bash\necho test"), 0755) |
|
|
Expect(err).NotTo(HaveOccurred()) |
|
|
}) |
|
|
|
|
|
It("should infer name from directory path when name is not provided", func() { |
|
|
|
|
|
|
|
|
err := services.InstallExternalBackend( |
|
|
context.Background(), |
|
|
galleries, |
|
|
systemState, |
|
|
ml, |
|
|
nil, |
|
|
testBackendPath, |
|
|
"", |
|
|
"", |
|
|
) |
|
|
|
|
|
|
|
|
if err != nil { |
|
|
Expect(err.Error()).NotTo(ContainSubstring("name is required")) |
|
|
} |
|
|
}) |
|
|
|
|
|
It("should use provided name when specified", func() { |
|
|
err := services.InstallExternalBackend( |
|
|
context.Background(), |
|
|
galleries, |
|
|
systemState, |
|
|
ml, |
|
|
nil, |
|
|
testBackendPath, |
|
|
"custom-backend-name", |
|
|
"", |
|
|
) |
|
|
|
|
|
if err != nil { |
|
|
Expect(err.Error()).NotTo(ContainSubstring("name is required")) |
|
|
} |
|
|
}) |
|
|
|
|
|
It("should support alias when provided", func() { |
|
|
err := services.InstallExternalBackend( |
|
|
context.Background(), |
|
|
galleries, |
|
|
systemState, |
|
|
ml, |
|
|
nil, |
|
|
testBackendPath, |
|
|
"custom-backend-name", |
|
|
"custom-alias", |
|
|
) |
|
|
|
|
|
if err != nil { |
|
|
Expect(err.Error()).NotTo(ContainSubstring("alias is not supported")) |
|
|
} |
|
|
}) |
|
|
}) |
|
|
}) |
|
|
|
|
|
var _ = Describe("GalleryOp with External Backend", func() { |
|
|
It("should have external backend fields in GalleryOp", func() { |
|
|
|
|
|
op := services.GalleryOp[string, string]{ |
|
|
ExternalURI: "oci://example.com/backend:latest", |
|
|
ExternalName: "test-backend", |
|
|
ExternalAlias: "test-alias", |
|
|
} |
|
|
|
|
|
Expect(op.ExternalURI).To(Equal("oci://example.com/backend:latest")) |
|
|
Expect(op.ExternalName).To(Equal("test-backend")) |
|
|
Expect(op.ExternalAlias).To(Equal("test-alias")) |
|
|
}) |
|
|
}) |
|
|
|