rest_test.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package api
  11. import (
  12. "bytes"
  13. "encoding/json"
  14. "fmt"
  15. "io/ioutil"
  16. "net/http"
  17. "strings"
  18. "sync"
  19. "testing"
  20. "devt.de/krotik/common/httputil"
  21. "devt.de/krotik/eliasdb/config"
  22. )
  23. const TESTPORT = ":9090"
  24. var lastRes []string
  25. type testEndpoint struct {
  26. *DefaultEndpointHandler
  27. }
  28. /*
  29. handleSearchQuery handles a search query REST call.
  30. */
  31. func (te *testEndpoint) HandleGET(w http.ResponseWriter, r *http.Request, resources []string) {
  32. lastRes = resources
  33. te.DefaultEndpointHandler.HandleGET(w, r, resources)
  34. }
  35. func (te *testEndpoint) SwaggerDefs(s map[string]interface{}) {
  36. }
  37. var testEndpointMap = map[string]RestEndpointInst{
  38. "/": func() RestEndpointHandler {
  39. return &testEndpoint{}
  40. },
  41. }
  42. func TestEndpointHandling(t *testing.T) {
  43. hs, wg := startServer()
  44. if hs == nil {
  45. return
  46. }
  47. defer func() {
  48. stopServer(hs, wg)
  49. }()
  50. queryURL := "http://localhost" + TESTPORT
  51. RegisterRestEndpoints(testEndpointMap)
  52. RegisterRestEndpoints(GeneralEndpointMap)
  53. lastRes = nil
  54. if res := sendTestRequest(queryURL, "GET", nil); res != "Method Not Allowed" {
  55. t.Error("Unexpected response:", res)
  56. return
  57. }
  58. if lastRes != nil {
  59. t.Error("Unexpected lastRes:", lastRes)
  60. }
  61. lastRes = nil
  62. if res := sendTestRequest(queryURL+"/foo/bar", "GET", nil); res != "Method Not Allowed" {
  63. t.Error("Unexpected response:", res)
  64. return
  65. }
  66. if fmt.Sprint(lastRes) != "[foo bar]" {
  67. t.Error("Unexpected lastRes:", lastRes)
  68. }
  69. lastRes = nil
  70. if res := sendTestRequest(queryURL+"/foo/bar/", "GET", nil); res != "Method Not Allowed" {
  71. t.Error("Unexpected response:", res)
  72. return
  73. }
  74. if fmt.Sprint(lastRes) != "[foo bar]" {
  75. t.Error("Unexpected lastRes:", lastRes)
  76. }
  77. if res := sendTestRequest(queryURL, "POST", nil); res != "Method Not Allowed" {
  78. t.Error("Unexpected response:", res)
  79. return
  80. }
  81. if res := sendTestRequest(queryURL, "PUT", nil); res != "Method Not Allowed" {
  82. t.Error("Unexpected response:", res)
  83. return
  84. }
  85. if res := sendTestRequest(queryURL, "DELETE", nil); res != "Method Not Allowed" {
  86. t.Error("Unexpected response:", res)
  87. return
  88. }
  89. if res := sendTestRequest(queryURL, "UPDATE", nil); res != "Method Not Allowed" {
  90. t.Error("Unexpected response:", res)
  91. return
  92. }
  93. // Test about endpoints
  94. if res := sendTestRequest(queryURL+"/db/about", "GET", nil); res != fmt.Sprintf(`
  95. {
  96. "api_versions": [
  97. "v1"
  98. ],
  99. "product": "EliasDB",
  100. "version": "%v"
  101. }`[1:], config.ProductVersion) {
  102. t.Error("Unexpected response:", res)
  103. return
  104. }
  105. if res := sendTestRequest(queryURL+"/db/swagger.json", "GET", nil); res != `
  106. {
  107. "basePath": "/db",
  108. "definitions": {
  109. "Error": {
  110. "description": "A human readable error mesage.",
  111. "type": "string"
  112. }
  113. },
  114. "host": "localhost:9090",
  115. "info": {
  116. "description": "Query and modify the EliasDB datastore.",
  117. "title": "EliasDB API",
  118. "version": "1.0.0"
  119. },
  120. "paths": {
  121. "/about": {
  122. "get": {
  123. "description": "Returns available API versions, product name and product version.",
  124. "produces": [
  125. "text/plain",
  126. "application/json"
  127. ],
  128. "responses": {
  129. "200": {
  130. "description": "About info object",
  131. "schema": {
  132. "properties": {
  133. "api_versions": {
  134. "description": "List of available API versions.",
  135. "items": {
  136. "description": "Available API version.",
  137. "type": "string"
  138. },
  139. "type": "array"
  140. },
  141. "product": {
  142. "description": "Product name of the REST API provider.",
  143. "type": "string"
  144. },
  145. "version": {
  146. "description": "Version of the REST API provider.",
  147. "type": "string"
  148. }
  149. },
  150. "type": "object"
  151. }
  152. },
  153. "default": {
  154. "description": "Error response",
  155. "schema": {
  156. "$ref": "#/definitions/Error"
  157. }
  158. }
  159. },
  160. "summary": "Return information about the REST API provider."
  161. }
  162. }
  163. },
  164. "produces": [
  165. "application/json"
  166. ],
  167. "schemes": [
  168. "https"
  169. ],
  170. "swagger": "2.0"
  171. }`[1:] {
  172. t.Error("Unexpected response:", res)
  173. return
  174. }
  175. }
  176. /*
  177. Send a request to a HTTP test server
  178. */
  179. func sendTestRequest(url string, method string, content []byte) string {
  180. body, _ := sendTestRequestResponse(url, method, content)
  181. return body
  182. }
  183. /*
  184. Send a request to a HTTP test server
  185. */
  186. func sendTestRequestResponse(url string, method string, content []byte) (string, *http.Response) {
  187. var req *http.Request
  188. var err error
  189. if content != nil {
  190. req, err = http.NewRequest(method, url, bytes.NewBuffer(content))
  191. } else {
  192. req, err = http.NewRequest(method, url, nil)
  193. }
  194. if err != nil {
  195. panic(err)
  196. }
  197. req.Header.Set("Content-Type", "application/json")
  198. client := &http.Client{}
  199. resp, err := client.Do(req)
  200. if err != nil {
  201. panic(err)
  202. }
  203. defer resp.Body.Close()
  204. body, _ := ioutil.ReadAll(resp.Body)
  205. bodyStr := strings.Trim(string(body), " \n")
  206. // Try json decoding first
  207. out := bytes.Buffer{}
  208. err = json.Indent(&out, []byte(bodyStr), "", " ")
  209. if err == nil {
  210. return out.String(), resp
  211. }
  212. // Just return the body
  213. return bodyStr, resp
  214. }
  215. /*
  216. Start a HTTP test server.
  217. */
  218. func startServer() (*httputil.HTTPServer, *sync.WaitGroup) {
  219. hs := &httputil.HTTPServer{}
  220. var wg sync.WaitGroup
  221. wg.Add(1)
  222. go hs.RunHTTPServer(TESTPORT, &wg)
  223. wg.Wait()
  224. // Server is started
  225. if hs.LastError != nil {
  226. panic(hs.LastError)
  227. }
  228. return hs, &wg
  229. }
  230. /*
  231. Stop a started HTTP test server.
  232. */
  233. func stopServer(hs *httputil.HTTPServer, wg *sync.WaitGroup) {
  234. if hs.Running == true {
  235. wg.Add(1)
  236. // Server is shut down
  237. hs.Shutdown()
  238. wg.Wait()
  239. } else {
  240. panic("Server was not running as expected")
  241. }
  242. }