您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

378 行
7.8 KiB

  1. package client
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "errors"
  6. "flag"
  7. "fmt"
  8. "os"
  9. "testing"
  10. "time"
  11. )
  12. const (
  13. TestStr = "Hello world"
  14. )
  15. var (
  16. client *Client
  17. runIntegrationTests bool
  18. )
  19. func TestMain(m *testing.M) {
  20. integrationsTestFlag := flag.Bool("integration", false, "Run the integration tests (in addition to the unit tests)")
  21. flag.Parse()
  22. if integrationsTestFlag != nil {
  23. runIntegrationTests = *integrationsTestFlag
  24. }
  25. code := m.Run()
  26. os.Exit(code)
  27. }
  28. func TestClientAddServer(t *testing.T) {
  29. if !runIntegrationTests {
  30. t.Skip("To run this test, use: go test -integration")
  31. }
  32. t.Log("Add local server 127.0.0.1:4730")
  33. var err error
  34. if client, err = New(Network, "127.0.0.1:4730"); err != nil {
  35. t.Fatal(err)
  36. }
  37. client.ErrorHandler = func(e error) {
  38. t.Log(e)
  39. }
  40. }
  41. func TestClientEcho(t *testing.T) {
  42. if !runIntegrationTests {
  43. t.Skip("To run this test, use: go test -integration")
  44. }
  45. echo, err := client.Echo([]byte(TestStr))
  46. if err != nil {
  47. t.Error(err)
  48. return
  49. }
  50. if string(echo) != TestStr {
  51. t.Errorf("Echo error, %s expected, %s got", TestStr, echo)
  52. return
  53. }
  54. }
  55. func TestClientDoBg(t *testing.T) {
  56. if !runIntegrationTests {
  57. t.Skip("To run this test, use: go test -integration")
  58. }
  59. handle, err := client.DoBg("ToUpper", []byte("abcdef"), JobLow)
  60. if err != nil {
  61. t.Error(err)
  62. return
  63. }
  64. if handle == "" {
  65. t.Error("Handle is empty.")
  66. } else {
  67. t.Log(handle)
  68. }
  69. }
  70. func TestClientDoBgWithId(t *testing.T) {
  71. if !runIntegrationTests {
  72. t.Skip("To run this test, use: go test -integration")
  73. }
  74. data := []byte("abcdef")
  75. hash := md5.Sum(data)
  76. id := hex.EncodeToString(hash[:])
  77. handle, err := client.DoBgWithId("ToUpper", data, JobLow, id)
  78. if err != nil {
  79. t.Error(err)
  80. return
  81. }
  82. if handle == "" {
  83. t.Error("Handle is empty.")
  84. } else {
  85. t.Log(handle)
  86. }
  87. }
  88. func TestClientDoBgWithIdFailsIfNoId(t *testing.T) {
  89. if !runIntegrationTests {
  90. t.Skip("To run this test, use: go test -integration")
  91. }
  92. data := []byte("abcdef")
  93. id := ""
  94. _, err := client.DoBgWithId("ToUpper", data, JobLow, id)
  95. if err == nil {
  96. t.Error("Expecting error")
  97. return
  98. }
  99. if err.Error() != "Invalid ID" {
  100. t.Error(fmt.Sprintf("Expecting \"Invalid ID\" error, got %s.", err.Error()))
  101. return
  102. }
  103. }
  104. func TestClientDo(t *testing.T) {
  105. if !runIntegrationTests {
  106. t.Skip("To run this test, use: go test -integration")
  107. }
  108. jobHandler := func(job *Response) {
  109. str := string(job.Data)
  110. if str == "ABCDEF" {
  111. t.Log(str)
  112. } else {
  113. t.Errorf("Invalid data: %s", job.Data)
  114. }
  115. return
  116. }
  117. handle, err := client.Do("ToUpper", []byte("abcdef"),
  118. JobLow, jobHandler)
  119. if err != nil {
  120. t.Error(err)
  121. return
  122. }
  123. if handle == "" {
  124. t.Error("Handle is empty.")
  125. } else {
  126. t.Log(handle)
  127. }
  128. }
  129. func TestClientDoWithId(t *testing.T) {
  130. if !runIntegrationTests {
  131. t.Skip("To run this test, use: go test -integration")
  132. }
  133. jobHandler := func(job *Response) {
  134. str := string(job.Data)
  135. if str == "ABCDEF" {
  136. t.Log(str)
  137. } else {
  138. t.Errorf("Invalid data: %s", job.Data)
  139. }
  140. return
  141. }
  142. data := []byte("abcdef")
  143. hash := md5.Sum(data)
  144. id := hex.EncodeToString(hash[:])
  145. handle, err := client.DoWithId("ToUpper", data,
  146. JobLow, jobHandler, id)
  147. if err != nil {
  148. t.Error(err)
  149. return
  150. }
  151. if handle == "" {
  152. t.Error("Handle is empty.")
  153. } else {
  154. t.Log(handle)
  155. }
  156. }
  157. func TestClientDoWithIdFailsIfNoId(t *testing.T) {
  158. if !runIntegrationTests {
  159. t.Skip("To run this test, use: go test -integration")
  160. }
  161. jobHandler := func(job *Response) {
  162. str := string(job.Data)
  163. if str == "ABCDEF" {
  164. t.Log(str)
  165. } else {
  166. t.Errorf("Invalid data: %s", job.Data)
  167. }
  168. return
  169. }
  170. data := []byte("abcdef")
  171. id := ""
  172. _, err := client.DoWithId("ToUpper", data,
  173. JobLow, jobHandler, id)
  174. if err == nil {
  175. t.Error("Expecting error")
  176. return
  177. }
  178. if err.Error() != "Invalid ID" {
  179. t.Error(fmt.Sprintf("Expecting \"Invalid ID\" error, got %s.", err.Error()))
  180. return
  181. }
  182. }
  183. func TestClientDoWithIdCheckSameHandle(t *testing.T) {
  184. if !runIntegrationTests {
  185. t.Skip("To run this test, use: go test -integration")
  186. }
  187. jobHandler := func(job *Response) {
  188. return
  189. }
  190. data := []byte("{productId:123,categoryId:1}")
  191. id := "123"
  192. handle1, err := client.DoWithId("PublishProduct", data,
  193. JobLow, jobHandler, id)
  194. if err != nil {
  195. t.Error(err)
  196. return
  197. }
  198. if handle1 == "" {
  199. t.Error("Handle is empty.")
  200. } else {
  201. t.Log(handle1)
  202. }
  203. handle2, err := client.DoWithId("PublishProduct", data,
  204. JobLow, jobHandler, id)
  205. if err != nil {
  206. t.Error(err)
  207. return
  208. }
  209. if handle2 == "" {
  210. t.Error("Handle is empty.")
  211. } else {
  212. t.Log(handle2)
  213. }
  214. if handle1 != handle2 {
  215. t.Error("expecting the same handle when using the same id on the same Job name")
  216. }
  217. }
  218. func TestClientDoWithIdCheckDifferentHandleOnDifferentJobs(t *testing.T) {
  219. if !runIntegrationTests {
  220. t.Skip("To run this test, use: go test -integration")
  221. }
  222. jobHandler := func(job *Response) {
  223. return
  224. }
  225. data := []byte("{productId:123}")
  226. id := "123"
  227. handle1, err := client.DoWithId("PublishProduct", data,
  228. JobLow, jobHandler, id)
  229. if err != nil {
  230. t.Error(err)
  231. return
  232. }
  233. if handle1 == "" {
  234. t.Error("Handle is empty.")
  235. } else {
  236. t.Log(handle1)
  237. }
  238. handle2, err := client.DoWithId("DeleteProduct", data,
  239. JobLow, jobHandler, id)
  240. if err != nil {
  241. t.Error(err)
  242. return
  243. }
  244. if handle2 == "" {
  245. t.Error("Handle is empty.")
  246. } else {
  247. t.Log(handle2)
  248. }
  249. if handle1 == handle2 {
  250. t.Error("expecting different handles because there are different job names")
  251. }
  252. }
  253. func TestClientMultiDo(t *testing.T) {
  254. if !runIntegrationTests {
  255. t.Skip("To run this test, use: go test -integration")
  256. }
  257. // This integration test requires that examples/pl/worker_multi.pl be running.
  258. //
  259. // Test invocation is:
  260. // go test -integration -timeout 10s -run '^TestClient(AddServer|MultiDo)$'
  261. //
  262. // Send 1000 requests to go through all race conditions
  263. const nreqs = 1000
  264. errCh := make(chan error)
  265. gotCh := make(chan string, nreqs)
  266. olderrh := client.ErrorHandler
  267. client.ErrorHandler = func(e error) { errCh <- e }
  268. client.ResponseTimeout = 5 * time.Second
  269. defer func() { client.ErrorHandler = olderrh }()
  270. nextJobCh := make(chan struct{})
  271. defer close(nextJobCh)
  272. go func() {
  273. for range nextJobCh {
  274. start := time.Now()
  275. handle, err := client.Do("PerlToUpper", []byte("abcdef"), JobNormal, func(r *Response) { gotCh <- string(r.Data) })
  276. if err == ErrLostConn && time.Since(start) > client.ResponseTimeout {
  277. errCh <- errors.New("Impossible 'lost conn', deadlock bug detected")
  278. } else if err != nil {
  279. errCh <- err
  280. }
  281. if handle == "" {
  282. errCh <- errors.New("Handle is empty.")
  283. }
  284. }
  285. }()
  286. for i := 0; i < nreqs; i++ {
  287. select {
  288. case err := <-errCh:
  289. t.Fatal(err)
  290. case nextJobCh <- struct{}{}:
  291. }
  292. }
  293. remaining := nreqs
  294. for remaining > 0 {
  295. select {
  296. case err := <-errCh:
  297. t.Fatal(err)
  298. case got := <-gotCh:
  299. if got != "ABCDEF" {
  300. t.Error("Unexpected response from PerlDoUpper: ", got)
  301. }
  302. remaining--
  303. t.Logf("%d response remaining", remaining)
  304. }
  305. }
  306. }
  307. func TestClientStatus(t *testing.T) {
  308. if !runIntegrationTests {
  309. t.Skip("To run this test, use: go test -integration")
  310. }
  311. status, err := client.Status("handle not exists")
  312. if err != nil {
  313. t.Error(err)
  314. return
  315. }
  316. if status.Known {
  317. t.Errorf("The job (%s) shouldn't be known.", status.Handle)
  318. return
  319. }
  320. if status.Running {
  321. t.Errorf("The job (%s) shouldn't be running.", status.Handle)
  322. return
  323. }
  324. handle, err := client.Do("Delay5sec", []byte("abcdef"), JobLow, nil)
  325. if err != nil {
  326. t.Error(err)
  327. return
  328. }
  329. status, err = client.Status(handle)
  330. if err != nil {
  331. t.Error(err)
  332. return
  333. }
  334. if !status.Known {
  335. t.Errorf("The job (%s) should be known.", status.Handle)
  336. return
  337. }
  338. if status.Running {
  339. t.Errorf("The job (%s) shouldn't be running.", status.Handle)
  340. return
  341. }
  342. }
  343. func TestClientClose(t *testing.T) {
  344. if !runIntegrationTests {
  345. t.Skip("To run this test, use: go test -integration")
  346. }
  347. if err := client.Close(); err != nil {
  348. t.Error(err)
  349. }
  350. }