manifest_test.go 3.8 KB

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