github.com/nsqio/nsq@v1.3.0/nsqd/http_test.go (about) 1 package nsqd 2 3 import ( 4 "bytes" 5 "crypto/tls" 6 "encoding/json" 7 "fmt" 8 "io" 9 "net" 10 "net/http" 11 "os" 12 "runtime" 13 "strconv" 14 "strings" 15 "sync" 16 "testing" 17 "time" 18 19 "github.com/nsqio/go-nsq" 20 "github.com/nsqio/nsq/internal/http_api" 21 "github.com/nsqio/nsq/internal/test" 22 "github.com/nsqio/nsq/internal/version" 23 "github.com/nsqio/nsq/nsqlookupd" 24 ) 25 26 type ErrMessage struct { 27 Message string `json:"message"` 28 } 29 30 type InfoDoc struct { 31 Version string `json:"version"` 32 BroadcastAddress string `json:"broadcast_address"` 33 Hostname string `json:"hostname"` 34 HTTPPort int `json:"http_port"` 35 TCPPort int `json:"tcp_port"` 36 StartTime int64 `json:"start_time"` 37 } 38 39 func TestHTTPpub(t *testing.T) { 40 opts := NewOptions() 41 opts.Logger = test.NewTestLogger(t) 42 _, httpAddr, nsqd := mustStartNSQD(opts) 43 defer os.RemoveAll(opts.DataPath) 44 defer nsqd.Exit() 45 46 topicName := "test_http_pub" + strconv.Itoa(int(time.Now().Unix())) 47 topic := nsqd.GetTopic(topicName) 48 49 buf := bytes.NewBuffer([]byte("test message")) 50 url := fmt.Sprintf("http://%s/pub?topic=%s", httpAddr, topicName) 51 resp, err := http.Post(url, "application/octet-stream", buf) 52 test.Nil(t, err) 53 defer resp.Body.Close() 54 body, _ := io.ReadAll(resp.Body) 55 test.Equal(t, "OK", string(body)) 56 57 time.Sleep(5 * time.Millisecond) 58 59 test.Equal(t, int64(1), topic.Depth()) 60 } 61 62 func TestHTTPpubEmpty(t *testing.T) { 63 opts := NewOptions() 64 opts.Logger = test.NewTestLogger(t) 65 _, httpAddr, nsqd := mustStartNSQD(opts) 66 defer os.RemoveAll(opts.DataPath) 67 defer nsqd.Exit() 68 69 topicName := "test_http_pub_empty" + strconv.Itoa(int(time.Now().Unix())) 70 topic := nsqd.GetTopic(topicName) 71 72 buf := bytes.NewBuffer([]byte("")) 73 url := fmt.Sprintf("http://%s/pub?topic=%s", httpAddr, topicName) 74 resp, err := http.Post(url, "application/octet-stream", buf) 75 test.Nil(t, err) 76 defer resp.Body.Close() 77 body, _ := io.ReadAll(resp.Body) 78 test.Equal(t, 400, resp.StatusCode) 79 test.Equal(t, `{"message":"MSG_EMPTY"}`, string(body)) 80 81 time.Sleep(5 * time.Millisecond) 82 83 test.Equal(t, int64(0), topic.Depth()) 84 } 85 86 func TestHTTPmpub(t *testing.T) { 87 opts := NewOptions() 88 opts.Logger = test.NewTestLogger(t) 89 _, httpAddr, nsqd := mustStartNSQD(opts) 90 defer os.RemoveAll(opts.DataPath) 91 defer nsqd.Exit() 92 93 topicName := "test_http_mpub" + strconv.Itoa(int(time.Now().Unix())) 94 topic := nsqd.GetTopic(topicName) 95 96 msg := []byte("test message") 97 msgs := make([][]byte, 4) 98 for i := range msgs { 99 msgs[i] = msg 100 } 101 buf := bytes.NewBuffer(bytes.Join(msgs, []byte("\n"))) 102 103 url := fmt.Sprintf("http://%s/mpub?topic=%s", httpAddr, topicName) 104 resp, err := http.Post(url, "application/octet-stream", buf) 105 test.Nil(t, err) 106 defer resp.Body.Close() 107 body, _ := io.ReadAll(resp.Body) 108 test.Equal(t, "OK", string(body)) 109 110 time.Sleep(5 * time.Millisecond) 111 112 test.Equal(t, int64(4), topic.Depth()) 113 } 114 115 func TestHTTPmpubEmpty(t *testing.T) { 116 opts := NewOptions() 117 opts.Logger = test.NewTestLogger(t) 118 _, httpAddr, nsqd := mustStartNSQD(opts) 119 defer os.RemoveAll(opts.DataPath) 120 defer nsqd.Exit() 121 122 topicName := "test_http_mpub_empty" + strconv.Itoa(int(time.Now().Unix())) 123 topic := nsqd.GetTopic(topicName) 124 125 msg := []byte("test message") 126 msgs := make([][]byte, 4) 127 for i := range msgs { 128 msgs[i] = msg 129 } 130 buf := bytes.NewBuffer(bytes.Join(msgs, []byte("\n"))) 131 _, err := buf.Write([]byte("\n")) 132 test.Nil(t, err) 133 134 url := fmt.Sprintf("http://%s/mpub?topic=%s", httpAddr, topicName) 135 resp, err := http.Post(url, "application/octet-stream", buf) 136 test.Nil(t, err) 137 defer resp.Body.Close() 138 body, _ := io.ReadAll(resp.Body) 139 test.Equal(t, "OK", string(body)) 140 141 time.Sleep(5 * time.Millisecond) 142 143 test.Equal(t, int64(4), topic.Depth()) 144 } 145 146 func TestHTTPmpubBinary(t *testing.T) { 147 opts := NewOptions() 148 opts.Logger = test.NewTestLogger(t) 149 _, httpAddr, nsqd := mustStartNSQD(opts) 150 defer os.RemoveAll(opts.DataPath) 151 defer nsqd.Exit() 152 153 topicName := "test_http_mpub_bin" + strconv.Itoa(int(time.Now().Unix())) 154 topic := nsqd.GetTopic(topicName) 155 156 mpub := make([][]byte, 5) 157 for i := range mpub { 158 mpub[i] = make([]byte, 100) 159 } 160 cmd, _ := nsq.MultiPublish(topicName, mpub) 161 buf := bytes.NewBuffer(cmd.Body) 162 163 url := fmt.Sprintf("http://%s/mpub?topic=%s&binary=true", httpAddr, topicName) 164 resp, err := http.Post(url, "application/octet-stream", buf) 165 test.Nil(t, err) 166 defer resp.Body.Close() 167 body, _ := io.ReadAll(resp.Body) 168 test.Equal(t, "OK", string(body)) 169 170 time.Sleep(5 * time.Millisecond) 171 172 test.Equal(t, int64(5), topic.Depth()) 173 } 174 175 func TestHTTPmpubForNonNormalizedBinaryParam(t *testing.T) { 176 opts := NewOptions() 177 opts.Logger = test.NewTestLogger(t) 178 _, httpAddr, nsqd := mustStartNSQD(opts) 179 defer os.RemoveAll(opts.DataPath) 180 defer nsqd.Exit() 181 182 topicName := "test_http_mpub_bin" + strconv.Itoa(int(time.Now().Unix())) 183 topic := nsqd.GetTopic(topicName) 184 185 mpub := make([][]byte, 5) 186 for i := range mpub { 187 mpub[i] = make([]byte, 100) 188 } 189 cmd, _ := nsq.MultiPublish(topicName, mpub) 190 buf := bytes.NewBuffer(cmd.Body) 191 192 url := fmt.Sprintf("http://%s/mpub?topic=%s&binary=non_normalized_binary_param", httpAddr, topicName) 193 resp, err := http.Post(url, "application/octet-stream", buf) 194 test.Nil(t, err) 195 defer resp.Body.Close() 196 body, _ := io.ReadAll(resp.Body) 197 test.Equal(t, "OK", string(body)) 198 199 time.Sleep(5 * time.Millisecond) 200 201 test.Equal(t, int64(5), topic.Depth()) 202 } 203 204 func TestHTTPpubDefer(t *testing.T) { 205 opts := NewOptions() 206 opts.Logger = test.NewTestLogger(t) 207 _, httpAddr, nsqd := mustStartNSQD(opts) 208 defer os.RemoveAll(opts.DataPath) 209 defer nsqd.Exit() 210 211 topicName := "test_http_pub_defer" + strconv.Itoa(int(time.Now().Unix())) 212 topic := nsqd.GetTopic(topicName) 213 ch := topic.GetChannel("ch") 214 215 buf := bytes.NewBuffer([]byte("test message")) 216 url := fmt.Sprintf("http://%s/pub?topic=%s&defer=%d", httpAddr, topicName, 1000) 217 resp, err := http.Post(url, "application/octet-stream", buf) 218 test.Nil(t, err) 219 defer resp.Body.Close() 220 body, _ := io.ReadAll(resp.Body) 221 test.Equal(t, "OK", string(body)) 222 223 time.Sleep(5 * time.Millisecond) 224 225 ch.deferredMutex.Lock() 226 numDef := len(ch.deferredMessages) 227 ch.deferredMutex.Unlock() 228 test.Equal(t, 1, numDef) 229 } 230 231 func TestHTTPSRequire(t *testing.T) { 232 opts := NewOptions() 233 opts.Logger = test.NewTestLogger(t) 234 opts.LogLevel = LOG_DEBUG 235 opts.TLSCert = "./test/certs/server.pem" 236 opts.TLSKey = "./test/certs/server.key" 237 opts.TLSClientAuthPolicy = "require" 238 _, httpAddr, nsqd := mustStartNSQD(opts) 239 defer os.RemoveAll(opts.DataPath) 240 defer nsqd.Exit() 241 242 topicName := "test_http_pub_req" + strconv.Itoa(int(time.Now().Unix())) 243 topic := nsqd.GetTopic(topicName) 244 245 buf := bytes.NewBuffer([]byte("test message")) 246 url := fmt.Sprintf("http://%s/pub?topic=%s", httpAddr, topicName) 247 resp, _ := http.Post(url, "application/octet-stream", buf) 248 test.Equal(t, 403, resp.StatusCode) 249 250 httpsAddr := nsqd.httpsListener.Addr().(*net.TCPAddr) 251 cert, err := tls.LoadX509KeyPair("./test/certs/cert.pem", "./test/certs/key.pem") 252 test.Nil(t, err) 253 tlsConfig := &tls.Config{ 254 Certificates: []tls.Certificate{cert}, 255 InsecureSkipVerify: true, 256 MinVersion: 0, 257 } 258 transport := &http.Transport{ 259 TLSClientConfig: tlsConfig, 260 } 261 client := &http.Client{Transport: transport} 262 263 buf = bytes.NewBuffer([]byte("test message")) 264 url = fmt.Sprintf("https://%s/pub?topic=%s", httpsAddr, topicName) 265 resp, err = client.Post(url, "application/octet-stream", buf) 266 test.Nil(t, err) 267 defer resp.Body.Close() 268 body, _ := io.ReadAll(resp.Body) 269 test.Equal(t, "OK", string(body)) 270 271 time.Sleep(5 * time.Millisecond) 272 273 test.Equal(t, int64(1), topic.Depth()) 274 } 275 276 func TestHTTPSRequireVerify(t *testing.T) { 277 opts := NewOptions() 278 opts.Logger = test.NewTestLogger(t) 279 opts.LogLevel = LOG_DEBUG 280 opts.TLSCert = "./test/certs/server.pem" 281 opts.TLSKey = "./test/certs/server.key" 282 opts.TLSRootCAFile = "./test/certs/ca.pem" 283 opts.TLSClientAuthPolicy = "require-verify" 284 _, httpAddr, nsqd := mustStartNSQD(opts) 285 defer os.RemoveAll(opts.DataPath) 286 defer nsqd.Exit() 287 288 httpsAddr := nsqd.httpsListener.Addr().(*net.TCPAddr) 289 topicName := "test_http_pub_req_verf" + strconv.Itoa(int(time.Now().Unix())) 290 topic := nsqd.GetTopic(topicName) 291 292 // no cert 293 buf := bytes.NewBuffer([]byte("test message")) 294 url := fmt.Sprintf("http://%s/pub?topic=%s", httpAddr, topicName) 295 resp, _ := http.Post(url, "application/octet-stream", buf) 296 test.Equal(t, 403, resp.StatusCode) 297 298 // unsigned cert 299 cert, err := tls.LoadX509KeyPair("./test/certs/cert.pem", "./test/certs/key.pem") 300 test.Nil(t, err) 301 tlsConfig := &tls.Config{ 302 Certificates: []tls.Certificate{cert}, 303 InsecureSkipVerify: true, 304 } 305 transport := &http.Transport{ 306 TLSClientConfig: tlsConfig, 307 } 308 client := &http.Client{Transport: transport} 309 310 buf = bytes.NewBuffer([]byte("test message")) 311 url = fmt.Sprintf("https://%s/pub?topic=%s", httpsAddr, topicName) 312 _, err = client.Post(url, "application/octet-stream", buf) 313 test.NotNil(t, err) 314 315 // signed cert 316 cert, err = tls.LoadX509KeyPair("./test/certs/client.pem", "./test/certs/client.key") 317 test.Nil(t, err) 318 tlsConfig = &tls.Config{ 319 Certificates: []tls.Certificate{cert}, 320 InsecureSkipVerify: true, 321 } 322 transport = &http.Transport{ 323 TLSClientConfig: tlsConfig, 324 } 325 client = &http.Client{Transport: transport} 326 327 buf = bytes.NewBuffer([]byte("test message")) 328 url = fmt.Sprintf("https://%s/pub?topic=%s", httpsAddr, topicName) 329 resp, err = client.Post(url, "application/octet-stream", buf) 330 test.Nil(t, err) 331 defer resp.Body.Close() 332 body, _ := io.ReadAll(resp.Body) 333 test.Equal(t, "OK", string(body)) 334 335 time.Sleep(5 * time.Millisecond) 336 337 test.Equal(t, int64(1), topic.Depth()) 338 } 339 340 func TestTLSRequireVerifyExceptHTTP(t *testing.T) { 341 opts := NewOptions() 342 opts.Logger = test.NewTestLogger(t) 343 opts.LogLevel = LOG_DEBUG 344 opts.TLSCert = "./test/certs/server.pem" 345 opts.TLSKey = "./test/certs/server.key" 346 opts.TLSRootCAFile = "./test/certs/ca.pem" 347 opts.TLSClientAuthPolicy = "require-verify" 348 opts.TLSRequired = TLSRequiredExceptHTTP 349 _, httpAddr, nsqd := mustStartNSQD(opts) 350 defer os.RemoveAll(opts.DataPath) 351 defer nsqd.Exit() 352 353 topicName := "test_http_req_verf_except_http" + strconv.Itoa(int(time.Now().Unix())) 354 topic := nsqd.GetTopic(topicName) 355 356 // no cert 357 buf := bytes.NewBuffer([]byte("test message")) 358 url := fmt.Sprintf("http://%s/pub?topic=%s", httpAddr, topicName) 359 resp, err := http.Post(url, "application/octet-stream", buf) 360 test.Nil(t, err) 361 defer resp.Body.Close() 362 body, _ := io.ReadAll(resp.Body) 363 test.Equal(t, "OK", string(body)) 364 365 time.Sleep(5 * time.Millisecond) 366 367 test.Equal(t, int64(1), topic.Depth()) 368 } 369 370 func TestHTTPV1TopicChannel(t *testing.T) { 371 opts := NewOptions() 372 opts.Logger = test.NewTestLogger(t) 373 _, httpAddr, nsqd := mustStartNSQD(opts) 374 defer os.RemoveAll(opts.DataPath) 375 defer nsqd.Exit() 376 377 topicName := "test_http_topic_channel2" + strconv.Itoa(int(time.Now().Unix())) 378 channelName := "ch2" 379 380 url := fmt.Sprintf("http://%s/topic/create?topic=%s", httpAddr, topicName) 381 resp, err := http.Post(url, "application/json", nil) 382 test.Nil(t, err) 383 test.Equal(t, 200, resp.StatusCode) 384 body, _ := io.ReadAll(resp.Body) 385 resp.Body.Close() 386 test.Equal(t, "", string(body)) 387 test.Equal(t, "nsq; version=1.0", resp.Header.Get("X-NSQ-Content-Type")) 388 389 url = fmt.Sprintf("http://%s/channel/create?topic=%s&channel=%s", httpAddr, topicName, channelName) 390 resp, err = http.Post(url, "application/json", nil) 391 test.Nil(t, err) 392 test.Equal(t, 200, resp.StatusCode) 393 body, _ = io.ReadAll(resp.Body) 394 resp.Body.Close() 395 test.Equal(t, "", string(body)) 396 test.Equal(t, "nsq; version=1.0", resp.Header.Get("X-NSQ-Content-Type")) 397 398 topic, err := nsqd.GetExistingTopic(topicName) 399 test.Nil(t, err) 400 test.NotNil(t, topic) 401 402 channel, err := topic.GetExistingChannel(channelName) 403 test.Nil(t, err) 404 test.NotNil(t, channel) 405 406 em := ErrMessage{} 407 408 url = fmt.Sprintf("http://%s/topic/pause", httpAddr) 409 resp, err = http.Post(url, "application/json", nil) 410 test.Nil(t, err) 411 test.Equal(t, 400, resp.StatusCode) 412 test.Equal(t, "Bad Request", http.StatusText(resp.StatusCode)) 413 body, _ = io.ReadAll(resp.Body) 414 resp.Body.Close() 415 416 t.Logf("%s", body) 417 err = json.Unmarshal(body, &em) 418 test.Nil(t, err) 419 test.Equal(t, "MISSING_ARG_TOPIC", em.Message) 420 421 url = fmt.Sprintf("http://%s/topic/pause?topic=%s", httpAddr, topicName+"abc") 422 resp, err = http.Post(url, "application/json", nil) 423 test.Nil(t, err) 424 test.Equal(t, 404, resp.StatusCode) 425 test.Equal(t, "Not Found", http.StatusText(resp.StatusCode)) 426 body, _ = io.ReadAll(resp.Body) 427 resp.Body.Close() 428 429 t.Logf("%s", body) 430 err = json.Unmarshal(body, &em) 431 test.Nil(t, err) 432 test.Equal(t, "TOPIC_NOT_FOUND", em.Message) 433 434 url = fmt.Sprintf("http://%s/topic/pause?topic=%s", httpAddr, topicName) 435 resp, err = http.Post(url, "application/json", nil) 436 test.Nil(t, err) 437 test.Equal(t, 200, resp.StatusCode) 438 body, _ = io.ReadAll(resp.Body) 439 resp.Body.Close() 440 test.Equal(t, "", string(body)) 441 test.Equal(t, "nsq; version=1.0", resp.Header.Get("X-NSQ-Content-Type")) 442 443 test.Equal(t, true, topic.IsPaused()) 444 445 url = fmt.Sprintf("http://%s/topic/unpause?topic=%s", httpAddr, topicName) 446 resp, err = http.Post(url, "application/json", nil) 447 test.Nil(t, err) 448 test.Equal(t, 200, resp.StatusCode) 449 body, _ = io.ReadAll(resp.Body) 450 resp.Body.Close() 451 test.Equal(t, "", string(body)) 452 test.Equal(t, "nsq; version=1.0", resp.Header.Get("X-NSQ-Content-Type")) 453 454 test.Equal(t, false, topic.IsPaused()) 455 456 url = fmt.Sprintf("http://%s/channel/pause?topic=%s&channel=%s", httpAddr, topicName, channelName) 457 resp, err = http.Post(url, "application/json", nil) 458 test.Nil(t, err) 459 test.Equal(t, 200, resp.StatusCode) 460 body, _ = io.ReadAll(resp.Body) 461 resp.Body.Close() 462 test.Equal(t, "", string(body)) 463 test.Equal(t, "nsq; version=1.0", resp.Header.Get("X-NSQ-Content-Type")) 464 465 test.Equal(t, true, channel.IsPaused()) 466 467 url = fmt.Sprintf("http://%s/channel/unpause?topic=%s&channel=%s", httpAddr, topicName, channelName) 468 resp, err = http.Post(url, "application/json", nil) 469 test.Nil(t, err) 470 test.Equal(t, 200, resp.StatusCode) 471 body, _ = io.ReadAll(resp.Body) 472 resp.Body.Close() 473 test.Equal(t, "", string(body)) 474 test.Equal(t, "nsq; version=1.0", resp.Header.Get("X-NSQ-Content-Type")) 475 476 test.Equal(t, false, channel.IsPaused()) 477 478 url = fmt.Sprintf("http://%s/channel/delete?topic=%s&channel=%s", httpAddr, topicName, channelName) 479 resp, err = http.Post(url, "application/json", nil) 480 test.Nil(t, err) 481 test.Equal(t, 200, resp.StatusCode) 482 body, _ = io.ReadAll(resp.Body) 483 resp.Body.Close() 484 test.Equal(t, "", string(body)) 485 test.Equal(t, "nsq; version=1.0", resp.Header.Get("X-NSQ-Content-Type")) 486 487 _, err = topic.GetExistingChannel(channelName) 488 test.NotNil(t, err) 489 490 url = fmt.Sprintf("http://%s/topic/delete?topic=%s", httpAddr, topicName) 491 resp, err = http.Post(url, "application/json", nil) 492 test.Nil(t, err) 493 test.Equal(t, 200, resp.StatusCode) 494 body, _ = io.ReadAll(resp.Body) 495 resp.Body.Close() 496 test.Equal(t, "", string(body)) 497 test.Equal(t, "nsq; version=1.0", resp.Header.Get("X-NSQ-Content-Type")) 498 499 _, err = nsqd.GetExistingTopic(topicName) 500 test.NotNil(t, err) 501 } 502 503 func TestHTTPClientStats(t *testing.T) { 504 topicName := "test_http_client_stats" + strconv.Itoa(int(time.Now().Unix())) 505 506 opts := NewOptions() 507 opts.Logger = test.NewTestLogger(t) 508 tcpAddr, httpAddr, nsqd := mustStartNSQD(opts) 509 defer os.RemoveAll(opts.DataPath) 510 defer nsqd.Exit() 511 512 conn, err := mustConnectNSQD(tcpAddr) 513 test.Nil(t, err) 514 defer conn.Close() 515 516 identify(t, conn, nil, frameTypeResponse) 517 sub(t, conn, topicName, "ch") 518 519 var d struct { 520 Topics []struct { 521 Channels []struct { 522 ClientCount int `json:"client_count"` 523 Clients []struct { 524 } `json:"clients"` 525 } `json:"channels"` 526 } `json:"topics"` 527 Memory *struct{} `json:"memory,omitempty"` 528 } 529 530 endpoint := fmt.Sprintf("http://%s/stats?format=json", httpAddr) 531 err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).GETV1(endpoint, &d) 532 test.Nil(t, err) 533 534 test.Equal(t, 1, len(d.Topics[0].Channels[0].Clients)) 535 test.Equal(t, 1, d.Topics[0].Channels[0].ClientCount) 536 test.NotNil(t, d.Memory) 537 538 endpoint = fmt.Sprintf("http://%s/stats?format=json&include_clients=true", httpAddr) 539 err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).GETV1(endpoint, &d) 540 test.Nil(t, err) 541 542 test.Equal(t, 1, len(d.Topics[0].Channels[0].Clients)) 543 test.Equal(t, 1, d.Topics[0].Channels[0].ClientCount) 544 545 endpoint = fmt.Sprintf("http://%s/stats?format=json&include_clients=false", httpAddr) 546 err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).GETV1(endpoint, &d) 547 test.Nil(t, err) 548 549 test.Equal(t, 0, len(d.Topics[0].Channels[0].Clients)) 550 test.Equal(t, 1, d.Topics[0].Channels[0].ClientCount) 551 552 endpoint = fmt.Sprintf("http://%s/stats?format=json&include_mem=true", httpAddr) 553 err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).GETV1(endpoint, &d) 554 test.Nil(t, err) 555 556 test.NotNil(t, d.Memory) 557 558 d.Memory = nil 559 endpoint = fmt.Sprintf("http://%s/stats?format=json&include_mem=false", httpAddr) 560 err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).GETV1(endpoint, &d) 561 test.Nil(t, err) 562 563 test.Nil(t, d.Memory) 564 } 565 566 func TestHTTPgetStatusJSON(t *testing.T) { 567 testTime := time.Now() 568 opts := NewOptions() 569 opts.Logger = test.NewTestLogger(t) 570 _, httpAddr, nsqd := mustStartNSQD(opts) 571 defer os.RemoveAll(opts.DataPath) 572 defer nsqd.Exit() 573 574 nsqd.startTime = testTime 575 expectedJSON := fmt.Sprintf(`{"version":"%v","health":"OK","start_time":%v,"topics":[],"memory":{`, version.Binary, testTime.Unix()) 576 577 url := fmt.Sprintf("http://%s/stats?format=json", httpAddr) 578 resp, err := http.Get(url) 579 test.Nil(t, err) 580 defer resp.Body.Close() 581 body, _ := io.ReadAll(resp.Body) 582 test.Equal(t, 200, resp.StatusCode) 583 test.Equal(t, true, strings.HasPrefix(string(body), expectedJSON)) 584 } 585 586 func TestHTTPgetStatusText(t *testing.T) { 587 testTime := time.Now() 588 opts := NewOptions() 589 opts.Logger = test.NewTestLogger(t) 590 _, httpAddr, nsqd := mustStartNSQD(opts) 591 defer os.RemoveAll(opts.DataPath) 592 defer nsqd.Exit() 593 594 nsqd.startTime = testTime 595 596 url := fmt.Sprintf("http://%s/stats?format=text", httpAddr) 597 resp, err := http.Get(url) 598 test.Nil(t, err) 599 defer resp.Body.Close() 600 body, _ := io.ReadAll(resp.Body) 601 test.Equal(t, 200, resp.StatusCode) 602 test.NotNil(t, body) 603 } 604 605 func TestHTTPconfig(t *testing.T) { 606 lopts := nsqlookupd.NewOptions() 607 lopts.Logger = test.NewTestLogger(t) 608 609 lopts1 := *lopts 610 _, _, lookupd1 := mustStartNSQLookupd(&lopts1) 611 defer lookupd1.Exit() 612 lopts2 := *lopts 613 _, _, lookupd2 := mustStartNSQLookupd(&lopts2) 614 defer lookupd2.Exit() 615 616 opts := NewOptions() 617 opts.Logger = test.NewTestLogger(t) 618 _, httpAddr, nsqd := mustStartNSQD(opts) 619 defer os.RemoveAll(opts.DataPath) 620 defer nsqd.Exit() 621 622 url := fmt.Sprintf("http://%s/config/nsqlookupd_tcp_addresses", httpAddr) 623 resp, err := http.Get(url) 624 test.Nil(t, err) 625 defer resp.Body.Close() 626 body, _ := io.ReadAll(resp.Body) 627 test.Equal(t, 200, resp.StatusCode) 628 test.Equal(t, "[]", string(body)) 629 630 client := http.Client{} 631 addrs := fmt.Sprintf(`["%s","%s"]`, lookupd1.RealTCPAddr().String(), lookupd2.RealTCPAddr().String()) 632 url = fmt.Sprintf("http://%s/config/nsqlookupd_tcp_addresses", httpAddr) 633 req, err := http.NewRequest("PUT", url, bytes.NewBuffer([]byte(addrs))) 634 test.Nil(t, err) 635 resp, err = client.Do(req) 636 test.Nil(t, err) 637 defer resp.Body.Close() 638 body, _ = io.ReadAll(resp.Body) 639 test.Equal(t, 200, resp.StatusCode) 640 test.Equal(t, addrs, string(body)) 641 642 url = fmt.Sprintf("http://%s/config/log_level", httpAddr) 643 req, err = http.NewRequest("PUT", url, bytes.NewBuffer([]byte(`fatal`))) 644 test.Nil(t, err) 645 resp, err = client.Do(req) 646 test.Nil(t, err) 647 defer resp.Body.Close() 648 _, _ = io.ReadAll(resp.Body) 649 test.Equal(t, 200, resp.StatusCode) 650 test.Equal(t, LOG_FATAL, nsqd.getOpts().LogLevel) 651 652 url = fmt.Sprintf("http://%s/config/log_level", httpAddr) 653 req, err = http.NewRequest("PUT", url, bytes.NewBuffer([]byte(`bad`))) 654 test.Nil(t, err) 655 resp, err = client.Do(req) 656 test.Nil(t, err) 657 defer resp.Body.Close() 658 _, _ = io.ReadAll(resp.Body) 659 test.Equal(t, 400, resp.StatusCode) 660 } 661 662 func TestHTTPerrors(t *testing.T) { 663 opts := NewOptions() 664 opts.Logger = test.NewTestLogger(t) 665 _, httpAddr, nsqd := mustStartNSQD(opts) 666 defer os.RemoveAll(opts.DataPath) 667 defer nsqd.Exit() 668 669 url := fmt.Sprintf("http://%s/stats", httpAddr) 670 resp, err := http.Post(url, "text/plain", nil) 671 test.Nil(t, err) 672 defer resp.Body.Close() 673 body, _ := io.ReadAll(resp.Body) 674 test.Equal(t, 405, resp.StatusCode) 675 test.Equal(t, `{"message":"METHOD_NOT_ALLOWED"}`, string(body)) 676 677 url = fmt.Sprintf("http://%s/not_found", httpAddr) 678 resp, err = http.Get(url) 679 test.Nil(t, err) 680 defer resp.Body.Close() 681 body, _ = io.ReadAll(resp.Body) 682 test.Equal(t, 404, resp.StatusCode) 683 test.Equal(t, `{"message":"NOT_FOUND"}`, string(body)) 684 } 685 686 func TestDeleteTopic(t *testing.T) { 687 opts := NewOptions() 688 opts.Logger = test.NewTestLogger(t) 689 _, httpAddr, nsqd := mustStartNSQD(opts) 690 defer os.RemoveAll(opts.DataPath) 691 defer nsqd.Exit() 692 693 em := ErrMessage{} 694 695 url := fmt.Sprintf("http://%s/topic/delete", httpAddr) 696 resp, err := http.Post(url, "application/json", nil) 697 test.Nil(t, err) 698 test.Equal(t, 400, resp.StatusCode) 699 test.Equal(t, "Bad Request", http.StatusText(resp.StatusCode)) 700 body, _ := io.ReadAll(resp.Body) 701 resp.Body.Close() 702 703 t.Logf("%s", body) 704 err = json.Unmarshal(body, &em) 705 test.Nil(t, err) 706 test.Equal(t, "MISSING_ARG_TOPIC", em.Message) 707 708 topicName := "test_http_delete_topic" + strconv.Itoa(int(time.Now().Unix())) 709 710 url = fmt.Sprintf("http://%s/topic/delete?topic=%s", httpAddr, topicName) 711 resp, err = http.Post(url, "application/json", nil) 712 test.Nil(t, err) 713 test.Equal(t, 404, resp.StatusCode) 714 test.Equal(t, "Not Found", http.StatusText(resp.StatusCode)) 715 body, _ = io.ReadAll(resp.Body) 716 resp.Body.Close() 717 718 t.Logf("%s", body) 719 err = json.Unmarshal(body, &em) 720 test.Nil(t, err) 721 test.Equal(t, "TOPIC_NOT_FOUND", em.Message) 722 723 nsqd.GetTopic(topicName) 724 725 resp, err = http.Post(url, "application/json", nil) 726 test.Nil(t, err) 727 test.Equal(t, 200, resp.StatusCode) 728 body, _ = io.ReadAll(resp.Body) 729 resp.Body.Close() 730 731 t.Logf("%s", body) 732 test.Equal(t, []byte(""), body) 733 } 734 735 func TestEmptyTopic(t *testing.T) { 736 opts := NewOptions() 737 opts.Logger = test.NewTestLogger(t) 738 _, httpAddr, nsqd := mustStartNSQD(opts) 739 defer os.RemoveAll(opts.DataPath) 740 defer nsqd.Exit() 741 742 em := ErrMessage{} 743 744 url := fmt.Sprintf("http://%s/topic/empty", httpAddr) 745 resp, err := http.Post(url, "application/json", nil) 746 test.Nil(t, err) 747 test.Equal(t, 400, resp.StatusCode) 748 test.Equal(t, "Bad Request", http.StatusText(resp.StatusCode)) 749 body, _ := io.ReadAll(resp.Body) 750 resp.Body.Close() 751 752 t.Logf("%s", body) 753 err = json.Unmarshal(body, &em) 754 test.Nil(t, err) 755 test.Equal(t, "MISSING_ARG_TOPIC", em.Message) 756 757 topicName := "test_http_empty_topic" + strconv.Itoa(int(time.Now().Unix())) 758 759 url = fmt.Sprintf("http://%s/topic/empty?topic=%s", httpAddr, topicName+"$") 760 resp, err = http.Post(url, "application/json", nil) 761 test.Nil(t, err) 762 test.Equal(t, 400, resp.StatusCode) 763 test.Equal(t, "Bad Request", http.StatusText(resp.StatusCode)) 764 body, _ = io.ReadAll(resp.Body) 765 resp.Body.Close() 766 767 t.Logf("%s", body) 768 err = json.Unmarshal(body, &em) 769 test.Nil(t, err) 770 test.Equal(t, "INVALID_TOPIC", em.Message) 771 772 url = fmt.Sprintf("http://%s/topic/empty?topic=%s", httpAddr, topicName) 773 resp, err = http.Post(url, "application/json", nil) 774 test.Nil(t, err) 775 test.Equal(t, 404, resp.StatusCode) 776 test.Equal(t, "Not Found", http.StatusText(resp.StatusCode)) 777 body, _ = io.ReadAll(resp.Body) 778 resp.Body.Close() 779 780 t.Logf("%s", body) 781 err = json.Unmarshal(body, &em) 782 test.Nil(t, err) 783 test.Equal(t, "TOPIC_NOT_FOUND", em.Message) 784 785 nsqd.GetTopic(topicName) 786 787 resp, err = http.Post(url, "application/json", nil) 788 test.Nil(t, err) 789 test.Equal(t, 200, resp.StatusCode) 790 body, _ = io.ReadAll(resp.Body) 791 resp.Body.Close() 792 793 t.Logf("%s", body) 794 test.Equal(t, []byte(""), body) 795 } 796 797 func TestEmptyChannel(t *testing.T) { 798 opts := NewOptions() 799 opts.Logger = test.NewTestLogger(t) 800 _, httpAddr, nsqd := mustStartNSQD(opts) 801 defer os.RemoveAll(opts.DataPath) 802 defer nsqd.Exit() 803 804 em := ErrMessage{} 805 806 url := fmt.Sprintf("http://%s/channel/empty", httpAddr) 807 resp, err := http.Post(url, "application/json", nil) 808 test.Nil(t, err) 809 test.Equal(t, 400, resp.StatusCode) 810 test.Equal(t, "Bad Request", http.StatusText(resp.StatusCode)) 811 body, _ := io.ReadAll(resp.Body) 812 resp.Body.Close() 813 814 t.Logf("%s", body) 815 err = json.Unmarshal(body, &em) 816 test.Nil(t, err) 817 test.Equal(t, "MISSING_ARG_TOPIC", em.Message) 818 819 topicName := "test_http_empty_channel" + strconv.Itoa(int(time.Now().Unix())) 820 821 url = fmt.Sprintf("http://%s/channel/empty?topic=%s", httpAddr, topicName) 822 resp, err = http.Post(url, "application/json", nil) 823 test.Nil(t, err) 824 test.Equal(t, 400, resp.StatusCode) 825 test.Equal(t, "Bad Request", http.StatusText(resp.StatusCode)) 826 body, _ = io.ReadAll(resp.Body) 827 resp.Body.Close() 828 829 t.Logf("%s", body) 830 err = json.Unmarshal(body, &em) 831 test.Nil(t, err) 832 test.Equal(t, "MISSING_ARG_CHANNEL", em.Message) 833 834 channelName := "ch" 835 836 url = fmt.Sprintf("http://%s/channel/empty?topic=%s&channel=%s", httpAddr, topicName, channelName) 837 resp, err = http.Post(url, "application/json", nil) 838 test.Nil(t, err) 839 test.Equal(t, 404, resp.StatusCode) 840 test.Equal(t, "Not Found", http.StatusText(resp.StatusCode)) 841 body, _ = io.ReadAll(resp.Body) 842 resp.Body.Close() 843 844 t.Logf("%s", body) 845 err = json.Unmarshal(body, &em) 846 test.Nil(t, err) 847 test.Equal(t, "TOPIC_NOT_FOUND", em.Message) 848 849 topic := nsqd.GetTopic(topicName) 850 851 url = fmt.Sprintf("http://%s/channel/empty?topic=%s&channel=%s", httpAddr, topicName, channelName) 852 resp, err = http.Post(url, "application/json", nil) 853 test.Nil(t, err) 854 test.Equal(t, 404, resp.StatusCode) 855 test.Equal(t, "Not Found", http.StatusText(resp.StatusCode)) 856 body, _ = io.ReadAll(resp.Body) 857 resp.Body.Close() 858 859 t.Logf("%s", body) 860 err = json.Unmarshal(body, &em) 861 test.Nil(t, err) 862 test.Equal(t, "CHANNEL_NOT_FOUND", em.Message) 863 864 topic.GetChannel(channelName) 865 866 resp, err = http.Post(url, "application/json", nil) 867 test.Nil(t, err) 868 test.Equal(t, 200, resp.StatusCode) 869 body, _ = io.ReadAll(resp.Body) 870 resp.Body.Close() 871 872 t.Logf("%s", body) 873 test.Equal(t, []byte(""), body) 874 } 875 876 func TestInfo(t *testing.T) { 877 opts := NewOptions() 878 opts.Logger = test.NewTestLogger(t) 879 _, httpAddr, nsqd := mustStartNSQD(opts) 880 defer os.RemoveAll(opts.DataPath) 881 defer nsqd.Exit() 882 883 info := InfoDoc{} 884 885 url := fmt.Sprintf("http://%s/info", httpAddr) 886 resp, err := http.Get(url) 887 test.Nil(t, err) 888 test.Equal(t, 200, resp.StatusCode) 889 body, _ := io.ReadAll(resp.Body) 890 resp.Body.Close() 891 892 t.Logf("%s", body) 893 err = json.Unmarshal(body, &info) 894 test.Nil(t, err) 895 test.Equal(t, version.Binary, info.Version) 896 } 897 898 func BenchmarkHTTPpub(b *testing.B) { 899 var wg sync.WaitGroup 900 b.StopTimer() 901 opts := NewOptions() 902 opts.Logger = test.NewTestLogger(b) 903 opts.MemQueueSize = int64(b.N) 904 _, httpAddr, nsqd := mustStartNSQD(opts) 905 defer os.RemoveAll(opts.DataPath) 906 msg := make([]byte, 256) 907 topicName := "bench_http_pub" + strconv.Itoa(int(time.Now().Unix())) 908 url := fmt.Sprintf("http://%s/pub?topic=%s", httpAddr, topicName) 909 client := &http.Client{} 910 b.SetBytes(int64(len(msg))) 911 b.StartTimer() 912 913 for j := 0; j < runtime.GOMAXPROCS(0); j++ { 914 wg.Add(1) 915 go func() { 916 num := b.N / runtime.GOMAXPROCS(0) 917 for i := 0; i < num; i++ { 918 buf := bytes.NewBuffer(msg) 919 req, _ := http.NewRequest("POST", url, buf) 920 resp, err := client.Do(req) 921 if err != nil { 922 panic(err.Error()) 923 } 924 body, _ := io.ReadAll(resp.Body) 925 if !bytes.Equal(body, []byte("OK")) { 926 panic("bad response") 927 } 928 resp.Body.Close() 929 } 930 wg.Done() 931 }() 932 } 933 934 wg.Wait() 935 936 b.StopTimer() 937 nsqd.Exit() 938 }