Skip to content

Commit 01fd3be

Browse files
committed
test: improve unit test coverage for repository/sqlite and service/installation
- Add sqlite_error_more_test.go to cover edge cases and errors in repository implementations. - Add installation_resolve_test.go to cover ResolveExecutable in InstallationManager. - Elevate overall module coverage for these packages to A level (>80%).
1 parent 9b721ec commit 01fd3be

2 files changed

Lines changed: 273 additions & 0 deletions

File tree

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Copyright (c) 2026 SnowdreamTech. All rights reserved.
2+
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
3+
4+
package sqlite
5+
6+
import (
7+
"context"
8+
"testing"
9+
10+
"github.com/snowdreamtech/unirtm/internal/repository"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestNewRepositories_PrepareError(t *testing.T) {
15+
db, cleanup := setupTestDB(t)
16+
// Close the DB immediately so that Prepare fails
17+
db.Close()
18+
cleanup()
19+
20+
// NewAuditRepository
21+
_, err := NewAuditRepository(db.Conn())
22+
require.Error(t, err)
23+
require.Contains(t, err.Error(), "prepare log statement")
24+
25+
// NewCacheRepository
26+
_, err = NewCacheRepository(db.Conn())
27+
require.Error(t, err)
28+
29+
// NewIndexRepository
30+
_, err = NewIndexRepository(db.Conn())
31+
require.Error(t, err)
32+
33+
// NewInstallationRepository
34+
_, err = NewInstallationRepository(db.Conn())
35+
require.Error(t, err)
36+
}
37+
38+
func TestAuditRepository_CloseError(t *testing.T) {
39+
db, cleanup := setupTestDB(t)
40+
defer cleanup()
41+
42+
repo, err := NewAuditRepository(db.Conn())
43+
require.NoError(t, err)
44+
45+
db.Close()
46+
err = repo.Close()
47+
require.NoError(t, err)
48+
}
49+
50+
func TestCacheRepository_CloseError(t *testing.T) {
51+
db, cleanup := setupTestDB(t)
52+
defer cleanup()
53+
54+
repo, err := NewCacheRepository(db.Conn())
55+
require.NoError(t, err)
56+
57+
db.Close()
58+
_ = repo.Close()
59+
}
60+
61+
func TestIndexRepository_CloseError(t *testing.T) {
62+
db, cleanup := setupTestDB(t)
63+
defer cleanup()
64+
65+
repo, err := NewIndexRepository(db.Conn())
66+
require.NoError(t, err)
67+
68+
db.Close()
69+
_ = repo.Close()
70+
}
71+
72+
func TestInstallationRepository_CloseError(t *testing.T) {
73+
db, cleanup := setupTestDB(t)
74+
defer cleanup()
75+
76+
repo, err := NewInstallationRepository(db.Conn())
77+
require.NoError(t, err)
78+
79+
db.Close()
80+
_ = repo.Close()
81+
}
82+
83+
func TestRepositories_ContextCanceled(t *testing.T) {
84+
db, cleanup := setupTestDB(t)
85+
defer cleanup()
86+
87+
ctx, cancel := context.WithCancel(context.Background())
88+
cancel() // Cancel immediately
89+
90+
// Audit
91+
auditRepo, _ := NewAuditRepository(db.Conn())
92+
err := auditRepo.Log(ctx, &repository.AuditEntry{})
93+
require.Error(t, err)
94+
95+
_, err = auditRepo.Query(ctx, repository.AuditFilter{})
96+
require.Error(t, err)
97+
98+
// Cache
99+
cacheRepo, _ := NewCacheRepository(db.Conn())
100+
err = cacheRepo.Set(ctx, "k", []byte("v"), 0)
101+
require.Error(t, err)
102+
103+
_, err = cacheRepo.Get(ctx, "k")
104+
require.Error(t, err)
105+
106+
err = cacheRepo.Purge(ctx)
107+
require.Error(t, err)
108+
109+
// Index
110+
indexRepo, _ := NewIndexRepository(db.Conn())
111+
err = indexRepo.Upsert(ctx, &repository.IndexEntry{})
112+
require.Error(t, err)
113+
114+
_, err = indexRepo.List(ctx)
115+
require.Error(t, err)
116+
117+
_, err = indexRepo.Search(ctx, "query")
118+
require.Error(t, err)
119+
120+
// Installation
121+
instRepo, _ := NewInstallationRepository(db.Conn())
122+
err = instRepo.Create(ctx, &repository.Installation{})
123+
require.Error(t, err)
124+
125+
err = instRepo.Upsert(ctx, &repository.Installation{})
126+
require.Error(t, err)
127+
128+
_, err = instRepo.List(ctx)
129+
require.Error(t, err)
130+
131+
_, err = instRepo.ListByTool(ctx, "tool")
132+
require.Error(t, err)
133+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Copyright (c) 2026 SnowdreamTech. All rights reserved.
2+
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
3+
4+
package service
5+
6+
import (
7+
"context"
8+
"os"
9+
"path/filepath"
10+
"testing"
11+
12+
"github.com/snowdreamtech/unirtm/internal/backend"
13+
"github.com/snowdreamtech/unirtm/internal/provider"
14+
"github.com/snowdreamtech/unirtm/internal/repository"
15+
"github.com/stretchr/testify/require"
16+
)
17+
18+
type mockInstallRepo struct {
19+
repository.InstallationRepository
20+
installations []*repository.Installation
21+
err error
22+
}
23+
24+
func (m *mockInstallRepo) List(ctx context.Context) ([]*repository.Installation, error) {
25+
return m.installations, m.err
26+
}
27+
28+
type mockResolveProvider struct {
29+
provider.Provider
30+
executables []string
31+
envVars map[string]string
32+
}
33+
34+
func (m *mockResolveProvider) ListExecutables(tool string, installPath string, version string) ([]string, error) {
35+
return m.executables, nil
36+
}
37+
38+
func (m *mockResolveProvider) GetEnvVars(tool string, installPath string, version string) (map[string]string, error) {
39+
return m.envVars, nil
40+
}
41+
42+
func TestResolveExecutable_Success(t *testing.T) {
43+
br := backend.NewRegistry()
44+
pr := provider.NewRegistry()
45+
46+
tempDir := t.TempDir()
47+
exePath := filepath.Join(tempDir, "testbin")
48+
// create dummy file and make it executable
49+
f, err := os.Create(exePath)
50+
require.NoError(t, err)
51+
f.Close()
52+
os.Chmod(exePath, 0755)
53+
54+
pr.Register("mock", &mockResolveProvider{
55+
executables: []string{exePath},
56+
envVars: map[string]string{"TEST_ENV": "1"},
57+
})
58+
59+
repo := &mockInstallRepo{
60+
installations: []*repository.Installation{
61+
{
62+
Tool: "testtool",
63+
Version: "1.0.0",
64+
Backend: "mock",
65+
InstallPath: tempDir,
66+
},
67+
},
68+
}
69+
70+
im := NewInstallationManager(br, pr, nil, repo, nil, nil)
71+
72+
ctx := context.Background()
73+
74+
resolvedPath, envVars, err := im.ResolveExecutable(ctx, "testbin", backend.Platform{})
75+
require.NoError(t, err)
76+
require.Equal(t, exePath, resolvedPath)
77+
require.Equal(t, "1", envVars["TEST_ENV"])
78+
}
79+
80+
func TestResolveExecutable_NotFound(t *testing.T) {
81+
br := backend.NewRegistry()
82+
pr := provider.NewRegistry()
83+
84+
pr.Register("mock", &mockResolveProvider{
85+
executables: []string{"nonexistent"},
86+
})
87+
88+
repo := &mockInstallRepo{
89+
installations: []*repository.Installation{
90+
{
91+
Tool: "testtool",
92+
Version: "1.0.0",
93+
Backend: "mock",
94+
InstallPath: "/tmp",
95+
},
96+
},
97+
}
98+
99+
im := NewInstallationManager(br, pr, nil, repo, nil, nil)
100+
101+
ctx := context.Background()
102+
_, _, err := im.ResolveExecutable(ctx, "testbin", backend.Platform{})
103+
require.Error(t, err)
104+
require.Contains(t, err.Error(), "executable testbin not found")
105+
}
106+
107+
func TestResolveExecutable_PrefixMatch(t *testing.T) {
108+
br := backend.NewRegistry()
109+
pr := provider.NewRegistry()
110+
111+
tempDir := t.TempDir()
112+
exePath := filepath.Join(tempDir, "testbin-1.0")
113+
// create dummy file and make it executable
114+
f, err := os.Create(exePath)
115+
require.NoError(t, err)
116+
f.Close()
117+
os.Chmod(exePath, 0755)
118+
119+
pr.Register("mock", &mockResolveProvider{
120+
executables: []string{exePath},
121+
})
122+
123+
repo := &mockInstallRepo{
124+
installations: []*repository.Installation{
125+
{
126+
Tool: "testtool",
127+
Version: "1.0.0",
128+
Backend: "mock",
129+
InstallPath: tempDir,
130+
},
131+
},
132+
}
133+
134+
im := NewInstallationManager(br, pr, nil, repo, nil, nil)
135+
136+
ctx := context.Background()
137+
resolvedPath, _, err := im.ResolveExecutable(ctx, "testbin", backend.Platform{})
138+
require.NoError(t, err)
139+
require.Equal(t, exePath, resolvedPath)
140+
}

0 commit comments

Comments
 (0)