manifest_test.go 3.73 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package server

import (
	"encoding/json"
	"os"
	"path/filepath"
	"slices"
	"testing"

	"github.com/ollama/ollama/types/model"
)

func createManifest(t *testing.T, path, name string) {
	t.Helper()

	p := filepath.Join(path, "manifests", name)
Michael Yang's avatar
lint  
Michael Yang committed
17
	if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
18
19
20
21
22
23
24
25
26
		t.Fatal(err)
	}

	f, err := os.Create(p)
	if err != nil {
		t.Fatal(err)
	}
	defer f.Close()

Michael Yang's avatar
Michael Yang committed
27
	if err := json.NewEncoder(f).Encode(Manifest{}); err != nil {
28
29
30
31
32
		t.Fatal(err)
	}
}

func TestManifests(t *testing.T) {
Michael Yang's avatar
Michael Yang committed
33
34
35
36
37
	cases := map[string]struct {
		ps               []string
		wantValidCount   int
		wantInvalidCount int
	}{
38
39
		"empty": {},
		"single": {
Michael Yang's avatar
Michael Yang committed
40
41
42
43
			ps: []string{
				filepath.Join("host", "namespace", "model", "tag"),
			},
			wantValidCount: 1,
44
45
		},
		"multiple": {
Michael Yang's avatar
Michael Yang committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
			ps: []string{
				filepath.Join("registry.ollama.ai", "library", "llama3", "latest"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q4_0"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q4_1"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q8_0"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q5_0"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q5_1"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q2_K"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q3_K_S"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q3_K_M"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q3_K_L"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q4_K_S"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q4_K_M"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q5_K_S"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q5_K_M"),
				filepath.Join("registry.ollama.ai", "library", "llama3", "q6_K"),
			},
			wantValidCount: 15,
64
65
		},
		"hidden": {
Michael Yang's avatar
Michael Yang committed
66
67
68
69
70
71
			ps: []string{
				filepath.Join("host", "namespace", "model", "tag"),
				filepath.Join("host", "namespace", "model", ".hidden"),
			},
			wantValidCount:   1,
			wantInvalidCount: 1,
72
		},
Michael Yang's avatar
Michael Yang committed
73
		"subdir": {
Michael Yang's avatar
Michael Yang committed
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
			ps: []string{
				filepath.Join("host", "namespace", "model", "tag", "one"),
				filepath.Join("host", "namespace", "model", "tag", "another", "one"),
			},
			wantInvalidCount: 2,
		},
		"upper tag": {
			ps: []string{
				filepath.Join("host", "namespace", "model", "TAG"),
			},
			wantValidCount: 1,
		},
		"upper model": {
			ps: []string{
				filepath.Join("host", "namespace", "MODEL", "tag"),
			},
			wantValidCount: 1,
		},
		"upper namespace": {
			ps: []string{
				filepath.Join("host", "NAMESPACE", "model", "tag"),
			},
			wantValidCount: 1,
		},
		"upper host": {
			ps: []string{
				filepath.Join("HOST", "namespace", "model", "tag"),
			},
			wantValidCount: 1,
Michael Yang's avatar
Michael Yang committed
103
		},
104
105
106
107
108
109
110
	}

	for n, wants := range cases {
		t.Run(n, func(t *testing.T) {
			d := t.TempDir()
			t.Setenv("OLLAMA_MODELS", d)

Michael Yang's avatar
Michael Yang committed
111
112
			for _, p := range wants.ps {
				createManifest(t, d, p)
113
114
115
116
117
118
119
120
121
122
123
124
			}

			ms, err := Manifests()
			if err != nil {
				t.Fatal(err)
			}

			var ns []model.Name
			for k := range ms {
				ns = append(ns, k)
			}

Michael Yang's avatar
Michael Yang committed
125
126
127
128
129
130
131
132
133
			var gotValidCount, gotInvalidCount int
			for _, p := range wants.ps {
				n := model.ParseNameFromFilepath(p)
				if n.IsValid() {
					gotValidCount++
				} else {
					gotInvalidCount++
				}

134
				if !n.IsValid() && slices.Contains(ns, n) {
Michael Yang's avatar
Michael Yang committed
135
					t.Errorf("unexpected invalid name: %s", p)
136
				} else if n.IsValid() && !slices.Contains(ns, n) {
Michael Yang's avatar
Michael Yang committed
137
					t.Errorf("missing valid name: %s", p)
138
139
				}
			}
Michael Yang's avatar
Michael Yang committed
140
141
142
143
144
145
146
147

			if gotValidCount != wants.wantValidCount {
				t.Errorf("got valid count %d, want %d", gotValidCount, wants.wantValidCount)
			}

			if gotInvalidCount != wants.wantInvalidCount {
				t.Errorf("got invalid count %d, want %d", gotInvalidCount, wants.wantInvalidCount)
			}
148
149
150
		})
	}
}