diff --git a/api/dms/service/v1/db_service_password_test.go b/api/dms/service/v1/db_service_password_test.go new file mode 100644 index 00000000..b9912386 --- /dev/null +++ b/api/dms/service/v1/db_service_password_test.go @@ -0,0 +1,73 @@ +package v1 + +import ( + "strings" + "testing" + + utilConf "github.com/actiontech/dms/pkg/dms-common/pkg/config" +) + +func TestAddDBServiceReq_EmptyPasswordRejected(t *testing.T) { + t.Parallel() + + base := func(password string) *AddDBServiceReq { + return &AddDBServiceReq{ + ProjectUid: "700300", + DBService: &DBService{ + Name: "gbase8a_empty_pwd", + DBType: "GBase-8a", + Host: "10.186.16.126", + Port: "5258", + User: "root", + Password: password, + Business: "default", + MaintenanceTimes: nil, + }, + } + } + + t.Run("password_empty_string", func(t *testing.T) { + t.Parallel() + err := utilConf.Validate(base("")) + if err == nil { + t.Fatal("expected empty password to fail Add validation") + } + msg := strings.ToLower(err.Error()) + if !strings.Contains(msg, "password") || !strings.Contains(msg, "required") { + t.Fatalf("expected Password required validation error, got: %v", err) + } + }) + + t.Run("password_non_empty_passes_password_rule", func(t *testing.T) { + t.Parallel() + if err := utilConf.Validate(base("not-empty")); err != nil { + t.Fatalf("expected non-empty password to pass Add validation, got: %v", err) + } + }) +} + +func TestAddDBServiceReq_MissingHostStillRequired(t *testing.T) { + t.Parallel() + + req := &AddDBServiceReq{ + ProjectUid: "700300", + DBService: &DBService{ + Name: "gbase8a_missing_host", + DBType: "GBase-8a", + Host: "", + Port: "5258", + User: "root", + Password: "not-empty", + Business: "default", + }, + } + + err := utilConf.Validate(req) + if err == nil { + t.Fatal("expected missing Host to fail validation") + } + msg := err.Error() + if !strings.Contains(msg, "Host") || !strings.Contains(msg, "required") { + t.Fatalf("expected Host required validation error, got: %v", err) + } +} diff --git a/api/dms/service/v2/db_service_password_test.go b/api/dms/service/v2/db_service_password_test.go new file mode 100644 index 00000000..a21b2359 --- /dev/null +++ b/api/dms/service/v2/db_service_password_test.go @@ -0,0 +1,73 @@ +package v2 + +import ( + "strings" + "testing" + + utilConf "github.com/actiontech/dms/pkg/dms-common/pkg/config" +) + +func TestAddDBServiceReq_EmptyPasswordRejected(t *testing.T) { + t.Parallel() + + base := func(password string) *AddDBServiceReq { + return &AddDBServiceReq{ + ProjectUid: "700300", + DBService: &DBService{ + Name: "gbase8a_empty_pwd", + DBType: "GBase-8a", + Host: "10.186.16.126", + Port: "5258", + User: "root", + Password: password, + EnvironmentTagUID: "2086752861772845056", + MaintenanceTimes: nil, + }, + } + } + + t.Run("password_empty_string", func(t *testing.T) { + t.Parallel() + err := utilConf.Validate(base("")) + if err == nil { + t.Fatal("expected empty password to fail Add validation") + } + msg := strings.ToLower(err.Error()) + if !strings.Contains(msg, "password") || !strings.Contains(msg, "required") { + t.Fatalf("expected Password required validation error, got: %v", err) + } + }) + + t.Run("password_non_empty_passes_password_rule", func(t *testing.T) { + t.Parallel() + if err := utilConf.Validate(base("not-empty")); err != nil { + t.Fatalf("expected non-empty password to pass Add validation, got: %v", err) + } + }) +} + +func TestAddDBServiceReq_MissingHostStillRequired(t *testing.T) { + t.Parallel() + + req := &AddDBServiceReq{ + ProjectUid: "700300", + DBService: &DBService{ + Name: "gbase8a_missing_host", + DBType: "GBase-8a", + Host: "", + Port: "5258", + User: "root", + Password: "not-empty", + EnvironmentTagUID: "2086752861772845056", + }, + } + + err := utilConf.Validate(req) + if err == nil { + t.Fatal("expected missing Host to fail validation") + } + msg := err.Error() + if !strings.Contains(msg, "Host") || !strings.Contains(msg, "required") { + t.Fatalf("expected Host required validation error, got: %v", err) + } +} diff --git a/internal/dms/biz/db_service_password_test.go b/internal/dms/biz/db_service_password_test.go new file mode 100644 index 00000000..6e76fd92 --- /dev/null +++ b/internal/dms/biz/db_service_password_test.go @@ -0,0 +1,181 @@ +package biz + +import ( + "context" + "io" + "strings" + "testing" + + pkgConst "github.com/actiontech/dms/internal/dms/pkg/constant" + utilLog "github.com/actiontech/dms/pkg/dms-common/pkg/log" +) + +type fakeDBServiceRepoForPassword struct { + svc *DBService + updated *DBService +} + +func (f *fakeDBServiceRepoForPassword) SaveDBServices(context.Context, []*DBService) error { + return nil +} +func (f *fakeDBServiceRepoForPassword) GetDBServicesByIds(context.Context, []string) ([]*DBService, error) { + return nil, nil +} +func (f *fakeDBServiceRepoForPassword) ListDBServices(context.Context, *ListDBServicesOption) ([]*DBService, int64, error) { + return nil, 0, nil +} +func (f *fakeDBServiceRepoForPassword) DelDBService(context.Context, string) error { return nil } +func (f *fakeDBServiceRepoForPassword) GetDBService(_ context.Context, _ string) (*DBService, error) { + return f.svc, nil +} +func (f *fakeDBServiceRepoForPassword) GetDBServices(context.Context, []pkgConst.FilterCondition) ([]*DBService, error) { + return nil, nil +} +func (f *fakeDBServiceRepoForPassword) CheckDBServiceExist(context.Context, []string) (bool, error) { + return true, nil +} +func (f *fakeDBServiceRepoForPassword) UpdateDBService(_ context.Context, dbService *DBService) error { + f.updated = dbService + return nil +} +func (f *fakeDBServiceRepoForPassword) CountDBService(context.Context) ([]DBTypeCount, error) { + return nil, nil +} +func (f *fakeDBServiceRepoForPassword) GetBusinessByProjectUID(context.Context, string) ([]string, error) { + return nil, nil +} +func (f *fakeDBServiceRepoForPassword) GetFieldDistinctValue(context.Context, DBServiceField, interface{}) error { + return nil +} + +type fakeProjectRepoForPassword struct { + project *Project +} + +func (f *fakeProjectRepoForPassword) SaveProject(context.Context, *Project) error { return nil } +func (f *fakeProjectRepoForPassword) BatchSaveProjects(context.Context, []*Project) error { + return nil +} +func (f *fakeProjectRepoForPassword) ListProjects(context.Context, *ListProjectsOption, string) ([]*Project, int64, error) { + return nil, 0, nil +} +func (f *fakeProjectRepoForPassword) GetProject(context.Context, string) (*Project, error) { + return f.project, nil +} +func (f *fakeProjectRepoForPassword) GetProjectByName(context.Context, string) (*Project, error) { + return f.project, nil +} +func (f *fakeProjectRepoForPassword) GetProjectByNames(context.Context, []string) ([]*Project, error) { + return []*Project{f.project}, nil +} +func (f *fakeProjectRepoForPassword) UpdateProject(context.Context, *Project) error { return nil } +func (f *fakeProjectRepoForPassword) DelProject(context.Context, string) error { return nil } +func (f *fakeProjectRepoForPassword) UpdateDBServiceBusiness(context.Context, string, string, string) error { + return nil +} + +type fakeEnvTagRepoForPassword struct { + tag *EnvironmentTag +} + +func (f *fakeEnvTagRepoForPassword) CreateEnvironmentTag(context.Context, *EnvironmentTag) error { + return nil +} +func (f *fakeEnvTagRepoForPassword) UpdateEnvironmentTag(context.Context, string, string, string) error { + return nil +} +func (f *fakeEnvTagRepoForPassword) DeleteEnvironmentTag(context.Context, string) error { return nil } +func (f *fakeEnvTagRepoForPassword) GetEnvironmentTagByName(context.Context, string, string) (bool, *EnvironmentTag, error) { + return true, f.tag, nil +} +func (f *fakeEnvTagRepoForPassword) GetEnvironmentTagByUID(context.Context, string) (*EnvironmentTag, error) { + return f.tag, nil +} +func (f *fakeEnvTagRepoForPassword) ListEnvironmentTags(context.Context, *ListEnvironmentTagsOption) ([]*EnvironmentTag, int64, error) { + return nil, 0, nil +} + +func newDBServiceUsecaseForEmptyPasswordTest(repo *fakeDBServiceRepoForPassword) *DBServiceUsecase { + logger := utilLog.NewMyLogger(io.Discard) + projectRepo := &fakeProjectRepoForPassword{ + project: &Project{UID: "700300", Status: ProjectStatusActive}, + } + projectUC := &ProjectUsecase{ + repo: projectRepo, + log: utilLog.NewHelper(logger, utilLog.WithMessageKey("biz.project.test")), + } + opUC := NewOpPermissionVerifyUsecase(logger, nil, &mockOpPermissionVerifyRepo{}, &mockUserRepo{users: map[string]*User{}}) + envUC := &EnvironmentTagUsecase{ + environmentTagRepo: &fakeEnvTagRepoForPassword{ + tag: &EnvironmentTag{UID: "env-1", Name: "prod"}, + }, + log: utilLog.NewHelper(logger, utilLog.WithMessageKey("biz.env.test")), + } + pluginUC := &PluginUsecase{registeredPlugins: nil} + return NewDBServiceUsecase(logger, repo, nil, pluginUC, opUC, projectUC, nil, envUC) +} + +func TestUpdateDBServiceByArgs_EmptyPasswordRejected(t *testing.T) { + repo := &fakeDBServiceRepoForPassword{ + svc: &DBService{ + UID: "ds-1", + Name: "gbase8a", + DBType: "GBase-8a", + Host: "10.186.16.126", + Port: "5258", + User: "root", + Password: "old-secret", + ProjectUID: "700300", + }, + } + uc := newDBServiceUsecaseForEmptyPasswordTest(repo) + empty := "" + err := uc.UpdateDBServiceByArgs(context.Background(), "ds-1", &BizDBServiceArgs{ + DBType: "GBase-8a", + Host: "10.186.16.126", + Port: "5258", + User: "root", + Password: &empty, + EnvironmentTagUID: "env-1", + }, pkgConst.UIDOfUserAdmin) + if err == nil { + t.Fatal("expected Update with password=\"\" to fail") + } + if !strings.Contains(err.Error(), "password can't be empty") { + t.Fatalf("expected \"password can't be empty\", got: %v", err) + } + if repo.updated != nil { + t.Fatal("expected UpdateDBService not to be called when password is empty") + } +} + +func TestUpdateDBServiceByArgs_MissingHostStillRejected(t *testing.T) { + repo := &fakeDBServiceRepoForPassword{ + svc: &DBService{ + UID: "ds-1", + Name: "gbase8a", + DBType: "GBase-8a", + Host: "10.186.16.126", + Port: "5258", + User: "root", + Password: "old-secret", + ProjectUID: "700300", + }, + } + uc := newDBServiceUsecaseForEmptyPasswordTest(repo) + pwd := "not-empty" + err := uc.UpdateDBServiceByArgs(context.Background(), "ds-1", &BizDBServiceArgs{ + DBType: "GBase-8a", + Host: "", + Port: "5258", + User: "root", + Password: &pwd, + EnvironmentTagUID: "env-1", + }, pkgConst.UIDOfUserAdmin) + if err == nil { + t.Fatal("expected missing Host to fail Update") + } + if !strings.Contains(err.Error(), "host") { + t.Fatalf("expected host-related error, got: %v", err) + } +}