mirror of
https://github.com/goharbor/harbor.git
synced 2025-03-09 21:19:04 +01:00
Add dao and manager for audit log ext (#21379)
Signed-off-by: stonezdj <stone.zhang@broadcom.com>
This commit is contained in:
parent
cc6ace188d
commit
60798a49b3
@ -462,6 +462,16 @@ packages:
|
||||
DAO:
|
||||
config:
|
||||
dir: testing/pkg/audit/dao
|
||||
github.com/goharbor/harbor/src/pkg/auditext:
|
||||
interfaces:
|
||||
Manager:
|
||||
config:
|
||||
dir: testing/pkg/auditext
|
||||
github.com/goharbor/harbor/src/pkg/auditext/dao:
|
||||
interfaces:
|
||||
DAO:
|
||||
config:
|
||||
dir: testing/pkg/auditext/dao
|
||||
github.com/goharbor/harbor/src/pkg/systemartifact:
|
||||
interfaces:
|
||||
Manager:
|
||||
|
@ -337,3 +337,13 @@ func MostMatchSorter(a, b string, matchWord string) bool {
|
||||
func IsLocalPath(path string) bool {
|
||||
return len(path) == 0 || (strings.HasPrefix(path, "/") && !strings.HasPrefix(path, "//"))
|
||||
}
|
||||
|
||||
// StringInSlice check if the string is in the slice
|
||||
func StringInSlice(str string, slice []string) bool {
|
||||
for _, s := range slice {
|
||||
if s == str {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/pkg/audit"
|
||||
"github.com/goharbor/harbor/src/pkg/auditext"
|
||||
"github.com/goharbor/harbor/src/pkg/user"
|
||||
)
|
||||
|
||||
@ -27,6 +28,7 @@ const UserNameParam = "username"
|
||||
|
||||
type AuditLogsDataMasking struct {
|
||||
manager audit.Manager
|
||||
extManager auditext.Manager
|
||||
userManager user.Manager
|
||||
}
|
||||
|
||||
@ -58,6 +60,9 @@ func (a *AuditLogsDataMasking) init() {
|
||||
if a.userManager == nil {
|
||||
a.userManager = user.New()
|
||||
}
|
||||
if a.extManager == nil {
|
||||
a.extManager = auditext.Mgr
|
||||
}
|
||||
}
|
||||
|
||||
func (a AuditLogsDataMasking) Run(ctx job.Context, params job.Parameters) error {
|
||||
@ -69,7 +74,11 @@ func (a AuditLogsDataMasking) Run(ctx job.Context, params job.Parameters) error
|
||||
return err
|
||||
}
|
||||
logger.Infof("Masking log entries for a user: %s", username)
|
||||
return a.manager.UpdateUsername(ctx.SystemContext(), username, a.userManager.GenerateCheckSum(username))
|
||||
err = a.manager.UpdateUsername(ctx.SystemContext(), username, a.userManager.GenerateCheckSum(username))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return a.extManager.UpdateUsername(ctx.SystemContext(), username, a.userManager.GenerateCheckSum(username))
|
||||
}
|
||||
|
||||
func (a AuditLogsDataMasking) parseParams(params job.Parameters) (string, error) {
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/goharbor/harbor/src/jobservice/job"
|
||||
mockjobservice "github.com/goharbor/harbor/src/testing/jobservice"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/audit"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/auditext"
|
||||
"github.com/goharbor/harbor/src/testing/pkg/user"
|
||||
)
|
||||
|
||||
@ -35,12 +36,14 @@ func TestAuditLogsCleanupJobValidateParams(t *testing.T) {
|
||||
const validUsername = "user"
|
||||
var (
|
||||
manager = &audit.Manager{}
|
||||
extManger = &auditext.Manager{}
|
||||
userManager = &user.Manager{}
|
||||
)
|
||||
|
||||
rep := &AuditLogsDataMasking{
|
||||
manager: manager,
|
||||
userManager: userManager,
|
||||
extManager: extManger,
|
||||
}
|
||||
err := rep.Validate(nil)
|
||||
// parameters are required
|
||||
@ -61,6 +64,7 @@ func TestAuditLogsCleanupJobValidateParams(t *testing.T) {
|
||||
ctx.On("GetLogger").Return(logger)
|
||||
userManager.On("GenerateCheckSum", validUsername).Return("hash")
|
||||
manager.On("UpdateUsername", context.TODO(), validUsername, "hash").Return(nil)
|
||||
extManger.On("UpdateUsername", context.TODO(), validUsername, "hash").Return(nil)
|
||||
|
||||
err = rep.Run(ctx, validParams)
|
||||
assert.Nil(t, err)
|
||||
|
205
src/pkg/auditext/dao/dao.go
Normal file
205
src/pkg/auditext/dao/dao.go
Normal file
@ -0,0 +1,205 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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 dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
beegorm "github.com/beego/beego/v2/client/orm"
|
||||
|
||||
"github.com/goharbor/harbor/src/common/utils"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/log"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/auditext/model"
|
||||
)
|
||||
|
||||
// DAO is the data access object for audit log
|
||||
type DAO interface {
|
||||
// Create the audit log ext
|
||||
Create(ctx context.Context, access *model.AuditLogExt) (id int64, err error)
|
||||
// Count returns the total count of audit log ext according to the query
|
||||
Count(ctx context.Context, query *q.Query) (total int64, err error)
|
||||
// List audit log ext according to the query
|
||||
List(ctx context.Context, query *q.Query) (access []*model.AuditLogExt, err error)
|
||||
// Get the audit log ext specified by ID
|
||||
Get(ctx context.Context, id int64) (access *model.AuditLogExt, err error)
|
||||
// Delete the audit log ext specified by ID
|
||||
Delete(ctx context.Context, id int64) (err error)
|
||||
// Purge the audit log ext
|
||||
Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error)
|
||||
// UpdateUsername replaces username in matched records
|
||||
UpdateUsername(ctx context.Context, username string, usernameReplace string) error
|
||||
}
|
||||
|
||||
// New returns an instance of the default DAO
|
||||
func New() DAO {
|
||||
return &dao{}
|
||||
}
|
||||
|
||||
type dao struct{}
|
||||
|
||||
func (d *dao) UpdateUsername(ctx context.Context, username string, usernameReplace string) error {
|
||||
o, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = o.Raw("UPDATE audit_log_ext SET username = ? WHERE username = ?", usernameReplace, username).Exec()
|
||||
return err
|
||||
}
|
||||
|
||||
// Count ...
|
||||
func (d *dao) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
qs, err := orm.QuerySetterForCount(ctx, &model.AuditLogExt{}, query)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return qs.Count()
|
||||
}
|
||||
|
||||
// List ...
|
||||
func (d *dao) List(ctx context.Context, query *q.Query) ([]*model.AuditLogExt, error) {
|
||||
audit := []*model.AuditLogExt{}
|
||||
qs, err := orm.QuerySetter(ctx, &model.AuditLogExt{}, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err = qs.All(&audit); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return audit, nil
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (d *dao) Get(ctx context.Context, id int64) (*model.AuditLogExt, error) {
|
||||
audit := &model.AuditLogExt{
|
||||
ID: id,
|
||||
}
|
||||
ormer, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := ormer.Read(audit); err != nil {
|
||||
if e := orm.AsNotFoundError(err, "audit %d not found", id); e != nil {
|
||||
err = e
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return audit, nil
|
||||
}
|
||||
|
||||
// Create ...
|
||||
func (d *dao) Create(ctx context.Context, audit *model.AuditLogExt) (int64, error) {
|
||||
ormer, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// the max length of username in database is 255, replace the last
|
||||
// three charaters with "..." if the length is greater than 256
|
||||
if len(audit.Username) > 255 {
|
||||
audit.Username = audit.Username[:252] + "..."
|
||||
}
|
||||
id, err := ormer.Insert(audit)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return id, err
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (d *dao) Delete(ctx context.Context, id int64) error {
|
||||
ormer, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n, err := ormer.Delete(&model.AuditLogExt{
|
||||
ID: id,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n == 0 {
|
||||
return errors.NotFoundError(nil).WithMessagef("access %d not found", id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Purge delete expired audit log ext
|
||||
func (*dao) Purge(ctx context.Context, retentionHour int, includeEventTypes []string, dryRun bool) (int64, error) {
|
||||
ormer, err := orm.FromContext(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if dryRun {
|
||||
return dryRunPurge(ormer, retentionHour, includeEventTypes)
|
||||
}
|
||||
filterEvents := permitEventTypes(includeEventTypes)
|
||||
if len(filterEvents) == 0 {
|
||||
log.Infof("no operation selected, skip to purge audit log")
|
||||
return 0, nil
|
||||
}
|
||||
sql := "DELETE FROM audit_log_ext WHERE op_time < NOW() - ? * interval '1 hour' AND lower(operation || '_' || resource_type) IN ('" + strings.Join(filterEvents, "','") + "')"
|
||||
log.Debugf("purge audit logs raw sql: %v", sql)
|
||||
|
||||
r, err := ormer.Raw(sql, retentionHour).Exec()
|
||||
if err != nil {
|
||||
log.Errorf("failed to purge audit log, error %v", err)
|
||||
return 0, err
|
||||
}
|
||||
delRows, rErr := r.RowsAffected()
|
||||
if rErr != nil {
|
||||
log.Errorf("failed to purge audit log, error %v", rErr)
|
||||
return 0, rErr
|
||||
}
|
||||
log.Infof("purged %d audit logs in the database", delRows)
|
||||
|
||||
return delRows, err
|
||||
}
|
||||
|
||||
func dryRunPurge(ormer beegorm.QueryExecutor, retentionHour int, includeEventTypes []string) (int64, error) {
|
||||
filterEvents := permitEventTypes(includeEventTypes)
|
||||
if len(filterEvents) == 0 {
|
||||
log.Infof("[DRYRUN]no operation selected, skip to purge audit log")
|
||||
return 0, nil
|
||||
}
|
||||
sql := "SELECT count(1) cnt FROM audit_log_ext WHERE op_time < NOW() - ? * interval '1 hour' AND lower(operation || '_' || resource_type) IN ('" + strings.Join(filterEvents, "','") + "')"
|
||||
log.Debugf("purge audit log count raw sql: %v", sql)
|
||||
|
||||
var cnt int64
|
||||
err := ormer.Raw(sql, retentionHour).QueryRow(&cnt)
|
||||
if err != nil {
|
||||
log.Errorf("failed to dry run purge audit log, error %v", err)
|
||||
return 0, err
|
||||
}
|
||||
log.Infof("[DRYRUN]purged %d audit logs in the database", cnt)
|
||||
return cnt, nil
|
||||
}
|
||||
|
||||
// permitEventTypes filter not allowed event type, if no event types specified, purge no operation, use this function to avoid SQL injection
|
||||
func permitEventTypes(includeEventTypes []string) []string {
|
||||
if includeEventTypes == nil {
|
||||
return nil
|
||||
}
|
||||
var filterEvents []string
|
||||
for _, e := range includeEventTypes {
|
||||
event := strings.ToLower(e)
|
||||
if utils.StringInSlice(event, model.EventTypes) {
|
||||
filterEvents = append(filterEvents, e)
|
||||
}
|
||||
}
|
||||
return filterEvents
|
||||
}
|
188
src/pkg/auditext/dao/dao_test.go
Normal file
188
src/pkg/auditext/dao/dao_test.go
Normal file
@ -0,0 +1,188 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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 dao
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
beegoorm "github.com/beego/beego/v2/client/orm"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
common_dao "github.com/goharbor/harbor/src/common/dao"
|
||||
"github.com/goharbor/harbor/src/lib/errors"
|
||||
"github.com/goharbor/harbor/src/lib/orm"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
"github.com/goharbor/harbor/src/pkg/auditext/model"
|
||||
)
|
||||
|
||||
type daoTestSuite struct {
|
||||
suite.Suite
|
||||
dao DAO
|
||||
auditID int64
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (d *daoTestSuite) SetupSuite() {
|
||||
d.dao = New()
|
||||
common_dao.PrepareTestForPostgresSQL()
|
||||
d.ctx = orm.NewContext(nil, beegoorm.NewOrm())
|
||||
artifactID, err := d.dao.Create(d.ctx, &model.AuditLogExt{
|
||||
Operation: "Create",
|
||||
ResourceType: "user",
|
||||
Resource: "user01",
|
||||
Username: "admin",
|
||||
OperationDescription: "Create user",
|
||||
OperationResult: true,
|
||||
OpTime: time.Now().AddDate(0, 0, -8),
|
||||
})
|
||||
d.Require().Nil(err)
|
||||
d.auditID = artifactID
|
||||
}
|
||||
|
||||
func (d *daoTestSuite) TearDownSuite() {
|
||||
ormer, err := orm.FromContext(d.ctx)
|
||||
d.Require().Nil(err)
|
||||
_, err = ormer.Raw("delete from audit_log_ext").Exec()
|
||||
d.Require().Nil(err)
|
||||
|
||||
}
|
||||
|
||||
func (d *daoTestSuite) TestList() {
|
||||
// nil query
|
||||
audits, err := d.dao.List(d.ctx, nil)
|
||||
d.Require().Nil(err)
|
||||
|
||||
// query by repository ID and name
|
||||
audits, err = d.dao.List(d.ctx, &q.Query{
|
||||
Keywords: map[string]interface{}{
|
||||
"Resource": "user01",
|
||||
},
|
||||
})
|
||||
d.Require().Nil(err)
|
||||
d.Require().Equal(1, len(audits))
|
||||
d.Equal("admin", audits[0].Username)
|
||||
}
|
||||
|
||||
func (d *daoTestSuite) TestGet() {
|
||||
// get the non-exist tag
|
||||
_, err := d.dao.Get(d.ctx, 10000)
|
||||
d.Require().NotNil(err)
|
||||
d.True(errors.IsErr(err, errors.NotFoundCode))
|
||||
|
||||
audit, err := d.dao.Get(d.ctx, d.auditID)
|
||||
d.Require().Nil(err)
|
||||
d.Require().NotNil(audit)
|
||||
d.Equal(d.auditID, audit.ID)
|
||||
}
|
||||
|
||||
func (d *daoTestSuite) TestCount() {
|
||||
total, err := d.dao.Count(d.ctx, nil)
|
||||
d.Require().Nil(err)
|
||||
d.True(total > 0)
|
||||
total, err = d.dao.Count(d.ctx, &q.Query{
|
||||
Keywords: map[string]interface{}{
|
||||
"Resource": "user01",
|
||||
},
|
||||
})
|
||||
d.Require().Nil(err)
|
||||
d.Equal(int64(1), total)
|
||||
}
|
||||
|
||||
func (d *daoTestSuite) TestListPIDs() {
|
||||
// get the non-exist tag
|
||||
id1, err := d.dao.Create(d.ctx, &model.AuditLogExt{
|
||||
Operation: "create",
|
||||
ResourceType: "artifact",
|
||||
Resource: "library/hello-world",
|
||||
Username: "admin",
|
||||
ProjectID: 11,
|
||||
})
|
||||
d.Require().Nil(err)
|
||||
id2, err := d.dao.Create(d.ctx, &model.AuditLogExt{
|
||||
Operation: "create",
|
||||
ResourceType: "artifact",
|
||||
Resource: "library/hello-world",
|
||||
Username: "admin",
|
||||
ProjectID: 12,
|
||||
})
|
||||
d.Require().Nil(err)
|
||||
id3, err := d.dao.Create(d.ctx, &model.AuditLogExt{
|
||||
Operation: "delete",
|
||||
ResourceType: "artifact",
|
||||
Resource: "library/hello-world",
|
||||
Username: "admin",
|
||||
ProjectID: 13,
|
||||
})
|
||||
d.Require().Nil(err)
|
||||
|
||||
// query by repository ID and name
|
||||
ol := &q.OrList{}
|
||||
for _, item := range []int64{11, 12, 13} {
|
||||
ol.Values = append(ol.Values, item)
|
||||
}
|
||||
audits, err := d.dao.List(d.ctx, &q.Query{
|
||||
Keywords: map[string]interface{}{
|
||||
"ProjectID": ol,
|
||||
},
|
||||
})
|
||||
d.Require().Nil(err)
|
||||
d.Require().Equal(3, len(audits))
|
||||
d.dao.Delete(d.ctx, id1)
|
||||
d.dao.Delete(d.ctx, id2)
|
||||
d.dao.Delete(d.ctx, id3)
|
||||
}
|
||||
|
||||
func (d *daoTestSuite) TestCreate() {
|
||||
audit := &model.AuditLogExt{
|
||||
Operation: "create",
|
||||
ResourceType: "user",
|
||||
Resource: "user02",
|
||||
OperationResult: true,
|
||||
Username: "admin",
|
||||
}
|
||||
_, err := d.dao.Create(d.ctx, audit)
|
||||
d.Require().Nil(err)
|
||||
}
|
||||
|
||||
func (d *daoTestSuite) TestPurge() {
|
||||
// try to purge the audit log ext with the time range of 30 days, false
|
||||
result, err := d.dao.Purge(d.ctx, 24*30, []string{"create_user"}, true)
|
||||
d.Require().Nil(err)
|
||||
d.Require().Equal(int64(0), result)
|
||||
// try to purge the audit log ext with the time range of 7 days, true
|
||||
result1, err := d.dao.Purge(d.ctx, 24*7, []string{"create_user"}, true)
|
||||
d.Require().Nil(err)
|
||||
d.Require().Equal(int64(1), result1)
|
||||
|
||||
}
|
||||
|
||||
func TestDaoTestSuite(t *testing.T) {
|
||||
suite.Run(t, &daoTestSuite{})
|
||||
}
|
||||
|
||||
func TestPermitEventTypes(t *testing.T) {
|
||||
// test permit event types
|
||||
eventTypes := permitEventTypes([]string{"create_user", "delete_user", "delete_anything"})
|
||||
if len(eventTypes) != 2 {
|
||||
t.Errorf("permitEventTypes failed")
|
||||
}
|
||||
eventTypes2 := permitEventTypes([]string{})
|
||||
if len(eventTypes2) != 0 {
|
||||
t.Errorf("permitEventTypes failed")
|
||||
}
|
||||
|
||||
}
|
99
src/pkg/auditext/manager.go
Normal file
99
src/pkg/auditext/manager.go
Normal file
@ -0,0 +1,99 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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 auditext
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/goharbor/harbor/src/lib/config"
|
||||
"github.com/goharbor/harbor/src/lib/q"
|
||||
auditV1 "github.com/goharbor/harbor/src/pkg/audit"
|
||||
"github.com/goharbor/harbor/src/pkg/auditext/dao"
|
||||
"github.com/goharbor/harbor/src/pkg/auditext/model"
|
||||
)
|
||||
|
||||
// Mgr is the global audit log manager instance
|
||||
var Mgr = New()
|
||||
|
||||
// Manager is used for audit log management
|
||||
type Manager interface {
|
||||
// Count returns the total count of audit logs according to the query
|
||||
Count(ctx context.Context, query *q.Query) (total int64, err error)
|
||||
// List audit logs according to the query
|
||||
List(ctx context.Context, query *q.Query) (audits []*model.AuditLogExt, err error)
|
||||
// Get the audit log specified by ID
|
||||
Get(ctx context.Context, id int64) (audit *model.AuditLogExt, err error)
|
||||
// Create the audit log
|
||||
Create(ctx context.Context, audit *model.AuditLogExt) (id int64, err error)
|
||||
// Delete the audit log specified by ID
|
||||
Delete(ctx context.Context, id int64) (err error)
|
||||
// Purge delete the audit log with retention hours
|
||||
Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error)
|
||||
// UpdateUsername Replace all log records username with its hash
|
||||
UpdateUsername(ctx context.Context, username string, replaceWith string) error
|
||||
}
|
||||
|
||||
// New returns a default implementation of Manager
|
||||
func New() Manager {
|
||||
return &manager{
|
||||
dao: dao.New(),
|
||||
}
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
dao dao.DAO
|
||||
}
|
||||
|
||||
func (m *manager) UpdateUsername(ctx context.Context, username string, replaceWith string) error {
|
||||
return m.dao.UpdateUsername(ctx, username, replaceWith)
|
||||
}
|
||||
|
||||
// Count ...
|
||||
func (m *manager) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
return m.dao.Count(ctx, query)
|
||||
}
|
||||
|
||||
// List ...
|
||||
func (m *manager) List(ctx context.Context, query *q.Query) ([]*model.AuditLogExt, error) {
|
||||
return m.dao.List(ctx, query)
|
||||
}
|
||||
|
||||
// Get ...
|
||||
func (m *manager) Get(ctx context.Context, id int64) (*model.AuditLogExt, error) {
|
||||
return m.dao.Get(ctx, id)
|
||||
}
|
||||
|
||||
// Create ...
|
||||
func (m *manager) Create(ctx context.Context, audit *model.AuditLogExt) (int64, error) {
|
||||
if len(config.AuditLogForwardEndpoint(ctx)) > 0 {
|
||||
auditV1.LogMgr.DefaultLogger(ctx).WithField("operator", audit.Username).
|
||||
WithField("time", audit.OpTime).WithField("resourceType", audit.ResourceType).
|
||||
Infof("action:%s, resource:%s", audit.Operation, audit.Resource)
|
||||
}
|
||||
if config.SkipAuditLogDatabase(ctx) {
|
||||
return 0, nil
|
||||
}
|
||||
return m.dao.Create(ctx, audit)
|
||||
}
|
||||
|
||||
// Purge ...
|
||||
func (m *manager) Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error) {
|
||||
return m.dao.Purge(ctx, retentionHour, includeOperations, dryRun)
|
||||
}
|
||||
|
||||
// Delete ...
|
||||
func (m *manager) Delete(ctx context.Context, id int64) error {
|
||||
return m.dao.Delete(ctx, id)
|
||||
}
|
104
src/pkg/auditext/manager_test.go
Normal file
104
src/pkg/auditext/manager_test.go
Normal file
@ -0,0 +1,104 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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 auditext
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
"github.com/goharbor/harbor/src/pkg/auditext/model"
|
||||
_ "github.com/goharbor/harbor/src/pkg/config/db"
|
||||
mockDAO "github.com/goharbor/harbor/src/testing/pkg/auditext/dao"
|
||||
)
|
||||
|
||||
type managerTestSuite struct {
|
||||
suite.Suite
|
||||
mgr *manager
|
||||
dao *mockDAO.DAO
|
||||
}
|
||||
|
||||
func (m *managerTestSuite) SetupTest() {
|
||||
m.dao = &mockDAO.DAO{}
|
||||
m.mgr = &manager{
|
||||
dao: m.dao,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *managerTestSuite) TestCount() {
|
||||
m.dao.On("Count", mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
total, err := m.mgr.Count(nil, nil)
|
||||
m.Require().Nil(err)
|
||||
m.Equal(int64(1), total)
|
||||
}
|
||||
|
||||
func (m *managerTestSuite) TestList() {
|
||||
audit := &model.AuditLogExt{
|
||||
ProjectID: 1,
|
||||
Resource: "library/hello-world",
|
||||
ResourceType: "artifact",
|
||||
}
|
||||
m.dao.On("List", mock.Anything, mock.Anything).Return([]*model.AuditLogExt{audit}, nil)
|
||||
auditLogs, err := m.mgr.List(nil, nil)
|
||||
m.Require().Nil(err)
|
||||
m.Equal(1, len(auditLogs))
|
||||
m.Equal(audit.Resource, auditLogs[0].Resource)
|
||||
}
|
||||
|
||||
func (m *managerTestSuite) TestGet() {
|
||||
audit := &model.AuditLogExt{
|
||||
ProjectID: 1,
|
||||
Resource: "library/hello-world",
|
||||
ResourceType: "artifact",
|
||||
}
|
||||
m.dao.On("Get", mock.Anything, mock.Anything).Return(audit, nil)
|
||||
au, err := m.mgr.Get(nil, 1)
|
||||
m.Require().Nil(err)
|
||||
m.dao.AssertExpectations(m.T())
|
||||
m.Require().NotNil(au)
|
||||
m.Equal(audit.Resource, au.Resource)
|
||||
}
|
||||
|
||||
func (m *managerTestSuite) TestCreate() {
|
||||
m.dao.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
id, err := m.mgr.Create(nil, &model.AuditLogExt{
|
||||
ProjectID: 1,
|
||||
Resource: "library/hello-world",
|
||||
ResourceType: "artifact",
|
||||
})
|
||||
m.Require().Nil(err)
|
||||
m.dao.AssertExpectations(m.T())
|
||||
m.Equal(int64(1), id)
|
||||
}
|
||||
|
||||
func (m *managerTestSuite) TestDelete() {
|
||||
m.dao.On("Delete", mock.Anything, mock.Anything).Return(nil)
|
||||
err := m.mgr.Delete(nil, 1)
|
||||
m.Require().Nil(err)
|
||||
m.dao.AssertExpectations(m.T())
|
||||
}
|
||||
|
||||
func (m *managerTestSuite) TestPurge() {
|
||||
m.dao.On("Purge", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil)
|
||||
total, err := m.mgr.Purge(nil, 1, nil, false)
|
||||
m.Require().Nil(err)
|
||||
m.Equal(int64(1), total)
|
||||
m.dao.AssertExpectations(m.T())
|
||||
}
|
||||
|
||||
func TestManager(t *testing.T) {
|
||||
suite.Run(t, &managerTestSuite{})
|
||||
}
|
62
src/pkg/auditext/model/model.go
Normal file
62
src/pkg/auditext/model/model.go
Normal file
@ -0,0 +1,62 @@
|
||||
// Copyright Project Harbor Authors
|
||||
//
|
||||
// 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 model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
beego_orm "github.com/beego/beego/v2/client/orm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
beego_orm.RegisterModel(&AuditLogExt{})
|
||||
}
|
||||
|
||||
// AuditLogExt is the model for audit log ext
|
||||
type AuditLogExt struct {
|
||||
ID int64 `orm:"pk;auto;column(id)" json:"id"`
|
||||
ProjectID int64 `orm:"column(project_id)" json:"project_id"`
|
||||
Operation string `orm:"column(operation)" json:"operation"`
|
||||
OperationDescription string `orm:"column(op_desc)" json:"operation_description"`
|
||||
OperationResult bool `orm:"column(op_result)" json:"operation_result"`
|
||||
ResourceType string `orm:"column(resource_type)" json:"resource_type"`
|
||||
Resource string `orm:"column(resource)" json:"resource"`
|
||||
Username string `orm:"column(username)" json:"username"`
|
||||
OpTime time.Time `orm:"column(op_time)" json:"op_time" sort:"default:desc"`
|
||||
Payload string `orm:"-" json:"payload"`
|
||||
}
|
||||
|
||||
// TableName for audit log
|
||||
func (a *AuditLogExt) TableName() string {
|
||||
return "audit_log_ext"
|
||||
}
|
||||
|
||||
// EventTypes defines the types of audit log event
|
||||
var EventTypes = []string{
|
||||
"create_artifact",
|
||||
"delete_artifact",
|
||||
"pull_artifact",
|
||||
"create_project",
|
||||
"delete_project",
|
||||
"delete_repository",
|
||||
"login_user",
|
||||
"logout_user",
|
||||
"create_user",
|
||||
"delete_user",
|
||||
"update_user",
|
||||
"create_robot",
|
||||
"delete_robot",
|
||||
"update_configure",
|
||||
}
|
212
src/testing/pkg/auditext/dao/dao.go
Normal file
212
src/testing/pkg/auditext/dao/dao.go
Normal file
@ -0,0 +1,212 @@
|
||||
// Code generated by mockery v2.46.2. DO NOT EDIT.
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
model "github.com/goharbor/harbor/src/pkg/auditext/model"
|
||||
|
||||
q "github.com/goharbor/harbor/src/lib/q"
|
||||
)
|
||||
|
||||
// DAO is an autogenerated mock type for the DAO type
|
||||
type DAO struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Count provides a mock function with given fields: ctx, query
|
||||
func (_m *DAO) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Count")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) (int64, error)); ok {
|
||||
return rf(ctx, query)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok {
|
||||
r0 = rf(ctx, query)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
|
||||
r1 = rf(ctx, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: ctx, access
|
||||
func (_m *DAO) Create(ctx context.Context, access *model.AuditLogExt) (int64, error) {
|
||||
ret := _m.Called(ctx, access)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Create")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *model.AuditLogExt) (int64, error)); ok {
|
||||
return rf(ctx, access)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *model.AuditLogExt) int64); ok {
|
||||
r0 = rf(ctx, access)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *model.AuditLogExt) error); ok {
|
||||
r1 = rf(ctx, access)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: ctx, id
|
||||
func (_m *DAO) Delete(ctx context.Context, id int64) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Delete")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Get provides a mock function with given fields: ctx, id
|
||||
func (_m *DAO) Get(ctx context.Context, id int64) (*model.AuditLogExt, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Get")
|
||||
}
|
||||
|
||||
var r0 *model.AuditLogExt
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) (*model.AuditLogExt, error)); ok {
|
||||
return rf(ctx, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) *model.AuditLogExt); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.AuditLogExt)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// List provides a mock function with given fields: ctx, query
|
||||
func (_m *DAO) List(ctx context.Context, query *q.Query) ([]*model.AuditLogExt, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for List")
|
||||
}
|
||||
|
||||
var r0 []*model.AuditLogExt
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) ([]*model.AuditLogExt, error)); ok {
|
||||
return rf(ctx, query)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*model.AuditLogExt); ok {
|
||||
r0 = rf(ctx, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.AuditLogExt)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
|
||||
r1 = rf(ctx, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Purge provides a mock function with given fields: ctx, retentionHour, includeOperations, dryRun
|
||||
func (_m *DAO) Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error) {
|
||||
ret := _m.Called(ctx, retentionHour, includeOperations, dryRun)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Purge")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int, []string, bool) (int64, error)); ok {
|
||||
return rf(ctx, retentionHour, includeOperations, dryRun)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int, []string, bool) int64); ok {
|
||||
r0 = rf(ctx, retentionHour, includeOperations, dryRun)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int, []string, bool) error); ok {
|
||||
r1 = rf(ctx, retentionHour, includeOperations, dryRun)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateUsername provides a mock function with given fields: ctx, username, usernameReplace
|
||||
func (_m *DAO) UpdateUsername(ctx context.Context, username string, usernameReplace string) error {
|
||||
ret := _m.Called(ctx, username, usernameReplace)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateUsername")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, username, usernameReplace)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewDAO creates a new instance of DAO. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewDAO(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *DAO {
|
||||
mock := &DAO{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
211
src/testing/pkg/auditext/manager.go
Normal file
211
src/testing/pkg/auditext/manager.go
Normal file
@ -0,0 +1,211 @@
|
||||
// Code generated by mockery v2.46.2. DO NOT EDIT.
|
||||
|
||||
package auditext
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
model "github.com/goharbor/harbor/src/pkg/auditext/model"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
q "github.com/goharbor/harbor/src/lib/q"
|
||||
)
|
||||
|
||||
// Manager is an autogenerated mock type for the Manager type
|
||||
type Manager struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Count provides a mock function with given fields: ctx, query
|
||||
func (_m *Manager) Count(ctx context.Context, query *q.Query) (int64, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Count")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) (int64, error)); ok {
|
||||
return rf(ctx, query)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) int64); ok {
|
||||
r0 = rf(ctx, query)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
|
||||
r1 = rf(ctx, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Create provides a mock function with given fields: ctx, audit
|
||||
func (_m *Manager) Create(ctx context.Context, audit *model.AuditLogExt) (int64, error) {
|
||||
ret := _m.Called(ctx, audit)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Create")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *model.AuditLogExt) (int64, error)); ok {
|
||||
return rf(ctx, audit)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *model.AuditLogExt) int64); ok {
|
||||
r0 = rf(ctx, audit)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *model.AuditLogExt) error); ok {
|
||||
r1 = rf(ctx, audit)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Delete provides a mock function with given fields: ctx, id
|
||||
func (_m *Manager) Delete(ctx context.Context, id int64) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Delete")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) error); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// Get provides a mock function with given fields: ctx, id
|
||||
func (_m *Manager) Get(ctx context.Context, id int64) (*model.AuditLogExt, error) {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Get")
|
||||
}
|
||||
|
||||
var r0 *model.AuditLogExt
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) (*model.AuditLogExt, error)); ok {
|
||||
return rf(ctx, id)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int64) *model.AuditLogExt); ok {
|
||||
r0 = rf(ctx, id)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*model.AuditLogExt)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
|
||||
r1 = rf(ctx, id)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// List provides a mock function with given fields: ctx, query
|
||||
func (_m *Manager) List(ctx context.Context, query *q.Query) ([]*model.AuditLogExt, error) {
|
||||
ret := _m.Called(ctx, query)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for List")
|
||||
}
|
||||
|
||||
var r0 []*model.AuditLogExt
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) ([]*model.AuditLogExt, error)); ok {
|
||||
return rf(ctx, query)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, *q.Query) []*model.AuditLogExt); ok {
|
||||
r0 = rf(ctx, query)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*model.AuditLogExt)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, *q.Query) error); ok {
|
||||
r1 = rf(ctx, query)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Purge provides a mock function with given fields: ctx, retentionHour, includeOperations, dryRun
|
||||
func (_m *Manager) Purge(ctx context.Context, retentionHour int, includeOperations []string, dryRun bool) (int64, error) {
|
||||
ret := _m.Called(ctx, retentionHour, includeOperations, dryRun)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Purge")
|
||||
}
|
||||
|
||||
var r0 int64
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int, []string, bool) (int64, error)); ok {
|
||||
return rf(ctx, retentionHour, includeOperations, dryRun)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, int, []string, bool) int64); ok {
|
||||
r0 = rf(ctx, retentionHour, includeOperations, dryRun)
|
||||
} else {
|
||||
r0 = ret.Get(0).(int64)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, int, []string, bool) error); ok {
|
||||
r1 = rf(ctx, retentionHour, includeOperations, dryRun)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UpdateUsername provides a mock function with given fields: ctx, username, replaceWith
|
||||
func (_m *Manager) UpdateUsername(ctx context.Context, username string, replaceWith string) error {
|
||||
ret := _m.Called(ctx, username, replaceWith)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for UpdateUsername")
|
||||
}
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
|
||||
r0 = rf(ctx, username, replaceWith)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewManager creates a new instance of Manager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewManager(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *Manager {
|
||||
mock := &Manager{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
Loading…
Reference in New Issue
Block a user