package catalogapp

import (
	"context"
	"regexp"
	"strings"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	"github.com/go-sql-driver/mysql"
)

func TestReadReleaseAdmissionConstraintsUsesTiDBConstraintInventory(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	mock.ExpectQuery(regexp.QuoteMeta(tidbReleaseAdmissionConstraintsQuery)).
		WillReturnRows(sqlmock.NewRows([]string{"TABLE_NAME", "CONSTRAINT_NAME", "CHECK_CLAUSE"}).
			AddRow("_System_CatalogAppRelease", releaseAdmissionConstraint, releaseAdmissionCheckExpression).
			AddRow("_System_CatalogAppReleaseSourceReceipt", releaseSourceReceiptConstraint, releaseSourceReceiptCheckExpression))

	found, err := readReleaseAdmissionConstraints(context.Background(), db)
	if err != nil {
		t.Fatal(err)
	}
	if len(found) != 2 {
		t.Fatalf("constraint count = %d, want 2", len(found))
	}
	if found[releaseAdmissionConstraint].tableName != "_System_CatalogAppRelease" {
		t.Fatalf("release constraint = %#v", found[releaseAdmissionConstraint])
	}
	if found[releaseSourceReceiptConstraint].tableName != "_System_CatalogAppReleaseSourceReceipt" {
		t.Fatalf("source constraint = %#v", found[releaseSourceReceiptConstraint])
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}

func TestReadReleaseAdmissionConstraintsFallsBackToStandardInventoryOnMySQL(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	mock.ExpectQuery(regexp.QuoteMeta(tidbReleaseAdmissionConstraintsQuery)).
		WillReturnError(&mysql.MySQLError{Number: 1109, Message: "Unknown table TIDB_CHECK_CONSTRAINTS"})
	mock.ExpectQuery(regexp.QuoteMeta(standardReleaseAdmissionConstraintsQuery)).
		WillReturnRows(sqlmock.NewRows([]string{"TABLE_NAME", "CONSTRAINT_NAME", "CHECK_CLAUSE"}).
			AddRow("_System_CatalogAppRelease", releaseAdmissionConstraint, releaseAdmissionCheckExpression))

	found, err := readReleaseAdmissionConstraints(context.Background(), db)
	if err != nil {
		t.Fatal(err)
	}
	if len(found) != 1 || found[releaseAdmissionConstraint].tableName != "_System_CatalogAppRelease" {
		t.Fatalf("constraints = %#v", found)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}

func TestReadReleaseAdmissionConstraintsFailsClosedOnTiDBInventoryError(t *testing.T) {
	db, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	defer db.Close()

	mock.ExpectQuery(regexp.QuoteMeta(tidbReleaseAdmissionConstraintsQuery)).
		WillReturnError(&mysql.MySQLError{Number: 1142, Message: "SELECT denied"})

	_, err = readReleaseAdmissionConstraints(context.Background(), db)
	if err == nil || !strings.Contains(err.Error(), "inspect TiDB Catalog AppRelease admission constraints") {
		t.Fatalf("error = %v", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}
