// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gensupport

import (
	"context"
	"errors"
	"io"
	"net"
	"net/http"
	"testing"
	"time"
)

func TestRetry(t *testing.T) {
	testCases := []struct {
		desc       string
		respStatus []int // HTTP status codes returned (length indicates number of calls we expect).
		maxRetry   int   // Max number of calls allowed by the BackoffStrategy.
		wantStatus int   // StatusCode of returned response.
	}{
		{
			desc:       "First call successful",
			respStatus: []int{200},
			maxRetry:   3,
			wantStatus: 200,
		},
		{
			desc:       "Retry before success",
			respStatus: []int{500, 500, 500, 200},
			maxRetry:   3,
			wantStatus: 200,
		},
		{
			desc:       "Backoff strategy abandons after 3 retries",
			respStatus: []int{500, 500, 500, 500},
			maxRetry:   3,
			wantStatus: 500,
		},
		{
			desc:       "Backoff strategy abandons after 2 retries",
			respStatus: []int{500, 500, 500},
			maxRetry:   2,
			wantStatus: 500,
		},
	}
	for _, tt := range testCases {
		// Function consumes tt.respStatus
		f := func() (*http.Response, error) {
			if len(tt.respStatus) == 0 {
				return nil, errors.New("too many requests to function")
			}
			resp := &http.Response{StatusCode: tt.respStatus[0]}
			tt.respStatus = tt.respStatus[1:]
			return resp, nil
		}

		backoff := &LimitRetryStrategy{
			Max:      tt.maxRetry,
			Strategy: NoPauseStrategy,
		}

		resp, err := Retry(context.Background(), f, backoff)
		if err != nil {
			t.Errorf("%s: Retry returned err %v", tt.desc, err)
		}
		if got := resp.StatusCode; got != tt.wantStatus {
			t.Errorf("%s: Retry returned response with StatusCode=%d; want %d", tt.desc, got, tt.wantStatus)
		}
		if len(tt.respStatus) != 0 {
			t.Errorf("%s: f was not called enough; status codes remaining: %v", tt.desc, tt.respStatus)
		}
	}
}

type checkCloseReader struct {
	closed bool
}

func (c *checkCloseReader) Read(p []byte) (n int, err error) { return 0, io.EOF }
func (c *checkCloseReader) Close() error {
	c.closed = true
	return nil
}

func TestRetryClosesBody(t *testing.T) {
	var i int
	responses := []*http.Response{
		{StatusCode: 500, Body: &checkCloseReader{}},
		{StatusCode: 500, Body: &checkCloseReader{}},
		{StatusCode: 200, Body: &checkCloseReader{}},
	}
	f := func() (*http.Response, error) {
		resp := responses[i]
		i++
		return resp, nil
	}

	resp, err := Retry(context.Background(), f, NoPauseStrategy)
	if err != nil {
		t.Fatalf("Retry returned error: %v", err)
	}
	if resp != responses[2] {
		t.Errorf("Retry returned %v; want %v", resp, responses[2])
	}
	for i, resp := range responses {
		want := i != 2 // Only the last response should not be closed.
		got := resp.Body.(*checkCloseReader).closed
		if got != want {
			t.Errorf("response[%d].Body closed = %t, want %t", i, got, want)
		}
	}
}

func RetryReturnsOnContextCancel(t *testing.T) {
	f := func() (*http.Response, error) {
		return nil, io.ErrUnexpectedEOF
	}
	backoff := UniformPauseStrategy(time.Hour)
	ctx, cancel := context.WithCancel(context.Background())

	errc := make(chan error, 1)
	go func() {
		_, err := Retry(ctx, f, backoff)
		errc <- err
	}()

	cancel()
	select {
	case err := <-errc:
		if err != ctx.Err() {
			t.Errorf("Retry returned err: %v, want %v", err, ctx.Err())
		}
	case <-time.After(5 * time.Second):
		t.Errorf("Timed out waiting for Retry to return")
	}
}

func TestShouldRetry(t *testing.T) {
	testCases := []struct {
		status int
		err    error
		want   bool
	}{
		{status: 200, want: false},
		{status: 308, want: false},
		{status: 403, want: false},
		{status: 429, want: true},
		{status: 500, want: true},
		{status: 503, want: true},
		{status: 600, want: false},
		{err: io.EOF, want: false},
		{err: errors.New("random badness"), want: false},
		{err: io.ErrUnexpectedEOF, want: true},
		{err: &net.AddrError{}, want: false},              // Not temporary.
		{err: &net.DNSError{IsTimeout: true}, want: true}, // Temporary.
	}
	for _, tt := range testCases {
		if got := shouldRetry(tt.status, tt.err); got != tt.want {
			t.Errorf("shouldRetry(%d, %v) = %t; want %t", tt.status, tt.err, got, tt.want)
		}
	}
}
