manifest_test.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package server
  2. import (
  3. "encoding/json"
  4. "os"
  5. "path/filepath"
  6. "slices"
  7. "testing"
  8. "github.com/ollama/ollama/types/model"
  9. )
  10. func createManifest(t *testing.T, path, name string) {
  11. t.Helper()
  12. p := filepath.Join(path, "manifests", name)
  13. if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
  14. t.Fatal(err)
  15. }
  16. f, err := os.Create(p)
  17. if err != nil {
  18. t.Fatal(err)
  19. }
  20. defer f.Close()
  21. if err := json.NewEncoder(f).Encode(Manifest{}); err != nil {
  22. t.Fatal(err)
  23. }
  24. }
  25. func TestManifests(t *testing.T) {
  26. cases := map[string]struct {
  27. ps []string
  28. wantValidCount int
  29. wantInvalidCount int
  30. }{
  31. "empty": {},
  32. "single": {
  33. ps: []string{
  34. filepath.Join("host", "namespace", "model", "tag"),
  35. },
  36. wantValidCount: 1,
  37. },
  38. "multiple": {
  39. ps: []string{
  40. filepath.Join("registry.ollama.ai", "library", "llama3", "latest"),
  41. filepath.Join("registry.ollama.ai", "library", "llama3", "q4_0"),
  42. filepath.Join("registry.ollama.ai", "library", "llama3", "q4_1"),
  43. filepath.Join("registry.ollama.ai", "library", "llama3", "q8_0"),
  44. filepath.Join("registry.ollama.ai", "library", "llama3", "q5_0"),
  45. filepath.Join("registry.ollama.ai", "library", "llama3", "q5_1"),
  46. filepath.Join("registry.ollama.ai", "library", "llama3", "q2_K"),
  47. filepath.Join("registry.ollama.ai", "library", "llama3", "q3_K_S"),
  48. filepath.Join("registry.ollama.ai", "library", "llama3", "q3_K_M"),
  49. filepath.Join("registry.ollama.ai", "library", "llama3", "q3_K_L"),
  50. filepath.Join("registry.ollama.ai", "library", "llama3", "q4_K_S"),
  51. filepath.Join("registry.ollama.ai", "library", "llama3", "q4_K_M"),
  52. filepath.Join("registry.ollama.ai", "library", "llama3", "q5_K_S"),
  53. filepath.Join("registry.ollama.ai", "library", "llama3", "q5_K_M"),
  54. filepath.Join("registry.ollama.ai", "library", "llama3", "q6_K"),
  55. },
  56. wantValidCount: 15,
  57. },
  58. "hidden": {
  59. ps: []string{
  60. filepath.Join("host", "namespace", "model", "tag"),
  61. filepath.Join("host", "namespace", "model", ".hidden"),
  62. },
  63. wantValidCount: 1,
  64. wantInvalidCount: 1,
  65. },
  66. "subdir": {
  67. ps: []string{
  68. filepath.Join("host", "namespace", "model", "tag", "one"),
  69. filepath.Join("host", "namespace", "model", "tag", "another", "one"),
  70. },
  71. wantInvalidCount: 2,
  72. },
  73. "upper tag": {
  74. ps: []string{
  75. filepath.Join("host", "namespace", "model", "TAG"),
  76. },
  77. wantValidCount: 1,
  78. },
  79. "upper model": {
  80. ps: []string{
  81. filepath.Join("host", "namespace", "MODEL", "tag"),
  82. },
  83. wantValidCount: 1,
  84. },
  85. "upper namespace": {
  86. ps: []string{
  87. filepath.Join("host", "NAMESPACE", "model", "tag"),
  88. },
  89. wantValidCount: 1,
  90. },
  91. "upper host": {
  92. ps: []string{
  93. filepath.Join("HOST", "namespace", "model", "tag"),
  94. },
  95. wantValidCount: 1,
  96. },
  97. }
  98. for n, wants := range cases {
  99. t.Run(n, func(t *testing.T) {
  100. d := t.TempDir()
  101. t.Setenv("OLLAMA_MODELS", d)
  102. for _, p := range wants.ps {
  103. createManifest(t, d, p)
  104. }
  105. ms, err := Manifests()
  106. if err != nil {
  107. t.Fatal(err)
  108. }
  109. var ns []model.Name
  110. for k := range ms {
  111. ns = append(ns, k)
  112. }
  113. var gotValidCount, gotInvalidCount int
  114. for _, p := range wants.ps {
  115. n := model.ParseNameFromFilepath(p)
  116. if n.IsValid() {
  117. gotValidCount++
  118. } else {
  119. gotInvalidCount++
  120. }
  121. if !n.IsValid() && slices.Contains(ns, n) {
  122. t.Errorf("unexpected invalid name: %s", p)
  123. } else if n.IsValid() && !slices.Contains(ns, n) {
  124. t.Errorf("missing valid name: %s", p)
  125. }
  126. }
  127. if gotValidCount != wants.wantValidCount {
  128. t.Errorf("got valid count %d, want %d", gotValidCount, wants.wantValidCount)
  129. }
  130. if gotInvalidCount != wants.wantInvalidCount {
  131. t.Errorf("got invalid count %d, want %d", gotInvalidCount, wants.wantInvalidCount)
  132. }
  133. })
  134. }
  135. }