package permission

import (
	"context"
	"strings"
	"testing"

	"github.com/tidbcloud/account/commons/database"
	"github.com/tidbcloud/account/internel/dao/entity"
	"github.com/tidbcloud/account/internel/svc/rbac"
	"github.com/tidbcloud/account/pkg/docker_db"
	"gotest.tools/v3/assert"
)

func TestPermissionSvc_parseRbacUri(t *testing.T) {
	reqUri := "/orgs/1/projects/2/dataapps/tidbs/3/get"
	scopeMap, err := parseRbacUri(reqUri, ScopeTypeMapping)
	assert.Assert(t, err == nil)
	assert.Assert(t, len(scopeMap) == 3)
	orgId := scopeMap[entity.RoleBindingScopeOrg]
	assert.Assert(t, orgId == 1)
	pid := scopeMap[entity.RoleBindingScopeProject]
	assert.Assert(t, pid == 2)
	tidbId := scopeMap[entity.RoleBindingScopeTiDB]
	assert.Assert(t, tidbId == 3)
	_, ok := scopeMap[entity.RoleBindingScopeDataAPP]
	assert.Assert(t, ok == false)
}

func TestPermissionSvc_checkIdentityPermission_ReqUriInvalid(t *testing.T) {
	ctx := context.TODO()
	targetType := entity.RoleBindingTargetUser
	var targetId uint64 = 71002
	reqUri := "orgs/1/orgs/1/projects/2/get"
	_, err := checkIdentityPermission(ctx, targetType, targetId, reqUri, "", "test")
	assert.Assert(t, err != nil)
	assert.Assert(t, strings.Contains(err.Error(), "parse access scope error"))
}

func TestPermissionSvc_checkIdentityPermission_ScopeNotMatch(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{})
	if err != nil {
		t.Fatal(err)
	}
	err = db.AutoMigrate(&entity.ResourceRelation{})
	if err != nil {
		t.Fatal(err)
	}
	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})

	reqUri := "orgs/1/projects/5/tidbs/3/get"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, "", "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, !ret.HasPermission)
	assert.Assert(t, strings.Contains(ret.Message, "scope resource not match"))
}

func TestPermissionSvc_checkIdentityPermission_BlackResourceUri_RolesEmpty(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{}, &entity.RoleBinding{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})

	reqUri := "orgs/1/projects/2/users/list"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, "", "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, !ret.HasPermission)
	assert.Assert(t, strings.Contains(ret.Message, "role is null"))
}

func TestPermissionSvc_checkIdentityPermission_BlackResourceUri_PrivNotMatch(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.RoleBinding{
		TargetType: entity.RoleBindingTargetUser,
		TargetID:   entity.ID(71002),
		ScopeType:  entity.RoleBindingScopeOrg,
		ScopeID:    1,
		Role:       entity.RoleOrgOwner,
		RoleID:     30,
		Status:     entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 30}},
		Name:      entity.RoleOrgOwner,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/projects/{project_id}/get",
	})
	db.Save(&entity.RbacRolePrivilege{
		RbacRoleID:      30,
		RbacPrivilegeID: 5,
	})

	reqUri := "orgs/1/projects/2/users/list"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, "", "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, !ret.HasPermission)
	assert.Assert(t, strings.Contains(ret.Message, "relate privileges not hited req_uri"))
}

func TestPermissionSvc_checkIdentityPermission_BlackResourceUri_PrivMatched(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.RoleBinding{
		TargetType: entity.RoleBindingTargetUser,
		TargetID:   entity.ID(71002),
		ScopeType:  entity.RoleBindingScopeOrg,
		ScopeID:    1,
		Role:       entity.RoleOrgOwner,
		RoleID:     30,
		Status:     entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 30}},
		Name:      entity.RoleOrgOwner,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/projects/{project_id}/users/list",
	})
	db.Save(&entity.RbacRolePrivilege{
		RbacRoleID:      30,
		RbacPrivilegeID: 5,
	})
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)

	reqUri := "orgs/1/projects/2/users/list"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, "", "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, ret.HasPermission)
}

func TestPermissionSvc_checkIdentityPermission_BlackResourceUri_Impersonated_PrivNotMatch(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.ImpersonatedUser{
		UserID:   71002,
		TenantID: 1,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 50}},
		Name:      entity.RoleImpersonateOrgOwner,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/projects/{project_id}/get",
	})
	db.Save(&entity.RbacRolePrivilege{
		RbacRoleID:      50,
		RbacPrivilegeID: 5,
	})
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleName2RoleId)

	reqUri := "orgs/1/projects/2/users/list"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, "", "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, !ret.HasPermission)
	assert.Assert(t, strings.Contains(ret.Message, "relate privileges not hited req_uri"))
}

