github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/lib/pq/notify_test.go (about) 1 package pq 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 "os" 8 "runtime" 9 "sync" 10 "sync/atomic" 11 "testing" 12 "time" 13 ) 14 15 var errNilNotification = errors.New("nil notification") 16 17 func expectNotification(t *testing.T, ch <-chan *Notification, relname string, extra string) error { 18 select { 19 case n := <-ch: 20 if n == nil { 21 return errNilNotification 22 } 23 if n.Channel != relname || n.Extra != extra { 24 return fmt.Errorf("unexpected notification %v", n) 25 } 26 return nil 27 case <-time.After(1500 * time.Millisecond): 28 return fmt.Errorf("timeout") 29 } 30 } 31 32 func expectNoNotification(t *testing.T, ch <-chan *Notification) error { 33 select { 34 case n := <-ch: 35 return fmt.Errorf("unexpected notification %v", n) 36 case <-time.After(100 * time.Millisecond): 37 return nil 38 } 39 } 40 41 func expectEvent(t *testing.T, eventch <-chan ListenerEventType, et ListenerEventType) error { 42 select { 43 case e := <-eventch: 44 if e != et { 45 return fmt.Errorf("unexpected event %v", e) 46 } 47 return nil 48 case <-time.After(1500 * time.Millisecond): 49 panic("expectEvent timeout") 50 } 51 } 52 53 func expectNoEvent(t *testing.T, eventch <-chan ListenerEventType) error { 54 select { 55 case e := <-eventch: 56 return fmt.Errorf("unexpected event %v", e) 57 case <-time.After(100 * time.Millisecond): 58 return nil 59 } 60 } 61 62 func newTestListenerConn(t *testing.T) (*ListenerConn, <-chan *Notification) { 63 datname := os.Getenv("PGDATABASE") 64 sslmode := os.Getenv("PGSSLMODE") 65 66 if datname == "" { 67 os.Setenv("PGDATABASE", "pqgotest") 68 } 69 70 if sslmode == "" { 71 os.Setenv("PGSSLMODE", "disable") 72 } 73 74 notificationChan := make(chan *Notification) 75 l, err := NewListenerConn("", notificationChan) 76 if err != nil { 77 t.Fatal(err) 78 } 79 80 return l, notificationChan 81 } 82 83 func TestNewListenerConn(t *testing.T) { 84 l, _ := newTestListenerConn(t) 85 86 defer l.Close() 87 } 88 89 func TestConnListen(t *testing.T) { 90 l, channel := newTestListenerConn(t) 91 92 defer l.Close() 93 94 db := openTestConn(t) 95 defer db.Close() 96 97 ok, err := l.Listen("notify_test") 98 if !ok || err != nil { 99 t.Fatal(err) 100 } 101 102 _, err = db.Exec("NOTIFY notify_test") 103 if err != nil { 104 t.Fatal(err) 105 } 106 107 err = expectNotification(t, channel, "notify_test", "") 108 if err != nil { 109 t.Fatal(err) 110 } 111 } 112 113 func TestConnUnlisten(t *testing.T) { 114 l, channel := newTestListenerConn(t) 115 116 defer l.Close() 117 118 db := openTestConn(t) 119 defer db.Close() 120 121 ok, err := l.Listen("notify_test") 122 if !ok || err != nil { 123 t.Fatal(err) 124 } 125 126 _, err = db.Exec("NOTIFY notify_test") 127 128 err = expectNotification(t, channel, "notify_test", "") 129 if err != nil { 130 t.Fatal(err) 131 } 132 133 ok, err = l.Unlisten("notify_test") 134 if !ok || err != nil { 135 t.Fatal(err) 136 } 137 138 _, err = db.Exec("NOTIFY notify_test") 139 if err != nil { 140 t.Fatal(err) 141 } 142 143 err = expectNoNotification(t, channel) 144 if err != nil { 145 t.Fatal(err) 146 } 147 } 148 149 func TestConnUnlistenAll(t *testing.T) { 150 l, channel := newTestListenerConn(t) 151 152 defer l.Close() 153 154 db := openTestConn(t) 155 defer db.Close() 156 157 ok, err := l.Listen("notify_test") 158 if !ok || err != nil { 159 t.Fatal(err) 160 } 161 162 _, err = db.Exec("NOTIFY notify_test") 163 164 err = expectNotification(t, channel, "notify_test", "") 165 if err != nil { 166 t.Fatal(err) 167 } 168 169 ok, err = l.UnlistenAll() 170 if !ok || err != nil { 171 t.Fatal(err) 172 } 173 174 _, err = db.Exec("NOTIFY notify_test") 175 if err != nil { 176 t.Fatal(err) 177 } 178 179 err = expectNoNotification(t, channel) 180 if err != nil { 181 t.Fatal(err) 182 } 183 } 184 185 func TestConnClose(t *testing.T) { 186 l, _ := newTestListenerConn(t) 187 defer l.Close() 188 189 err := l.Close() 190 if err != nil { 191 t.Fatal(err) 192 } 193 err = l.Close() 194 if err != errListenerConnClosed { 195 t.Fatalf("expected errListenerConnClosed; got %v", err) 196 } 197 } 198 199 func TestConnPing(t *testing.T) { 200 l, _ := newTestListenerConn(t) 201 defer l.Close() 202 err := l.Ping() 203 if err != nil { 204 t.Fatal(err) 205 } 206 err = l.Close() 207 if err != nil { 208 t.Fatal(err) 209 } 210 err = l.Ping() 211 if err != errListenerConnClosed { 212 t.Fatalf("expected errListenerConnClosed; got %v", err) 213 } 214 } 215 216 // Test for deadlock where a query fails while another one is queued 217 func TestConnExecDeadlock(t *testing.T) { 218 l, _ := newTestListenerConn(t) 219 defer l.Close() 220 221 var wg sync.WaitGroup 222 wg.Add(2) 223 224 go func() { 225 l.ExecSimpleQuery("SELECT pg_sleep(60)") 226 wg.Done() 227 }() 228 runtime.Gosched() 229 go func() { 230 l.ExecSimpleQuery("SELECT 1") 231 wg.Done() 232 }() 233 // give the two goroutines some time to get into position 234 runtime.Gosched() 235 // calls Close on the net.Conn; equivalent to a network failure 236 l.Close() 237 238 var done int32 = 0 239 go func() { 240 time.Sleep(10 * time.Second) 241 if atomic.LoadInt32(&done) != 1 { 242 panic("timed out") 243 } 244 }() 245 wg.Wait() 246 atomic.StoreInt32(&done, 1) 247 } 248 249 // Test for ListenerConn being closed while a slow query is executing 250 func TestListenerConnCloseWhileQueryIsExecuting(t *testing.T) { 251 l, _ := newTestListenerConn(t) 252 defer l.Close() 253 254 var wg sync.WaitGroup 255 wg.Add(1) 256 257 go func() { 258 sent, err := l.ExecSimpleQuery("SELECT pg_sleep(60)") 259 if sent { 260 panic("expected sent=false") 261 } 262 // could be any of a number of errors 263 if err == nil { 264 panic("expected error") 265 } 266 wg.Done() 267 }() 268 // give the above goroutine some time to get into position 269 runtime.Gosched() 270 err := l.Close() 271 if err != nil { 272 t.Fatal(err) 273 } 274 var done int32 = 0 275 go func() { 276 time.Sleep(10 * time.Second) 277 if atomic.LoadInt32(&done) != 1 { 278 panic("timed out") 279 } 280 }() 281 wg.Wait() 282 atomic.StoreInt32(&done, 1) 283 } 284 285 func TestNotifyExtra(t *testing.T) { 286 db := openTestConn(t) 287 defer db.Close() 288 289 if getServerVersion(t, db) < 90000 { 290 t.Skip("skipping NOTIFY payload test since the server does not appear to support it") 291 } 292 293 l, channel := newTestListenerConn(t) 294 defer l.Close() 295 296 ok, err := l.Listen("notify_test") 297 if !ok || err != nil { 298 t.Fatal(err) 299 } 300 301 _, err = db.Exec("NOTIFY notify_test, 'something'") 302 if err != nil { 303 t.Fatal(err) 304 } 305 306 err = expectNotification(t, channel, "notify_test", "something") 307 if err != nil { 308 t.Fatal(err) 309 } 310 } 311 312 // create a new test listener and also set the timeouts 313 func newTestListenerTimeout(t *testing.T, min time.Duration, max time.Duration) (*Listener, <-chan ListenerEventType) { 314 datname := os.Getenv("PGDATABASE") 315 sslmode := os.Getenv("PGSSLMODE") 316 317 if datname == "" { 318 os.Setenv("PGDATABASE", "pqgotest") 319 } 320 321 if sslmode == "" { 322 os.Setenv("PGSSLMODE", "disable") 323 } 324 325 eventch := make(chan ListenerEventType, 16) 326 l := NewListener("", min, max, func(t ListenerEventType, err error) { eventch <- t }) 327 err := expectEvent(t, eventch, ListenerEventConnected) 328 if err != nil { 329 t.Fatal(err) 330 } 331 return l, eventch 332 } 333 334 func newTestListener(t *testing.T) (*Listener, <-chan ListenerEventType) { 335 return newTestListenerTimeout(t, time.Hour, time.Hour) 336 } 337 338 func TestListenerListen(t *testing.T) { 339 l, _ := newTestListener(t) 340 defer l.Close() 341 342 db := openTestConn(t) 343 defer db.Close() 344 345 err := l.Listen("notify_listen_test") 346 if err != nil { 347 t.Fatal(err) 348 } 349 350 _, err = db.Exec("NOTIFY notify_listen_test") 351 if err != nil { 352 t.Fatal(err) 353 } 354 355 err = expectNotification(t, l.Notify, "notify_listen_test", "") 356 if err != nil { 357 t.Fatal(err) 358 } 359 } 360 361 func TestListenerUnlisten(t *testing.T) { 362 l, _ := newTestListener(t) 363 defer l.Close() 364 365 db := openTestConn(t) 366 defer db.Close() 367 368 err := l.Listen("notify_listen_test") 369 if err != nil { 370 t.Fatal(err) 371 } 372 373 _, err = db.Exec("NOTIFY notify_listen_test") 374 if err != nil { 375 t.Fatal(err) 376 } 377 378 err = l.Unlisten("notify_listen_test") 379 if err != nil { 380 t.Fatal(err) 381 } 382 383 err = expectNotification(t, l.Notify, "notify_listen_test", "") 384 if err != nil { 385 t.Fatal(err) 386 } 387 388 _, err = db.Exec("NOTIFY notify_listen_test") 389 if err != nil { 390 t.Fatal(err) 391 } 392 393 err = expectNoNotification(t, l.Notify) 394 if err != nil { 395 t.Fatal(err) 396 } 397 } 398 399 func TestListenerUnlistenAll(t *testing.T) { 400 l, _ := newTestListener(t) 401 defer l.Close() 402 403 db := openTestConn(t) 404 defer db.Close() 405 406 err := l.Listen("notify_listen_test") 407 if err != nil { 408 t.Fatal(err) 409 } 410 411 _, err = db.Exec("NOTIFY notify_listen_test") 412 if err != nil { 413 t.Fatal(err) 414 } 415 416 err = l.UnlistenAll() 417 if err != nil { 418 t.Fatal(err) 419 } 420 421 err = expectNotification(t, l.Notify, "notify_listen_test", "") 422 if err != nil { 423 t.Fatal(err) 424 } 425 426 _, err = db.Exec("NOTIFY notify_listen_test") 427 if err != nil { 428 t.Fatal(err) 429 } 430 431 err = expectNoNotification(t, l.Notify) 432 if err != nil { 433 t.Fatal(err) 434 } 435 } 436 437 func TestListenerFailedQuery(t *testing.T) { 438 l, eventch := newTestListener(t) 439 defer l.Close() 440 441 db := openTestConn(t) 442 defer db.Close() 443 444 err := l.Listen("notify_listen_test") 445 if err != nil { 446 t.Fatal(err) 447 } 448 449 _, err = db.Exec("NOTIFY notify_listen_test") 450 if err != nil { 451 t.Fatal(err) 452 } 453 454 err = expectNotification(t, l.Notify, "notify_listen_test", "") 455 if err != nil { 456 t.Fatal(err) 457 } 458 459 // shouldn't cause a disconnect 460 ok, err := l.cn.ExecSimpleQuery("SELECT error") 461 if !ok { 462 t.Fatalf("could not send query to server: %v", err) 463 } 464 _, ok = err.(PGError) 465 if !ok { 466 t.Fatalf("unexpected error %v", err) 467 } 468 err = expectNoEvent(t, eventch) 469 if err != nil { 470 t.Fatal(err) 471 } 472 473 // should still work 474 _, err = db.Exec("NOTIFY notify_listen_test") 475 if err != nil { 476 t.Fatal(err) 477 } 478 479 err = expectNotification(t, l.Notify, "notify_listen_test", "") 480 if err != nil { 481 t.Fatal(err) 482 } 483 } 484 485 func TestListenerReconnect(t *testing.T) { 486 l, eventch := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour) 487 defer l.Close() 488 489 db := openTestConn(t) 490 defer db.Close() 491 492 err := l.Listen("notify_listen_test") 493 if err != nil { 494 t.Fatal(err) 495 } 496 497 _, err = db.Exec("NOTIFY notify_listen_test") 498 if err != nil { 499 t.Fatal(err) 500 } 501 502 err = expectNotification(t, l.Notify, "notify_listen_test", "") 503 if err != nil { 504 t.Fatal(err) 505 } 506 507 // kill the connection and make sure it comes back up 508 ok, err := l.cn.ExecSimpleQuery("SELECT pg_terminate_backend(pg_backend_pid())") 509 if ok { 510 t.Fatalf("could not kill the connection: %v", err) 511 } 512 if err != io.EOF { 513 t.Fatalf("unexpected error %v", err) 514 } 515 err = expectEvent(t, eventch, ListenerEventDisconnected) 516 if err != nil { 517 t.Fatal(err) 518 } 519 err = expectEvent(t, eventch, ListenerEventReconnected) 520 if err != nil { 521 t.Fatal(err) 522 } 523 524 // should still work 525 _, err = db.Exec("NOTIFY notify_listen_test") 526 if err != nil { 527 t.Fatal(err) 528 } 529 530 // should get nil after Reconnected 531 err = expectNotification(t, l.Notify, "", "") 532 if err != errNilNotification { 533 t.Fatal(err) 534 } 535 536 err = expectNotification(t, l.Notify, "notify_listen_test", "") 537 if err != nil { 538 t.Fatal(err) 539 } 540 } 541 542 func TestListenerClose(t *testing.T) { 543 l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour) 544 defer l.Close() 545 546 err := l.Close() 547 if err != nil { 548 t.Fatal(err) 549 } 550 err = l.Close() 551 if err != errListenerClosed { 552 t.Fatalf("expected errListenerClosed; got %v", err) 553 } 554 } 555 556 func TestListenerPing(t *testing.T) { 557 l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour) 558 defer l.Close() 559 560 err := l.Ping() 561 if err != nil { 562 t.Fatal(err) 563 } 564 565 err = l.Close() 566 if err != nil { 567 t.Fatal(err) 568 } 569 570 err = l.Ping() 571 if err != errListenerClosed { 572 t.Fatalf("expected errListenerClosed; got %v", err) 573 } 574 }