Skip to content

Commit 140833f

Browse files
committed
implements checks for filter breakages
1 parent 846f37f commit 140833f

File tree

4 files changed

+236
-0
lines changed

4 files changed

+236
-0
lines changed

internal/adapter/discovery/repository.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ func NewStaticEndpointRepository() *StaticEndpointRepository {
3535
}
3636
}
3737

38+
func NewStaticEndpointRepositoryWithFactory(factory *profile.Factory) *StaticEndpointRepository {
39+
return &StaticEndpointRepository{
40+
endpoints: make(map[string]*domain.Endpoint),
41+
profileFactory: factory,
42+
}
43+
}
44+
3845
func (r *StaticEndpointRepository) GetAll(ctx context.Context) ([]*domain.Endpoint, error) {
3946
r.mu.RLock()
4047
defer r.mu.RUnlock()

internal/adapter/registry/profile/factory.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,8 @@ func (f *Factory) buildPrefixLookup() {
160160
f.prefixLookup[profileName] = profileName
161161
}
162162
}
163+
164+
// GetLoader returns the profile loader for testing purposes
165+
func (f *Factory) GetLoader() *ProfileLoader {
166+
return f.loader
167+
}

internal/adapter/registry/profile/loader.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,3 +374,17 @@ func (l *ProfileLoader) GetAllProfiles() map[string]domain.InferenceProfile {
374374
}
375375
return profiles
376376
}
377+
378+
// SetFilter sets the profile filter configuration
379+
func (l *ProfileLoader) SetFilter(filter *domain.FilterConfig) {
380+
l.mu.Lock()
381+
defer l.mu.Unlock()
382+
l.profileFilter = filter
383+
}
384+
385+
// SetFilterAdapter sets the filter implementation
386+
func (l *ProfileLoader) SetFilterAdapter(filterAdapter ports.Filter) {
387+
l.mu.Lock()
388+
defer l.mu.Unlock()
389+
l.filter = filterAdapter
390+
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
package integration
2+
3+
import (
4+
"context"
5+
"testing"
6+
"time"
7+
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/require"
10+
"github.com/thushan/olla/internal/adapter/discovery"
11+
"github.com/thushan/olla/internal/adapter/filter"
12+
"github.com/thushan/olla/internal/adapter/registry/profile"
13+
"github.com/thushan/olla/internal/config"
14+
"github.com/thushan/olla/internal/core/domain"
15+
)
16+
17+
func TestFilteringOutOllamaProfile(t *testing.T) {
18+
t.Run("filtering ollama profile with no endpoints using it", func(t *testing.T) {
19+
// Create profile factory with filter that excludes ollama
20+
profileFilter := &domain.FilterConfig{
21+
Exclude: []string{"ollama"},
22+
}
23+
24+
factory, err := profile.NewFactory("../../config/profiles")
25+
require.NoError(t, err)
26+
27+
// Create filter adapter
28+
filterAdapter := filter.NewGlobFilter()
29+
30+
// Apply filter to profile loader
31+
loader := factory.GetLoader()
32+
if loader != nil {
33+
loader.SetFilterAdapter(filterAdapter)
34+
loader.SetFilter(profileFilter)
35+
err = loader.LoadProfiles()
36+
require.NoError(t, err)
37+
}
38+
39+
// Verify ollama profile is not available
40+
availableProfiles := factory.GetAvailableProfiles()
41+
assert.NotContains(t, availableProfiles, "ollama")
42+
43+
// Verify ValidateProfileType returns false for ollama
44+
assert.False(t, factory.ValidateProfileType("ollama"))
45+
46+
// Create repository with no endpoints
47+
repo := discovery.NewStaticEndpointRepository()
48+
49+
// Load empty config - should work fine
50+
err = repo.LoadFromConfig(context.Background(), []config.EndpointConfig{})
51+
assert.NoError(t, err, "Loading empty config should work even with ollama filtered")
52+
53+
// Try to get endpoints - should work fine
54+
endpoints, err := repo.GetAll(context.Background())
55+
assert.NoError(t, err)
56+
assert.Empty(t, endpoints)
57+
})
58+
59+
t.Run("filtering ollama profile breaks endpoints that use it", func(t *testing.T) {
60+
// Create profile factory with filter that excludes ollama
61+
profileFilter := &domain.FilterConfig{
62+
Exclude: []string{"ollama"},
63+
}
64+
65+
factory, err := profile.NewFactory("../../config/profiles")
66+
require.NoError(t, err)
67+
68+
// Create filter adapter
69+
filterAdapter := filter.NewGlobFilter()
70+
71+
// Apply filter to profile loader
72+
loader := factory.GetLoader()
73+
if loader != nil {
74+
loader.SetFilterAdapter(filterAdapter)
75+
loader.SetFilter(profileFilter)
76+
err = loader.LoadProfiles()
77+
require.NoError(t, err)
78+
}
79+
80+
// Create repository with the filtered factory
81+
repo := discovery.NewStaticEndpointRepositoryWithFactory(factory)
82+
83+
// Try to load config with ollama endpoint
84+
configs := []config.EndpointConfig{
85+
{
86+
Name: "test-ollama",
87+
URL: "http://localhost:11434",
88+
Type: "ollama",
89+
HealthCheckURL: "/",
90+
ModelURL: "/api/tags",
91+
CheckInterval: 5 * time.Second,
92+
CheckTimeout: 2 * time.Second,
93+
},
94+
}
95+
96+
// This should fail because ollama profile is filtered out
97+
err = repo.LoadFromConfig(context.Background(), configs)
98+
assert.Error(t, err, "Should fail to load endpoint with filtered profile type")
99+
assert.Contains(t, err.Error(), "unsupported endpoint type: ollama")
100+
})
101+
102+
// Removed test for "auto" type - auto is for discovery detection, not a real profile type
103+
104+
t.Run("endpoint with empty type works even with ollama filtered", func(t *testing.T) {
105+
// Create profile factory with filter that excludes ollama
106+
profileFilter := &domain.FilterConfig{
107+
Exclude: []string{"ollama"},
108+
}
109+
110+
factory, err := profile.NewFactory("../../config/profiles")
111+
require.NoError(t, err)
112+
113+
// Create filter adapter
114+
filterAdapter := filter.NewGlobFilter()
115+
116+
// Apply filter to profile loader
117+
loader := factory.GetLoader()
118+
if loader != nil {
119+
loader.SetFilterAdapter(filterAdapter)
120+
loader.SetFilter(profileFilter)
121+
err = loader.LoadProfiles()
122+
require.NoError(t, err)
123+
}
124+
125+
// Create repository with the filtered factory
126+
repo := discovery.NewStaticEndpointRepositoryWithFactory(factory)
127+
128+
// Load config with empty type endpoint
129+
configs := []config.EndpointConfig{
130+
{
131+
Name: "test-empty-type",
132+
URL: "http://localhost:11434",
133+
Type: "", // empty type should work (no validation)
134+
HealthCheckURL: "/",
135+
ModelURL: "/api/tags",
136+
CheckInterval: 5 * time.Second,
137+
CheckTimeout: 2 * time.Second,
138+
},
139+
}
140+
141+
// This should work because empty type skips validation
142+
err = repo.LoadFromConfig(context.Background(), configs)
143+
assert.NoError(t, err, "Should load endpoint with empty type even with ollama filtered")
144+
145+
// Verify endpoint was loaded
146+
endpoints, err := repo.GetAll(context.Background())
147+
assert.NoError(t, err)
148+
assert.Len(t, endpoints, 1)
149+
assert.Equal(t, "", endpoints[0].Type)
150+
})
151+
}
152+
153+
func TestProfileFactoryWithFiltering(t *testing.T) {
154+
t.Run("GetProfile fallback to openai-compatible when profile filtered", func(t *testing.T) {
155+
// Create factory
156+
factory, err := profile.NewFactory("../../config/profiles")
157+
require.NoError(t, err)
158+
159+
// Create filter that excludes ollama but keeps openai-compatible
160+
profileFilter := &domain.FilterConfig{
161+
Exclude: []string{"ollama"},
162+
}
163+
164+
filterAdapter := filter.NewGlobFilter()
165+
loader := factory.GetLoader()
166+
if loader != nil {
167+
loader.SetFilterAdapter(filterAdapter)
168+
loader.SetFilter(profileFilter)
169+
err = loader.LoadProfiles()
170+
require.NoError(t, err)
171+
}
172+
173+
// Try to get ollama profile - should fallback to openai-compatible
174+
profile, err := factory.GetProfile("ollama")
175+
assert.NoError(t, err, "Should fallback to openai-compatible")
176+
assert.NotNil(t, profile)
177+
178+
// Verify it's actually the openai-compatible profile
179+
config := profile.GetConfig()
180+
assert.NotNil(t, config)
181+
// The openai-compatible profile should have specific characteristics
182+
// but since GetProfile returns the fallback, this is working as designed
183+
})
184+
185+
t.Run("GetProfile fails when both ollama and openai-compatible filtered", func(t *testing.T) {
186+
// Create factory
187+
factory, err := profile.NewFactory("../../config/profiles")
188+
require.NoError(t, err)
189+
190+
// Create filter that excludes both ollama and openai-compatible
191+
profileFilter := &domain.FilterConfig{
192+
Exclude: []string{"ollama", "openai-compatible"},
193+
}
194+
195+
filterAdapter := filter.NewGlobFilter()
196+
loader := factory.GetLoader()
197+
if loader != nil {
198+
loader.SetFilterAdapter(filterAdapter)
199+
loader.SetFilter(profileFilter)
200+
err = loader.LoadProfiles()
201+
require.NoError(t, err)
202+
}
203+
204+
// Try to get ollama profile - should fail completely
205+
profile, err := factory.GetProfile("ollama")
206+
assert.Error(t, err, "Should fail when both ollama and fallback are filtered")
207+
assert.Nil(t, profile)
208+
assert.Contains(t, err.Error(), "profile not found")
209+
})
210+
}

0 commit comments

Comments
 (0)