config_test.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package envconfig
  2. import (
  3. "math"
  4. "testing"
  5. "time"
  6. "github.com/google/go-cmp/cmp"
  7. )
  8. func TestHost(t *testing.T) {
  9. cases := map[string]struct {
  10. value string
  11. expect string
  12. }{
  13. "empty": {"", "http://127.0.0.1:11434"},
  14. "only address": {"1.2.3.4", "http://1.2.3.4:11434"},
  15. "only port": {":1234", "http://:1234"},
  16. "address and port": {"1.2.3.4:1234", "http://1.2.3.4:1234"},
  17. "hostname": {"example.com", "http://example.com:11434"},
  18. "hostname and port": {"example.com:1234", "http://example.com:1234"},
  19. "zero port": {":0", "http://:0"},
  20. "too large port": {":66000", "http://:11434"},
  21. "too small port": {":-1", "http://:11434"},
  22. "ipv6 localhost": {"[::1]", "http://[::1]:11434"},
  23. "ipv6 world open": {"[::]", "http://[::]:11434"},
  24. "ipv6 no brackets": {"::1", "http://[::1]:11434"},
  25. "ipv6 + port": {"[::1]:1337", "http://[::1]:1337"},
  26. "extra space": {" 1.2.3.4 ", "http://1.2.3.4:11434"},
  27. "extra quotes": {"\"1.2.3.4\"", "http://1.2.3.4:11434"},
  28. "extra space+quotes": {" \" 1.2.3.4 \" ", "http://1.2.3.4:11434"},
  29. "extra single quotes": {"'1.2.3.4'", "http://1.2.3.4:11434"},
  30. "http": {"http://1.2.3.4", "http://1.2.3.4:80"},
  31. "http port": {"http://1.2.3.4:4321", "http://1.2.3.4:4321"},
  32. "https": {"https://1.2.3.4", "https://1.2.3.4:443"},
  33. "https port": {"https://1.2.3.4:4321", "https://1.2.3.4:4321"},
  34. "proxy path": {"https://example.com/ollama", "https://example.com:443/ollama"},
  35. }
  36. for name, tt := range cases {
  37. t.Run(name, func(t *testing.T) {
  38. t.Setenv("OLLAMA_HOST", tt.value)
  39. if host := Host(); host.String() != tt.expect {
  40. t.Errorf("%s: expected %s, got %s", name, tt.expect, host.String())
  41. }
  42. })
  43. }
  44. }
  45. func TestOrigins(t *testing.T) {
  46. cases := []struct {
  47. value string
  48. expect []string
  49. }{
  50. {"", []string{
  51. "http://localhost",
  52. "https://localhost",
  53. "http://localhost:*",
  54. "https://localhost:*",
  55. "http://127.0.0.1",
  56. "https://127.0.0.1",
  57. "http://127.0.0.1:*",
  58. "https://127.0.0.1:*",
  59. "http://0.0.0.0",
  60. "https://0.0.0.0",
  61. "http://0.0.0.0:*",
  62. "https://0.0.0.0:*",
  63. "app://*",
  64. "file://*",
  65. "tauri://*",
  66. "vscode-webview://*",
  67. "vscode-file://*",
  68. }},
  69. {"http://10.0.0.1", []string{
  70. "http://10.0.0.1",
  71. "http://localhost",
  72. "https://localhost",
  73. "http://localhost:*",
  74. "https://localhost:*",
  75. "http://127.0.0.1",
  76. "https://127.0.0.1",
  77. "http://127.0.0.1:*",
  78. "https://127.0.0.1:*",
  79. "http://0.0.0.0",
  80. "https://0.0.0.0",
  81. "http://0.0.0.0:*",
  82. "https://0.0.0.0:*",
  83. "app://*",
  84. "file://*",
  85. "tauri://*",
  86. "vscode-webview://*",
  87. "vscode-file://*",
  88. }},
  89. {"http://172.16.0.1,https://192.168.0.1", []string{
  90. "http://172.16.0.1",
  91. "https://192.168.0.1",
  92. "http://localhost",
  93. "https://localhost",
  94. "http://localhost:*",
  95. "https://localhost:*",
  96. "http://127.0.0.1",
  97. "https://127.0.0.1",
  98. "http://127.0.0.1:*",
  99. "https://127.0.0.1:*",
  100. "http://0.0.0.0",
  101. "https://0.0.0.0",
  102. "http://0.0.0.0:*",
  103. "https://0.0.0.0:*",
  104. "app://*",
  105. "file://*",
  106. "tauri://*",
  107. "vscode-webview://*",
  108. "vscode-file://*",
  109. }},
  110. {"http://totally.safe,http://definitely.legit", []string{
  111. "http://totally.safe",
  112. "http://definitely.legit",
  113. "http://localhost",
  114. "https://localhost",
  115. "http://localhost:*",
  116. "https://localhost:*",
  117. "http://127.0.0.1",
  118. "https://127.0.0.1",
  119. "http://127.0.0.1:*",
  120. "https://127.0.0.1:*",
  121. "http://0.0.0.0",
  122. "https://0.0.0.0",
  123. "http://0.0.0.0:*",
  124. "https://0.0.0.0:*",
  125. "app://*",
  126. "file://*",
  127. "tauri://*",
  128. "vscode-webview://*",
  129. "vscode-file://*",
  130. }},
  131. }
  132. for _, tt := range cases {
  133. t.Run(tt.value, func(t *testing.T) {
  134. t.Setenv("OLLAMA_ORIGINS", tt.value)
  135. if diff := cmp.Diff(AllowedOrigins(), tt.expect); diff != "" {
  136. t.Errorf("%s: mismatch (-want +got):\n%s", tt.value, diff)
  137. }
  138. })
  139. }
  140. }
  141. func TestBool(t *testing.T) {
  142. cases := map[string]bool{
  143. "": false,
  144. "true": true,
  145. "false": false,
  146. "1": true,
  147. "0": false,
  148. // invalid values
  149. "random": true,
  150. "something": true,
  151. }
  152. for k, v := range cases {
  153. t.Run(k, func(t *testing.T) {
  154. t.Setenv("OLLAMA_BOOL", k)
  155. if b := Bool("OLLAMA_BOOL")(); b != v {
  156. t.Errorf("%s: expected %t, got %t", k, v, b)
  157. }
  158. })
  159. }
  160. }
  161. func TestUint(t *testing.T) {
  162. cases := map[string]uint{
  163. "0": 0,
  164. "1": 1,
  165. "1337": 1337,
  166. // default values
  167. "": 11434,
  168. "-1": 11434,
  169. "0o10": 11434,
  170. "0x10": 11434,
  171. "string": 11434,
  172. }
  173. for k, v := range cases {
  174. t.Run(k, func(t *testing.T) {
  175. t.Setenv("OLLAMA_UINT", k)
  176. if i := Uint("OLLAMA_UINT", 11434)(); i != v {
  177. t.Errorf("%s: expected %d, got %d", k, v, i)
  178. }
  179. })
  180. }
  181. }
  182. func TestKeepAlive(t *testing.T) {
  183. cases := map[string]time.Duration{
  184. "": 5 * time.Minute,
  185. "1s": time.Second,
  186. "1m": time.Minute,
  187. "1h": time.Hour,
  188. "5m0s": 5 * time.Minute,
  189. "1h2m3s": 1*time.Hour + 2*time.Minute + 3*time.Second,
  190. "0": time.Duration(0),
  191. "60": 60 * time.Second,
  192. "120": 2 * time.Minute,
  193. "3600": time.Hour,
  194. "-0": time.Duration(0),
  195. "-1": time.Duration(math.MaxInt64),
  196. "-1m": time.Duration(math.MaxInt64),
  197. // invalid values
  198. " ": 5 * time.Minute,
  199. "???": 5 * time.Minute,
  200. "1d": 5 * time.Minute,
  201. "1y": 5 * time.Minute,
  202. "1w": 5 * time.Minute,
  203. }
  204. for tt, expect := range cases {
  205. t.Run(tt, func(t *testing.T) {
  206. t.Setenv("OLLAMA_KEEP_ALIVE", tt)
  207. if actual := KeepAlive(); actual != expect {
  208. t.Errorf("%s: expected %s, got %s", tt, expect, actual)
  209. }
  210. })
  211. }
  212. }
  213. func TestLoadTimeout(t *testing.T) {
  214. defaultTimeout := 5 * time.Minute
  215. cases := map[string]time.Duration{
  216. "": defaultTimeout,
  217. "1s": time.Second,
  218. "1m": time.Minute,
  219. "1h": time.Hour,
  220. "5m0s": defaultTimeout,
  221. "1h2m3s": 1*time.Hour + 2*time.Minute + 3*time.Second,
  222. "0": time.Duration(math.MaxInt64),
  223. "60": 60 * time.Second,
  224. "120": 2 * time.Minute,
  225. "3600": time.Hour,
  226. "-0": time.Duration(math.MaxInt64),
  227. "-1": time.Duration(math.MaxInt64),
  228. "-1m": time.Duration(math.MaxInt64),
  229. // invalid values
  230. " ": defaultTimeout,
  231. "???": defaultTimeout,
  232. "1d": defaultTimeout,
  233. "1y": defaultTimeout,
  234. "1w": defaultTimeout,
  235. }
  236. for tt, expect := range cases {
  237. t.Run(tt, func(t *testing.T) {
  238. t.Setenv("OLLAMA_LOAD_TIMEOUT", tt)
  239. if actual := LoadTimeout(); actual != expect {
  240. t.Errorf("%s: expected %s, got %s", tt, expect, actual)
  241. }
  242. })
  243. }
  244. }
  245. func TestVar(t *testing.T) {
  246. cases := map[string]string{
  247. "value": "value",
  248. " value ": "value",
  249. " 'value' ": "value",
  250. ` "value" `: "value",
  251. " ' value ' ": " value ",
  252. ` " value " `: " value ",
  253. }
  254. for k, v := range cases {
  255. t.Run(k, func(t *testing.T) {
  256. t.Setenv("OLLAMA_VAR", k)
  257. if s := Var("OLLAMA_VAR"); s != v {
  258. t.Errorf("%s: expected %q, got %q", k, v, s)
  259. }
  260. })
  261. }
  262. }
  263. func TestContextLength(t *testing.T) {
  264. cases := map[string]uint{
  265. "": 2048,
  266. "4096": 4096,
  267. }
  268. for k, v := range cases {
  269. t.Run(k, func(t *testing.T) {
  270. t.Setenv("OLLAMA_CONTEXT_LENGTH", k)
  271. if i := ContextLength(); i != v {
  272. t.Errorf("%s: expected %d, got %d", k, v, i)
  273. }
  274. })
  275. }
  276. }