package httpfetcher import ( "context" "errors" "net" "syscall" "testing" "time" ) // TestFetchFailedBeforeAnswer checks that a fetch whose connection is refused // fails with ErrUpstreamRequestFailed, and that a fetch its caller cancels // while connecting fails with context.Canceled and not with // ErrUpstreamRequestFailed. func TestFetchFailedBeforeAnswer(t *testing.T) { t.Parallel() tests := []struct { name string dial func(cancel context.CancelFunc) error wantErr error wantNotErr error }{ { name: "connection refused", dial: func(context.CancelFunc) error { return syscall.ECONNREFUSED }, wantErr: ErrUpstreamRequestFailed, wantNotErr: context.Canceled, }, { name: "cancelled while connecting", dial: func(cancel context.CancelFunc) error { cancel() return context.Canceled }, wantErr: context.Canceled, wantNotErr: ErrUpstreamRequestFailed, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() ctx, cancel := context.WithCancel(testContext(t)) defer cancel() f := New(&Config{ Timeout: 30 * time.Second, MaxResponseSize: 50 << 20, AllowHTTP: true, MaxConnectionsPerHost: 20, MaxConnections: 64, DialContext: func(context.Context, string, string) (net.Conn, error) { return nil, tt.dial(cancel) }, }) _, err := f.Fetch(ctx, upstreamSource("/image"), "", "") t.Logf("Fetch() error: %v", err) if !errors.Is(err, tt.wantErr) { t.Errorf("Fetch() error = %v, want %v", err, tt.wantErr) } if errors.Is(err, tt.wantNotErr) { t.Errorf("Fetch() error = %v, must not be %v", err, tt.wantNotErr) } }) } }