server_test.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. package manager
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io/ioutil"
  7. "math/rand"
  8. "net/http"
  9. "strings"
  10. "testing"
  11. "time"
  12. . "github.com/smartystreets/goconvey/convey"
  13. . "github.com/tuna/tunasync/internal"
  14. )
  15. const (
  16. _magicBadWorkerID = "magic_bad_worker_id"
  17. )
  18. func postJSON(url string, obj interface{}) (*http.Response, error) {
  19. b := new(bytes.Buffer)
  20. json.NewEncoder(b).Encode(obj)
  21. return http.Post(url, "application/json; charset=utf-8", b)
  22. }
  23. func TestHTTPServer(t *testing.T) {
  24. Convey("HTTP server should work", t, func() {
  25. InitLogger(true, true, false)
  26. s := makeHTTPServer(false)
  27. So(s, ShouldNotBeNil)
  28. s.setDBAdapter(&mockDBAdapter{
  29. workerStore: map[string]workerStatus{
  30. _magicBadWorkerID: workerStatus{
  31. ID: _magicBadWorkerID,
  32. }},
  33. statusStore: make(map[string]mirrorStatus),
  34. })
  35. port := rand.Intn(10000) + 20000
  36. baseURL := fmt.Sprintf("http://127.0.0.1:%d", port)
  37. go func() {
  38. s.Run(fmt.Sprintf("127.0.0.1:%d", port))
  39. }()
  40. time.Sleep(50 * time.Microsecond)
  41. resp, err := http.Get(baseURL + "/ping")
  42. So(err, ShouldBeNil)
  43. So(resp.StatusCode, ShouldEqual, http.StatusOK)
  44. So(resp.Header.Get("Content-Type"), ShouldEqual, "application/json; charset=utf-8")
  45. defer resp.Body.Close()
  46. body, err := ioutil.ReadAll(resp.Body)
  47. So(err, ShouldBeNil)
  48. var p map[string]string
  49. err = json.Unmarshal(body, &p)
  50. So(err, ShouldBeNil)
  51. So(p[_infoKey], ShouldEqual, "pong")
  52. Convey("when database fail", func() {
  53. resp, err := http.Get(fmt.Sprintf("%s/workers/%s/jobs", baseURL, _magicBadWorkerID))
  54. So(err, ShouldBeNil)
  55. So(resp.StatusCode, ShouldEqual, http.StatusInternalServerError)
  56. defer resp.Body.Close()
  57. var msg map[string]string
  58. err = json.NewDecoder(resp.Body).Decode(&msg)
  59. So(err, ShouldBeNil)
  60. So(msg[_errorKey], ShouldEqual, fmt.Sprintf("failed to list jobs of worker %s: %s", _magicBadWorkerID, "database fail"))
  61. })
  62. Convey("when register a worker", func() {
  63. w := workerStatus{
  64. ID: "test_worker1",
  65. }
  66. resp, err := postJSON(baseURL+"/workers", w)
  67. So(err, ShouldBeNil)
  68. So(resp.StatusCode, ShouldEqual, http.StatusOK)
  69. Convey("list all workers", func() {
  70. So(err, ShouldBeNil)
  71. resp, err := http.Get(baseURL + "/workers")
  72. So(err, ShouldBeNil)
  73. defer resp.Body.Close()
  74. var actualResponseObj []WorkerInfoMsg
  75. err = json.NewDecoder(resp.Body).Decode(&actualResponseObj)
  76. So(err, ShouldBeNil)
  77. So(len(actualResponseObj), ShouldEqual, 2)
  78. })
  79. Convey("update mirror status of a existed worker", func() {
  80. status := mirrorStatus{
  81. Name: "arch-sync1",
  82. Worker: "test_worker1",
  83. IsMaster: true,
  84. Status: Success,
  85. LastUpdate: time.Now(),
  86. Upstream: "mirrors.tuna.tsinghua.edu.cn",
  87. Size: "3GB",
  88. }
  89. resp, err := postJSON(fmt.Sprintf("%s/workers/%s/jobs/%s", baseURL, status.Worker, status.Name), status)
  90. So(err, ShouldBeNil)
  91. So(resp.StatusCode, ShouldEqual, http.StatusOK)
  92. Convey("list mirror status of an existed worker", func() {
  93. expectedResponse, err := json.Marshal([]mirrorStatus{status})
  94. So(err, ShouldBeNil)
  95. resp, err := http.Get(baseURL + "/workers/test_worker1/jobs")
  96. So(err, ShouldBeNil)
  97. So(resp.StatusCode, ShouldEqual, http.StatusOK)
  98. // err = json.NewDecoder(resp.Body).Decode(&mirrorStatusList)
  99. body, err := ioutil.ReadAll(resp.Body)
  100. defer resp.Body.Close()
  101. So(err, ShouldBeNil)
  102. So(strings.TrimSpace(string(body)), ShouldEqual, string(expectedResponse))
  103. })
  104. Convey("list all job status of all workers", func() {
  105. expectedResponse, err := json.Marshal([]mirrorStatus{status})
  106. So(err, ShouldBeNil)
  107. resp, err := http.Get(baseURL + "/jobs")
  108. So(err, ShouldBeNil)
  109. So(resp.StatusCode, ShouldEqual, http.StatusOK)
  110. body, err := ioutil.ReadAll(resp.Body)
  111. defer resp.Body.Close()
  112. So(err, ShouldBeNil)
  113. So(strings.TrimSpace(string(body)), ShouldEqual, string(expectedResponse))
  114. })
  115. })
  116. Convey("update mirror status of an inexisted worker", func() {
  117. invalidWorker := "test_worker2"
  118. status := mirrorStatus{
  119. Name: "arch-sync2",
  120. Worker: invalidWorker,
  121. IsMaster: true,
  122. Status: Success,
  123. LastUpdate: time.Now(),
  124. Upstream: "mirrors.tuna.tsinghua.edu.cn",
  125. Size: "4GB",
  126. }
  127. resp, err := postJSON(fmt.Sprintf("%s/workers/%s/jobs/%s",
  128. baseURL, status.Worker, status.Name), status)
  129. So(err, ShouldBeNil)
  130. So(resp.StatusCode, ShouldEqual, http.StatusBadRequest)
  131. defer resp.Body.Close()
  132. var msg map[string]string
  133. err = json.NewDecoder(resp.Body).Decode(&msg)
  134. So(err, ShouldBeNil)
  135. So(msg[_errorKey], ShouldEqual, "invalid workerID "+invalidWorker)
  136. })
  137. })
  138. })
  139. }
  140. type mockDBAdapter struct {
  141. workerStore map[string]workerStatus
  142. statusStore map[string]mirrorStatus
  143. }
  144. func (b *mockDBAdapter) Init() error {
  145. return nil
  146. }
  147. func (b *mockDBAdapter) ListWorkers() ([]workerStatus, error) {
  148. workers := make([]workerStatus, len(b.workerStore))
  149. idx := 0
  150. for _, w := range b.workerStore {
  151. workers[idx] = w
  152. idx++
  153. }
  154. return workers, nil
  155. }
  156. func (b *mockDBAdapter) GetWorker(workerID string) (workerStatus, error) {
  157. w, ok := b.workerStore[workerID]
  158. if !ok {
  159. return workerStatus{}, fmt.Errorf("invalid workerId")
  160. }
  161. return w, nil
  162. }
  163. func (b *mockDBAdapter) CreateWorker(w workerStatus) (workerStatus, error) {
  164. // _, ok := b.workerStore[w.ID]
  165. // if ok {
  166. // return workerStatus{}, fmt.Errorf("duplicate worker name")
  167. // }
  168. b.workerStore[w.ID] = w
  169. return w, nil
  170. }
  171. func (b *mockDBAdapter) GetMirrorStatus(workerID, mirrorID string) (mirrorStatus, error) {
  172. id := mirrorID + "/" + workerID
  173. status, ok := b.statusStore[id]
  174. if !ok {
  175. return mirrorStatus{}, fmt.Errorf("no mirror %s exists in worker %s", mirrorID, workerID)
  176. }
  177. return status, nil
  178. }
  179. func (b *mockDBAdapter) UpdateMirrorStatus(workerID, mirrorID string, status mirrorStatus) (mirrorStatus, error) {
  180. // if _, ok := b.workerStore[workerID]; !ok {
  181. // // unregistered worker
  182. // return mirrorStatus{}, fmt.Errorf("invalid workerID %s", workerID)
  183. // }
  184. id := mirrorID + "/" + workerID
  185. b.statusStore[id] = status
  186. return status, nil
  187. }
  188. func (b *mockDBAdapter) ListMirrorStatus(workerID string) ([]mirrorStatus, error) {
  189. var mirrorStatusList []mirrorStatus
  190. // simulating a database fail
  191. if workerID == _magicBadWorkerID {
  192. return []mirrorStatus{}, fmt.Errorf("database fail")
  193. }
  194. for k, v := range b.statusStore {
  195. if wID := strings.Split(k, "/")[1]; wID == workerID {
  196. mirrorStatusList = append(mirrorStatusList, v)
  197. }
  198. }
  199. return mirrorStatusList, nil
  200. }
  201. func (b *mockDBAdapter) ListAllMirrorStatus() ([]mirrorStatus, error) {
  202. var mirrorStatusList []mirrorStatus
  203. for _, v := range b.statusStore {
  204. mirrorStatusList = append(mirrorStatusList, v)
  205. }
  206. return mirrorStatusList, nil
  207. }
  208. func (b *mockDBAdapter) Close() error {
  209. return nil
  210. }