func TestPermissionSvc_checkIdentityPermission_BlackResourceUri_Impersonated_PrivMatched(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.ImpersonatedUser{
		UserID:   71002,
		TenantID: 1,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 51}},
		Name:      entity.RoleImpersonateOrgOwner,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/projects/{project_id}/users/list",
	})
	db.Save(&entity.RbacRolePrivilege{
		RbacRoleID:      51,
		RbacPrivilegeID: 5,
	})
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleName2RoleId)

	reqUri := "orgs/1/projects/2/users/list"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, "", "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, ret.HasPermission)
}

func TestPermissionSvc_checkIdentityPermission_ValidResourceUri_PrivNotAssignRole(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.RoleBinding{
		TargetType: entity.RoleBindingTargetUser,
		TargetID:   entity.ID(71002),
		ScopeType:  entity.RoleBindingScopeOrg,
		ScopeID:    1,
		Role:       entity.RoleOrgOwner,
		RoleID:     30,
		Status:     entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 51}},
		Name:      entity.RoleOrgOwner,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/projects/{project_id}/users/list",
	})
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleName2RoleId)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4ResourceUri2RoleId)

	reqUri := "orgs/1/projects/2/users/list"
	resoruceUri := "orgs/{org_id}/projects/{project_id}/users/list"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, resoruceUri, "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, !ret.HasPermission)
	assert.Assert(t, strings.Contains(ret.Message, "not assigned to any roles"))
}

func TestPermissionSvc_checkIdentityPermission_ValidResourceUri_ScopeNotMatch(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.RoleBinding{
		TargetType: entity.RoleBindingTargetUser,
		TargetID:   entity.ID(71002),
		ScopeType:  entity.RoleBindingScopeOrg,
		ScopeID:    2,
		Role:       entity.RoleOrgOwner,
		RoleID:     51,
		Status:     entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 51}},
		Name:      entity.RoleOrgOwner,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/projects/{project_id}/users/list",
	})
	db.Save(&entity.RbacRolePrivilege{
		RbacRoleID:      51,
		RbacPrivilegeID: 5,
	})

	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleName2RoleId)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4ResourceUri2RoleId)

	reqUri := "orgs/1/projects/2/users/list"
	resoruceUri := "orgs/{org_id}/projects/{project_id}/users/list"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, resoruceUri, "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, !ret.HasPermission)
	assert.Assert(t, strings.Contains(ret.Message, "access scope is not matched assigned scopes"))
}

func TestPermissionSvc_checkIdentityPermission_ValidResourceUri_PrivMatched(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.RoleBinding{
		TargetType: entity.RoleBindingTargetUser,
		TargetID:   entity.ID(71002),
		ScopeType:  entity.RoleBindingScopeOrg,
		ScopeID:    1,
		Role:       entity.RoleOrgOwner,
		RoleID:     51,
		Status:     entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 51}},
		Name:      entity.RoleOrgOwner,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/projects/{project_id}/users/list",
	})
	db.Save(&entity.RbacRolePrivilege{
		RbacRoleID:      51,
		RbacPrivilegeID: 5,
	})

	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleName2RoleId)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4ResourceUri2RoleId)

	reqUri := "orgs/1/projects/2/users/list"
	resoruceUri := "orgs/{org_id}/projects/{project_id}/users/list"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, resoruceUri, "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, ret.HasPermission)
}

func TestPermissionSvc_checkIdentityPermission_ValidResourceUri_OrgScopePrivMatched(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     1,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.RoleBinding{
		TargetType: entity.RoleBindingTargetUser,
		TargetID:   entity.ID(71002),
		ScopeType:  entity.RoleBindingScopeOrg,
		ScopeID:    1,
		Role:       entity.RoleOrgOwner,
		RoleID:     30,
		Status:     entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 30}},
		Name:      entity.RoleOrgOwner,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/tidbs/{tidb_id}/get",
	})
	db.Save(&entity.RbacRolePrivilege{
		RbacRoleID:      30,
		RbacPrivilegeID: 5,
	})

	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleName2RoleId)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4ResourceUri2RoleId)

	reqUri := "orgs/1/tidbs/3/get"
	resoruceUri := "orgs/{org_id}/tidbs/{tidb_id}/get"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, resoruceUri, "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, ret.HasPermission)
}

func TestPermissionSvc_checkIdentityPermission_ValidResourceUri_TiDBScopePrivMatched(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     1,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.RoleBinding{
		TargetType: entity.RoleBindingTargetUser,
		TargetID:   entity.ID(71002),
		ScopeType:  entity.RoleBindingScopeTiDB,
		ScopeID:    3,
		Role:       entity.RoleClusterAdmin,
		RoleID:     50,
		Status:     entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 50}},
		Name:      entity.RoleClusterAdmin,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/tidbs/{tidb_id}/get",
	})
	db.Save(&entity.RbacRolePrivilege{
		RbacRoleID:      50,
		RbacPrivilegeID: 5,
	})

	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleName2RoleId)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4ResourceUri2RoleId)

	reqUri := "orgs/1/tidbs/3/get"
	resoruceUri := "orgs/{org_id}/tidbs/{tidb_id}/get"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, resoruceUri, "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, ret.HasPermission)
}

