mirror of
https://github.com/mudler/LocalAI.git
synced 2026-01-06 10:39:55 -06:00
* feat(loader): refactor single active backend support to LRU This changeset introduces LRU management of loaded backends. Users can set now a maximum number of models to be loaded concurrently, and, when setting LocalAI in single active backend mode we set LRU to 1 for backward compatibility. Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * chore: add tests Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Update docs Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * Fixups Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
599 lines
18 KiB
Go
599 lines
18 KiB
Go
package services_test
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/mudler/LocalAI/core/config"
|
|
"github.com/mudler/LocalAI/core/schema"
|
|
"github.com/mudler/LocalAI/core/services"
|
|
"github.com/mudler/LocalAI/core/templates"
|
|
"github.com/mudler/LocalAI/pkg/model"
|
|
"github.com/mudler/LocalAI/pkg/system"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("AgentJobService", func() {
|
|
var (
|
|
service *services.AgentJobService
|
|
tempDir string
|
|
appConfig *config.ApplicationConfig
|
|
modelLoader *model.ModelLoader
|
|
configLoader *config.ModelConfigLoader
|
|
evaluator *templates.Evaluator
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
var err error
|
|
tempDir, err = os.MkdirTemp("", "agent_jobs_test")
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
systemState := &system.SystemState{}
|
|
systemState.Model.ModelsPath = tempDir
|
|
|
|
appConfig = config.NewApplicationConfig(
|
|
config.WithDynamicConfigDir(tempDir),
|
|
config.WithContext(context.Background()),
|
|
)
|
|
appConfig.SystemState = systemState
|
|
appConfig.APIAddress = "127.0.0.1:8080"
|
|
appConfig.AgentJobRetentionDays = 30
|
|
|
|
modelLoader = model.NewModelLoader(systemState)
|
|
configLoader = config.NewModelConfigLoader(tempDir)
|
|
evaluator = templates.NewEvaluator(tempDir)
|
|
|
|
service = services.NewAgentJobService(
|
|
appConfig,
|
|
modelLoader,
|
|
configLoader,
|
|
evaluator,
|
|
)
|
|
})
|
|
|
|
AfterEach(func() {
|
|
os.RemoveAll(tempDir)
|
|
})
|
|
|
|
Describe("Task CRUD operations", func() {
|
|
It("should create a task", func() {
|
|
task := schema.Task{
|
|
Name: "Test Task",
|
|
Description: "Test Description",
|
|
Model: "test-model",
|
|
Prompt: "Hello {{.name}}",
|
|
Enabled: true,
|
|
}
|
|
|
|
id, err := service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(id).NotTo(BeEmpty())
|
|
|
|
retrieved, err := service.GetTask(id)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(retrieved.Name).To(Equal("Test Task"))
|
|
Expect(retrieved.Description).To(Equal("Test Description"))
|
|
Expect(retrieved.Model).To(Equal("test-model"))
|
|
Expect(retrieved.Prompt).To(Equal("Hello {{.name}}"))
|
|
})
|
|
|
|
It("should update a task", func() {
|
|
task := schema.Task{
|
|
Name: "Original Task",
|
|
Model: "test-model",
|
|
Prompt: "Original prompt",
|
|
}
|
|
|
|
id, err := service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
updatedTask := schema.Task{
|
|
Name: "Updated Task",
|
|
Model: "test-model",
|
|
Prompt: "Updated prompt",
|
|
}
|
|
|
|
err = service.UpdateTask(id, updatedTask)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
retrieved, err := service.GetTask(id)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(retrieved.Name).To(Equal("Updated Task"))
|
|
Expect(retrieved.Prompt).To(Equal("Updated prompt"))
|
|
})
|
|
|
|
It("should delete a task", func() {
|
|
task := schema.Task{
|
|
Name: "Task to Delete",
|
|
Model: "test-model",
|
|
Prompt: "Prompt",
|
|
}
|
|
|
|
id, err := service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
err = service.DeleteTask(id)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, err = service.GetTask(id)
|
|
Expect(err).To(HaveOccurred())
|
|
})
|
|
|
|
It("should list all tasks", func() {
|
|
task1 := schema.Task{Name: "Task 1", Model: "test-model", Prompt: "Prompt 1"}
|
|
task2 := schema.Task{Name: "Task 2", Model: "test-model", Prompt: "Prompt 2"}
|
|
|
|
_, err := service.CreateTask(task1)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
_, err = service.CreateTask(task2)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
tasks := service.ListTasks()
|
|
Expect(len(tasks)).To(BeNumerically(">=", 2))
|
|
})
|
|
})
|
|
|
|
Describe("Job operations", func() {
|
|
var taskID string
|
|
|
|
BeforeEach(func() {
|
|
task := schema.Task{
|
|
Name: "Test Task",
|
|
Model: "test-model",
|
|
Prompt: "Hello {{.name}}",
|
|
Enabled: true,
|
|
}
|
|
var err error
|
|
taskID, err = service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
|
|
It("should create and queue a job", func() {
|
|
params := map[string]string{"name": "World"}
|
|
jobID, err := service.ExecuteJob(taskID, params, "test", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(jobID).NotTo(BeEmpty())
|
|
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(job.TaskID).To(Equal(taskID))
|
|
Expect(job.Status).To(Equal(schema.JobStatusPending))
|
|
Expect(job.Parameters).To(Equal(params))
|
|
})
|
|
|
|
It("should list jobs with filters", func() {
|
|
params := map[string]string{}
|
|
jobID1, err := service.ExecuteJob(taskID, params, "test", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
time.Sleep(10 * time.Millisecond) // Ensure different timestamps
|
|
|
|
jobID2, err := service.ExecuteJob(taskID, params, "test", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
allJobs := service.ListJobs(nil, nil, 0)
|
|
Expect(len(allJobs)).To(BeNumerically(">=", 2))
|
|
|
|
filteredJobs := service.ListJobs(&taskID, nil, 0)
|
|
Expect(len(filteredJobs)).To(BeNumerically(">=", 2))
|
|
|
|
status := schema.JobStatusPending
|
|
pendingJobs := service.ListJobs(nil, &status, 0)
|
|
Expect(len(pendingJobs)).To(BeNumerically(">=", 2))
|
|
|
|
// Verify both jobs are in the list
|
|
jobIDs := make(map[string]bool)
|
|
for _, job := range pendingJobs {
|
|
jobIDs[job.ID] = true
|
|
}
|
|
Expect(jobIDs[jobID1]).To(BeTrue())
|
|
Expect(jobIDs[jobID2]).To(BeTrue())
|
|
})
|
|
|
|
It("should cancel a pending job", func() {
|
|
params := map[string]string{}
|
|
jobID, err := service.ExecuteJob(taskID, params, "test", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
err = service.CancelJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(job.Status).To(Equal(schema.JobStatusCancelled))
|
|
})
|
|
|
|
It("should delete a job", func() {
|
|
params := map[string]string{}
|
|
jobID, err := service.ExecuteJob(taskID, params, "test", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
err = service.DeleteJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
_, err = service.GetJob(jobID)
|
|
Expect(err).To(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Describe("File operations", func() {
|
|
It("should save and load tasks from file", func() {
|
|
task := schema.Task{
|
|
Name: "Persistent Task",
|
|
Model: "test-model",
|
|
Prompt: "Test prompt",
|
|
}
|
|
|
|
id, err := service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Create a new service instance to test loading
|
|
newService := services.NewAgentJobService(
|
|
appConfig,
|
|
modelLoader,
|
|
configLoader,
|
|
evaluator,
|
|
)
|
|
|
|
err = newService.LoadTasksFromFile()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
retrieved, err := newService.GetTask(id)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(retrieved.Name).To(Equal("Persistent Task"))
|
|
})
|
|
|
|
It("should save and load jobs from file", func() {
|
|
task := schema.Task{
|
|
Name: "Test Task",
|
|
Model: "test-model",
|
|
Prompt: "Test prompt",
|
|
Enabled: true,
|
|
}
|
|
|
|
taskID, err := service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
params := map[string]string{}
|
|
jobID, err := service.ExecuteJob(taskID, params, "test", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
service.SaveJobsToFile()
|
|
|
|
// Create a new service instance to test loading
|
|
newService := services.NewAgentJobService(
|
|
appConfig,
|
|
modelLoader,
|
|
configLoader,
|
|
evaluator,
|
|
)
|
|
|
|
err = newService.LoadJobsFromFile()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
retrieved, err := newService.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(retrieved.TaskID).To(Equal(taskID))
|
|
})
|
|
})
|
|
|
|
Describe("Prompt templating", func() {
|
|
It("should build prompt from template with parameters", func() {
|
|
task := schema.Task{
|
|
Name: "Template Task",
|
|
Model: "test-model",
|
|
Prompt: "Hello {{.name}}, you are {{.role}}",
|
|
}
|
|
|
|
id, err := service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// We can't directly test buildPrompt as it's private, but we can test via ExecuteJob
|
|
// which uses it internally. However, without a real model, the job will fail.
|
|
// So we'll just verify the task was created correctly.
|
|
Expect(id).NotTo(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Describe("Job cleanup", func() {
|
|
It("should cleanup old jobs", func() {
|
|
task := schema.Task{
|
|
Name: "Test Task",
|
|
Model: "test-model",
|
|
Prompt: "Test prompt",
|
|
Enabled: true,
|
|
}
|
|
|
|
taskID, err := service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
params := map[string]string{}
|
|
jobID, err := service.ExecuteJob(taskID, params, "test", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Manually set job creation time to be old
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Modify the job's CreatedAt to be 31 days ago
|
|
oldTime := time.Now().AddDate(0, 0, -31)
|
|
job.CreatedAt = oldTime
|
|
// We can't directly modify jobs in the service, so we'll test cleanup differently
|
|
// by setting retention to 0 and creating a new job
|
|
|
|
// Test that cleanup runs without error
|
|
err = service.CleanupOldJobs()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
Describe("Multimedia support", func() {
|
|
Describe("Task multimedia sources", func() {
|
|
It("should create a task with multimedia sources", func() {
|
|
task := schema.Task{
|
|
Name: "Multimedia Task",
|
|
Model: "test-model",
|
|
Prompt: "Analyze this image",
|
|
MultimediaSources: []schema.MultimediaSourceConfig{
|
|
{
|
|
Type: "image",
|
|
URL: "https://example.com/image.png",
|
|
Headers: map[string]string{"Authorization": "Bearer token123"},
|
|
},
|
|
{
|
|
Type: "video",
|
|
URL: "https://example.com/video.mp4",
|
|
},
|
|
},
|
|
}
|
|
|
|
id, err := service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(id).NotTo(BeEmpty())
|
|
|
|
retrieved, err := service.GetTask(id)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(retrieved.MultimediaSources).To(HaveLen(2))
|
|
Expect(retrieved.MultimediaSources[0].Type).To(Equal("image"))
|
|
Expect(retrieved.MultimediaSources[0].URL).To(Equal("https://example.com/image.png"))
|
|
Expect(retrieved.MultimediaSources[0].Headers["Authorization"]).To(Equal("Bearer token123"))
|
|
Expect(retrieved.MultimediaSources[1].Type).To(Equal("video"))
|
|
})
|
|
|
|
It("should save and load tasks with multimedia sources from file", func() {
|
|
task := schema.Task{
|
|
Name: "Persistent Multimedia Task",
|
|
Model: "test-model",
|
|
Prompt: "Test prompt",
|
|
MultimediaSources: []schema.MultimediaSourceConfig{
|
|
{
|
|
Type: "audio",
|
|
URL: "https://example.com/audio.mp3",
|
|
Headers: map[string]string{
|
|
"X-Custom-Header": "value",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
id, err := service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Create a new service instance to test loading
|
|
newService := services.NewAgentJobService(
|
|
appConfig,
|
|
modelLoader,
|
|
configLoader,
|
|
evaluator,
|
|
)
|
|
|
|
err = newService.LoadTasksFromFile()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
retrieved, err := newService.GetTask(id)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(retrieved.Name).To(Equal("Persistent Multimedia Task"))
|
|
Expect(retrieved.MultimediaSources).To(HaveLen(1))
|
|
Expect(retrieved.MultimediaSources[0].Type).To(Equal("audio"))
|
|
Expect(retrieved.MultimediaSources[0].URL).To(Equal("https://example.com/audio.mp3"))
|
|
Expect(retrieved.MultimediaSources[0].Headers["X-Custom-Header"]).To(Equal("value"))
|
|
})
|
|
})
|
|
|
|
Describe("Job multimedia", func() {
|
|
var taskID string
|
|
|
|
BeforeEach(func() {
|
|
task := schema.Task{
|
|
Name: "Test Task",
|
|
Model: "test-model",
|
|
Prompt: "Hello {{.name}}",
|
|
Enabled: true,
|
|
}
|
|
var err error
|
|
taskID, err = service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
|
|
It("should create a job with multimedia content", func() {
|
|
params := map[string]string{"name": "World"}
|
|
multimedia := &schema.MultimediaAttachment{
|
|
Images: []string{"https://example.com/image1.png", "data:image/png;base64,iVBORw0KG"},
|
|
Videos: []string{"https://example.com/video.mp4"},
|
|
Audios: []string{"data:audio/mpeg;base64,SUQzBAAAAA"},
|
|
Files: []string{"https://example.com/file.pdf"},
|
|
}
|
|
|
|
jobID, err := service.ExecuteJob(taskID, params, "test", multimedia)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(jobID).NotTo(BeEmpty())
|
|
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(job.TaskID).To(Equal(taskID))
|
|
Expect(job.Images).To(HaveLen(2))
|
|
Expect(job.Images[0]).To(Equal("https://example.com/image1.png"))
|
|
Expect(job.Images[1]).To(Equal("data:image/png;base64,iVBORw0KG"))
|
|
Expect(job.Videos).To(HaveLen(1))
|
|
Expect(job.Videos[0]).To(Equal("https://example.com/video.mp4"))
|
|
Expect(job.Audios).To(HaveLen(1))
|
|
Expect(job.Audios[0]).To(Equal("data:audio/mpeg;base64,SUQzBAAAAA"))
|
|
Expect(job.Files).To(HaveLen(1))
|
|
Expect(job.Files[0]).To(Equal("https://example.com/file.pdf"))
|
|
})
|
|
|
|
It("should create a job with partial multimedia (only images)", func() {
|
|
params := map[string]string{}
|
|
multimedia := &schema.MultimediaAttachment{
|
|
Images: []string{"https://example.com/image.png"},
|
|
}
|
|
|
|
jobID, err := service.ExecuteJob(taskID, params, "test", multimedia)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(job.Images).To(HaveLen(1))
|
|
Expect(job.Videos).To(BeEmpty())
|
|
Expect(job.Audios).To(BeEmpty())
|
|
Expect(job.Files).To(BeEmpty())
|
|
})
|
|
|
|
It("should create a job without multimedia (nil)", func() {
|
|
params := map[string]string{"name": "Test"}
|
|
jobID, err := service.ExecuteJob(taskID, params, "test", nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(job.Images).To(BeEmpty())
|
|
Expect(job.Videos).To(BeEmpty())
|
|
Expect(job.Audios).To(BeEmpty())
|
|
Expect(job.Files).To(BeEmpty())
|
|
})
|
|
|
|
It("should save and load jobs with multimedia from file", func() {
|
|
params := map[string]string{}
|
|
multimedia := &schema.MultimediaAttachment{
|
|
Images: []string{"https://example.com/image.png"},
|
|
Videos: []string{"https://example.com/video.mp4"},
|
|
}
|
|
|
|
jobID, err := service.ExecuteJob(taskID, params, "test", multimedia)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Wait a bit for async save to complete
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
// Ensure directory exists before saving
|
|
err = os.MkdirAll(tempDir, 0755)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
err = service.SaveJobsToFile()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
// Create a new service instance to test loading
|
|
newService := services.NewAgentJobService(
|
|
appConfig,
|
|
modelLoader,
|
|
configLoader,
|
|
evaluator,
|
|
)
|
|
|
|
err = newService.LoadJobsFromFile()
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
retrieved, err := newService.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(retrieved.TaskID).To(Equal(taskID))
|
|
Expect(retrieved.Images).To(HaveLen(1))
|
|
Expect(retrieved.Images[0]).To(Equal("https://example.com/image.png"))
|
|
Expect(retrieved.Videos).To(HaveLen(1))
|
|
Expect(retrieved.Videos[0]).To(Equal("https://example.com/video.mp4"))
|
|
})
|
|
})
|
|
|
|
Describe("Multimedia format handling", func() {
|
|
var taskID string
|
|
|
|
BeforeEach(func() {
|
|
task := schema.Task{
|
|
Name: "Test Task",
|
|
Model: "test-model",
|
|
Prompt: "Test prompt",
|
|
Enabled: true,
|
|
}
|
|
var err error
|
|
taskID, err = service.CreateTask(task)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
})
|
|
|
|
It("should handle URLs correctly", func() {
|
|
multimedia := &schema.MultimediaAttachment{
|
|
Images: []string{"https://example.com/image.png"},
|
|
Videos: []string{"http://example.com/video.mp4"},
|
|
}
|
|
|
|
jobID, err := service.ExecuteJob(taskID, map[string]string{}, "test", multimedia)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(job.Images[0]).To(Equal("https://example.com/image.png"))
|
|
Expect(job.Videos[0]).To(Equal("http://example.com/video.mp4"))
|
|
})
|
|
|
|
It("should handle data URIs correctly", func() {
|
|
multimedia := &schema.MultimediaAttachment{
|
|
Images: []string{"data:image/png;base64,iVBORw0KG"},
|
|
Videos: []string{"data:video/mp4;base64,AAAAIGZ0eXBpc29t"},
|
|
}
|
|
|
|
jobID, err := service.ExecuteJob(taskID, map[string]string{}, "test", multimedia)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(job.Images[0]).To(Equal("data:image/png;base64,iVBORw0KG"))
|
|
Expect(job.Videos[0]).To(Equal("data:video/mp4;base64,AAAAIGZ0eXBpc29t"))
|
|
})
|
|
|
|
It("should handle base64 strings (will be converted during execution)", func() {
|
|
// Base64 strings without data URI prefix should be stored as-is
|
|
// They will be converted to data URIs during execution
|
|
multimedia := &schema.MultimediaAttachment{
|
|
Images: []string{"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="},
|
|
}
|
|
|
|
jobID, err := service.ExecuteJob(taskID, map[string]string{}, "test", multimedia)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
// The base64 string is stored as-is in the job
|
|
Expect(job.Images[0]).To(Equal("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="))
|
|
})
|
|
|
|
It("should handle empty multimedia arrays", func() {
|
|
multimedia := &schema.MultimediaAttachment{
|
|
Images: []string{""},
|
|
}
|
|
|
|
jobID, err := service.ExecuteJob(taskID, map[string]string{}, "test", multimedia)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
|
|
job, err := service.GetJob(jobID)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
// Empty strings are stored in the job but will be filtered during execution
|
|
// The job stores what was provided, filtering happens in convertToMultimediaContent
|
|
Expect(job.Images).To(HaveLen(1))
|
|
Expect(job.Images[0]).To(Equal(""))
|
|
Expect(job.Videos).To(BeEmpty())
|
|
})
|
|
})
|
|
})
|
|
})
|