server_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // SPDX-FileCopyrightText: Copyright The Miniflux Authors. All rights reserved.
  2. // SPDX-License-Identifier: Apache-2.0
  3. package server
  4. import (
  5. "os"
  6. "runtime"
  7. "testing"
  8. )
  9. func TestDetermineListenTargets(t *testing.T) {
  10. tests := []struct {
  11. name string
  12. addresses []string
  13. certDomain string
  14. certFile string
  15. keyFile string
  16. expected []listenTarget
  17. }{
  18. {
  19. name: "single HTTP listener",
  20. addresses: []string{":8080"},
  21. expected: []listenTarget{
  22. {address: ":8080", mode: modeHTTP},
  23. },
  24. },
  25. {
  26. name: "multiple HTTP listeners",
  27. addresses: []string{":8080", ":9090"},
  28. expected: []listenTarget{
  29. {address: ":8080", mode: modeHTTP},
  30. {address: ":9090", mode: modeHTTP},
  31. },
  32. },
  33. {
  34. name: "TLS with cert files",
  35. addresses: []string{":443"},
  36. certFile: "/path/to/cert.pem",
  37. keyFile: "/path/to/key.pem",
  38. expected: []listenTarget{
  39. {address: ":443", mode: modeTLS},
  40. },
  41. },
  42. {
  43. name: "cert file without key file falls back to HTTP",
  44. addresses: []string{":8080"},
  45. certFile: "/path/to/cert.pem",
  46. expected: []listenTarget{
  47. {address: ":8080", mode: modeHTTP},
  48. },
  49. },
  50. {
  51. name: "key file without cert file falls back to HTTP",
  52. addresses: []string{":8080"},
  53. keyFile: "/path/to/key.pem",
  54. expected: []listenTarget{
  55. {address: ":8080", mode: modeHTTP},
  56. },
  57. },
  58. {
  59. name: "autocert with :https address",
  60. addresses: []string{":https"},
  61. certDomain: "example.com",
  62. expected: []listenTarget{
  63. {address: ":https", mode: modeAutocertTLS},
  64. },
  65. },
  66. {
  67. name: "autocert with first address containing colon",
  68. addresses: []string{":443"},
  69. certDomain: "example.com",
  70. expected: []listenTarget{
  71. {address: ":443", mode: modeAutocertTLS},
  72. },
  73. },
  74. {
  75. name: "autocert does not apply to second non-https address",
  76. addresses: []string{":https", ":8080"},
  77. certDomain: "example.com",
  78. expected: []listenTarget{
  79. {address: ":https", mode: modeAutocertTLS},
  80. {address: ":8080", mode: modeHTTP},
  81. },
  82. },
  83. {
  84. name: "unix socket",
  85. addresses: []string{"/var/run/miniflux.sock"},
  86. expected: []listenTarget{
  87. {address: "/var/run/miniflux.sock", mode: modeUnixSocket},
  88. },
  89. },
  90. {
  91. name: "unix socket with TLS",
  92. addresses: []string{"/var/run/miniflux.sock"},
  93. certFile: "/path/to/cert.pem",
  94. keyFile: "/path/to/key.pem",
  95. expected: []listenTarget{
  96. {address: "/var/run/miniflux.sock", mode: modeUnixSocketTLS},
  97. },
  98. },
  99. {
  100. name: "mixed unix socket and TCP",
  101. addresses: []string{"/var/run/miniflux.sock", ":8080"},
  102. certFile: "/path/to/cert.pem",
  103. keyFile: "/path/to/key.pem",
  104. expected: []listenTarget{
  105. {address: "/var/run/miniflux.sock", mode: modeUnixSocketTLS},
  106. {address: ":8080", mode: modeTLS},
  107. },
  108. },
  109. {
  110. name: "empty address list",
  111. addresses: []string{},
  112. expected: nil,
  113. },
  114. }
  115. for _, tc := range tests {
  116. t.Run(tc.name, func(t *testing.T) {
  117. got := determineListenTargets(tc.addresses, tc.certDomain, tc.certFile, tc.keyFile)
  118. if len(got) != len(tc.expected) {
  119. t.Fatalf("got %d targets, want %d", len(got), len(tc.expected))
  120. }
  121. for i := range got {
  122. if got[i] != tc.expected[i] {
  123. t.Errorf("target[%d] = %+v, want %+v", i, got[i], tc.expected[i])
  124. }
  125. }
  126. })
  127. }
  128. }
  129. func TestAnyTLS(t *testing.T) {
  130. tests := []struct {
  131. name string
  132. targets []listenTarget
  133. expected bool
  134. }{
  135. {
  136. name: "empty list",
  137. targets: nil,
  138. expected: false,
  139. },
  140. {
  141. name: "HTTP only",
  142. targets: []listenTarget{{mode: modeHTTP}},
  143. expected: false,
  144. },
  145. {
  146. name: "systemd only",
  147. targets: []listenTarget{{mode: modeSystemd}},
  148. expected: false,
  149. },
  150. {
  151. name: "unix socket without TLS",
  152. targets: []listenTarget{{mode: modeUnixSocket}},
  153. expected: false,
  154. },
  155. {
  156. name: "TLS mode",
  157. targets: []listenTarget{{mode: modeTLS}},
  158. expected: true,
  159. },
  160. {
  161. name: "autocert TLS mode",
  162. targets: []listenTarget{{mode: modeAutocertTLS}},
  163. expected: true,
  164. },
  165. {
  166. name: "unix socket TLS mode",
  167. targets: []listenTarget{{mode: modeUnixSocketTLS}},
  168. expected: true,
  169. },
  170. {
  171. name: "mixed with one TLS",
  172. targets: []listenTarget{{mode: modeHTTP}, {mode: modeTLS}, {mode: modeUnixSocket}},
  173. expected: true,
  174. },
  175. }
  176. for _, tc := range tests {
  177. t.Run(tc.name, func(t *testing.T) {
  178. if got := anyTLS(tc.targets); got != tc.expected {
  179. t.Errorf("anyTLS() = %v, want %v", got, tc.expected)
  180. }
  181. })
  182. }
  183. }
  184. func TestCreateUnixSocketListenerPermissions(t *testing.T) {
  185. if runtime.GOOS == "windows" {
  186. t.Skip("Unix sockets are not supported on Windows")
  187. }
  188. tempFile, err := os.CreateTemp("/tmp", "miniflux-*.sock")
  189. if err != nil {
  190. t.Fatalf("Unable to allocate Unix socket path: %v", err)
  191. }
  192. socketFile := tempFile.Name()
  193. if err := tempFile.Close(); err != nil {
  194. t.Fatalf("Unable to close temporary file: %v", err)
  195. }
  196. if err := os.Remove(socketFile); err != nil {
  197. t.Fatalf("Unable to prepare Unix socket path: %v", err)
  198. }
  199. t.Cleanup(func() { os.Remove(socketFile) })
  200. listener := createUnixSocketListener(socketFile)
  201. t.Cleanup(func() { listener.Close() })
  202. fileInfo, err := os.Stat(socketFile)
  203. if err != nil {
  204. t.Fatalf("Unable to stat Unix socket: %v", err)
  205. }
  206. if got, want := fileInfo.Mode().Perm(), os.FileMode(0660); got != want {
  207. t.Errorf("Unix socket permissions = %04o, want %04o", got, want)
  208. }
  209. }