...

Source file src/github.com/cybertec-postgresql/pgwatch/v6/internal/db/deadlines_test.go

Documentation: github.com/cybertec-postgresql/pgwatch/v6/internal/db

     1  package db
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"strings"
     7  	"testing"
     8  	"testing/synctest"
     9  	"time"
    10  )
    11  
    12  func TestWithFetchTimeout_BelowFloor(t *testing.T) {
    13  	orig := MinFetchTimeout
    14  	t.Cleanup(func() { MinFetchTimeout = orig })
    15  
    16  	synctest.Test(t, func(t *testing.T) {
    17  		MinFetchTimeout = 50 * time.Millisecond
    18  		ctx, cancel := WithFetchTimeout(context.Background(), "fetch x", 5*time.Millisecond)
    19  		defer cancel()
    20  		deadline, ok := ctx.Deadline()
    21  		if !ok {
    22  			t.Fatal("expected deadline to be set")
    23  		}
    24  		if got := time.Until(deadline); got < 40*time.Millisecond || got > 60*time.Millisecond {
    25  			t.Fatalf("deadline remaining %v, want ~%v (the floor)", got, MinFetchTimeout)
    26  		}
    27  	})
    28  }
    29  
    30  func TestWithFetchTimeout_AboveFloor(t *testing.T) {
    31  	orig := MinFetchTimeout
    32  	t.Cleanup(func() { MinFetchTimeout = orig })
    33  
    34  	synctest.Test(t, func(t *testing.T) {
    35  		MinFetchTimeout = 10 * time.Millisecond
    36  		ctx, cancel := WithFetchTimeout(context.Background(), "fetch x", 250*time.Millisecond)
    37  		defer cancel()
    38  		deadline, ok := ctx.Deadline()
    39  		if !ok {
    40  			t.Fatal("expected deadline to be set")
    41  		}
    42  		if got := time.Until(deadline); got < 240*time.Millisecond || got > 260*time.Millisecond {
    43  			t.Fatalf("deadline remaining %v, want ~250ms (the interval)", got)
    44  		}
    45  	})
    46  }
    47  
    48  func TestWithFetchTimeout_DeadlineFires(t *testing.T) {
    49  	orig := MinFetchTimeout
    50  	t.Cleanup(func() { MinFetchTimeout = orig })
    51  
    52  	synctest.Test(t, func(t *testing.T) {
    53  		MinFetchTimeout = 25 * time.Millisecond
    54  		ctx, cancel := WithFetchTimeout(context.Background(), "fetch db_stats", time.Millisecond)
    55  		defer cancel()
    56  		time.Sleep(50 * time.Millisecond) // fake clock advances past the 25ms deadline
    57  		if !errors.Is(ctx.Err(), context.DeadlineExceeded) {
    58  			t.Fatalf("expected context.DeadlineExceeded, got %v", ctx.Err())
    59  		}
    60  		cause := context.Cause(ctx)
    61  		if !strings.Contains(cause.Error(), "fetch db_stats") {
    62  			t.Fatalf("cause %q does not embed operation name", cause)
    63  		}
    64  	})
    65  }
    66  
    67  func TestWithOpTimeout_DeadlineEqualsD(t *testing.T) {
    68  	synctest.Test(t, func(t *testing.T) {
    69  		ctx, cancel := WithOpTimeout(context.Background(), "ping", 75*time.Millisecond)
    70  		defer cancel()
    71  		deadline, ok := ctx.Deadline()
    72  		if !ok {
    73  			t.Fatal("expected deadline")
    74  		}
    75  		if got := time.Until(deadline); got < 65*time.Millisecond || got > 85*time.Millisecond {
    76  			t.Fatalf("deadline remaining %v, want ~75ms", got)
    77  		}
    78  	})
    79  }
    80  
    81  func TestWithOpTimeout_DeadlineFires(t *testing.T) {
    82  	synctest.Test(t, func(t *testing.T) {
    83  		ctx, cancel := WithOpTimeout(context.Background(), "resolve source-x", 25*time.Millisecond)
    84  		defer cancel()
    85  		time.Sleep(50 * time.Millisecond)
    86  		if !errors.Is(ctx.Err(), context.DeadlineExceeded) {
    87  			t.Fatalf("expected context.DeadlineExceeded, got %v", ctx.Err())
    88  		}
    89  		cause := context.Cause(ctx)
    90  		if !strings.Contains(cause.Error(), "resolve source-x") {
    91  			t.Fatalf("cause %q does not embed operation name", cause)
    92  		}
    93  	})
    94  }
    95  
    96  func TestWithOpTimeout_ParentCancel(t *testing.T) {
    97  	synctest.Test(t, func(t *testing.T) {
    98  		parent, parentCancel := context.WithCancel(context.Background())
    99  		ctx, cancel := WithOpTimeout(parent, "ping", time.Hour)
   100  		defer cancel()
   101  		parentCancel()
   102  		time.Sleep(time.Millisecond)
   103  		if !errors.Is(ctx.Err(), context.Canceled) {
   104  			t.Fatalf("expected context.Canceled, got %v", ctx.Err())
   105  		}
   106  		cause := context.Cause(ctx)
   107  		if errors.Is(cause, context.DeadlineExceeded) {
   108  			t.Fatalf("cause should not be DeadlineExceeded for parent cancel; got %v", cause)
   109  		}
   110  	})
   111  }
   112