package mysql

import (
	"context"
	"errors"
	"fmt"
	"testing"
	"time"

	mysqldriver "github.com/go-sql-driver/mysql"
)

func TestIsRetryableGrowthTransactionError(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name string
		err  error
		want bool
	}{
		{name: "deadlock", err: &mysqldriver.MySQLError{Number: 1213, Message: "deadlock"}, want: true},
		{name: "wrapped deadlock", err: fmt.Errorf("consume growth event: %w", &mysqldriver.MySQLError{Number: 1213, Message: "deadlock"}), want: true},
		{name: "lock wait timeout", err: &mysqldriver.MySQLError{Number: 1205, Message: "lock wait timeout"}, want: false},
		{name: "duplicate key", err: &mysqldriver.MySQLError{Number: 1062, Message: "duplicate"}, want: false},
		{name: "text only", err: errors.New("Error 1213: Deadlock found"), want: false},
		{name: "context canceled", err: context.Canceled, want: false},
		{name: "nil", err: nil, want: false},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()
			if got := isRetryableGrowthTransactionError(test.err); got != test.want {
				t.Fatalf("isRetryableGrowthTransactionError()=%v want=%v err=%v", got, test.want, test.err)
			}
		})
	}
}

func TestGrowthTransactionRetryDelayIsBounded(t *testing.T) {
	t.Parallel()

	for attempt := 0; attempt < growthTransactionMaxAttempts-1; attempt++ {
		delay := growthTransactionRetryDelay("growth-event-1", attempt)
		minimum := time.Duration(attempt+1) * growthTransactionRetryStep
		maximum := minimum + growthTransactionRetryJitterWindow
		if delay < minimum || delay > maximum {
			t.Fatalf("attempt %d delay=%s outside [%s,%s]", attempt, delay, minimum, maximum)
		}
	}
}