func TestPermissionSvc_checkIdentityPermission_ValidResourceUri_Impersonatd_PrivMatched(t *testing.T) {
	id, db, err := docker_db.InitDockerGormDB(false)
	if err != nil {
		t.Fatal(err)
	}
	defer docker_db.ReleaseDockerDB(id)

	database.DBConn.DB = db

	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
	if err != nil {
		t.Fatal(err)
	}

	db.Save(&entity.Tenant{
		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
		Email:     "test@pingcap.com",
		Status:    entity.TenantStatusActive,
	})
	db.Save(&entity.Project{
		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
		TenantID:  entity.ID(1),
		Status:    entity.ProjectStatusActive,
	})
	db.Save(&entity.ResourceRelation{
		ParentType:   entity.RoleBindingScopeOrg.String(),
		ParentID:     3,
		ResourceType: entity.RoleBindingScopeTiDB.String(),
		ResourceID:   3,
	})
	db.Save(&entity.ImpersonatedUser{
		UserID:   71002,
		TenantID: 1,
	})
	db.Save(&entity.RbacRole{
		Updatable: entity.Updatable{Base: entity.Base{ID: 51}},
		Name:      entity.RoleImpersonateOrgOwner,
		Status:    entity.RoleBindingStatusActive,
	})
	db.Save(&entity.RbacPrivilege{
		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
		ResourceUri: "orgs/{org_id}/projects/{project_id}/users/list",
	})
	db.Save(&entity.RbacRolePrivilege{
		RbacRoleID:      51,
		RbacPrivilegeID: 5,
	})

	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleName2RoleId)
	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4ResourceUri2RoleId)

	reqUri := "orgs/1/projects/2/users/list"
	resoruceUri := "orgs/{org_id}/projects/{project_id}/users/list"
	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, resoruceUri, "test")
	assert.Assert(t, err == nil)
	assert.Assert(t, ret.HasPermission)
}

//func TestPermissionSvc_checkIdentityPermission_HasPriv_TidbIdMatchedOrgId(t *testing.T) {
//	id, db, err := docker_db.InitDockerGormDB(false)
//	if err != nil {
//		t.Fatal(err)
//	}
//	defer docker_db.ReleaseDockerDB(id)
//
//	database.DBConn.DB = db
//
//	err = db.AutoMigrate(&entity.Project{}, &entity.ResourceRelation{}, &entity.ImpersonatedUser{},
//		&entity.RoleBinding{}, &entity.RbacRole{}, &entity.RbacPrivilege{}, &entity.RbacRolePrivilege{})
//	if err != nil {
//		t.Fatal(err)
//	}
//
//	db.Save(&entity.Tenant{
//		Updatable: entity.Updatable{Base: entity.Base{ID: 1}},
//		Email:     "test@pingcap.com",
//		Status:    entity.TenantStatusActive,
//	})
//	db.Save(&entity.Project{
//		Updatable: entity.Updatable{Base: entity.Base{ID: 2}},
//		TenantID:  entity.ID(1),
//		Status:    entity.ProjectStatusActive,
//	})
//	db.Save(&entity.ResourceRelation{
//		ParentType:   entity.RoleBindingScopeOrg.String(),
//		ParentID:     1,
//		ResourceType: entity.RoleBindingScopeTiDB.String(),
//		ResourceID:   3,
//	})
//	db.Save(&entity.RoleBinding{
//		TargetType: entity.RoleBindingTargetUser,
//		TargetID:   entity.ID(71002),
//		ScopeType:  entity.RoleBindingScopeOrg,
//		ScopeID:    1,
//		Role:       entity.RoleOrgOwner,
//		RoleID:     51,
//		Status:     entity.RoleBindingStatusActive,
//	})
//	db.Save(&entity.RbacRole{
//		Updatable: entity.Updatable{Base: entity.Base{ID: 51}},
//		Name:      entity.RoleProjectOwner,
//		Status:    entity.RoleBindingStatusActive,
//	})
//	db.Save(&entity.RbacPrivilege{
//		Updatable:   entity.Updatable{Base: entity.Base{ID: 5}},
//		ResourceUri: "tidbs/{tidb_id}/get",
//	})
//	db.Save(&entity.RbacRolePrivilege{
//		RbacRoleID:      51,
//		RbacPrivilegeID: 5,
//	})
//
//	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleId2ResourceUri)
//	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4RoleName2RoleId)
//	rbac.LocalCache4RBAC.Delete(rbac.CacheKey4ResourceUri2RoleId)
//
//	reqUri := "tidbs/3/get"
//	resoruceUri := "tidbs/{tidb_id}/get"
//	ret, err := checkIdentityPermission(context.TODO(), entity.RoleBindingTargetUser, 71002, reqUri, resoruceUri, "test")
//	assert.Assert(t, err == nil)
//	assert.Assert(t, ret.HasPermission)
//}
