From 2c1d0533965276bda02c036b03fa525e700cdf05 Mon Sep 17 00:00:00 2001 From: Nirav Parikh Date: Wed, 23 Nov 2022 14:11:30 +0530 Subject: [PATCH] updated query to use time column instead of timestamp from data --- CHANGELOG.md | 2 ++ internal/dao/auditlog.go | 4 ++-- pkg/service/audit_log_db.go | 1 + pkg/service/audit_log_db_test.go | 24 ++++++++++++------------ pkg/service/cluster.go | 3 ++- pkg/service/relay_audit_db_test.go | 24 ++++++++++++------------ 6 files changed, 31 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e66649b..348ad72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. ## Unreleased +- Added database auditlog storage option [niravparikh05](https://github.com/niravparikh05) + ## [0.1.7] - 2022-11-04 ## Added diff --git a/internal/dao/auditlog.go b/internal/dao/auditlog.go index d66347e..24aeb06 100644 --- a/internal/dao/auditlog.go +++ b/internal/dao/auditlog.go @@ -92,7 +92,7 @@ func buildRelayAuditQuery(query *bun.SelectQuery, filters query.QueryFilters) *b } if filters.GetTimefrom() != "" { diff := strings.Split(filters.GetTimefrom(), "-")[1] - query.Where("to_timestamp(data->>'ts', 'YYYY-MM-DD\"T\"HH:MI:SS') between now() - interval ? and now()", diff) + query.Where("time between now() - interval ? and now()", diff) } return query } @@ -118,7 +118,7 @@ func buildQuery(query *bun.SelectQuery, filters query.QueryFilters) *bun.SelectQ if filters.GetTimefrom() != "" { diff := strings.Split(filters.GetTimefrom(), "-")[1] - query.Where("to_timestamp(data->>'timestamp', 'YYYY-MM-DD\"T\"HH:MI:SS') between now() - interval ? and now()", diff) + query.Where("time between now() - interval ? and now()", diff) } return query diff --git a/pkg/service/audit_log_db.go b/pkg/service/audit_log_db.go index 57e45bf..ce43c7d 100644 --- a/pkg/service/audit_log_db.go +++ b/pkg/service/audit_log_db.go @@ -41,6 +41,7 @@ func buildDataSource(logs []models.AuditLog) (ds []*auditv1.DataSource) { for _, log := range logs { data := &auditv1.Data{} json.Unmarshal(log.Data, data) + data.Timestamp = log.Time.String() ds = append(ds, &auditv1.DataSource{ XSource: &auditv1.DataSourceJSON{ Json: data, diff --git a/pkg/service/audit_log_db_test.go b/pkg/service/audit_log_db_test.go index 8ac5848..7129e10 100644 --- a/pkg/service/audit_log_db_test.go +++ b/pkg/service/audit_log_db_test.go @@ -70,16 +70,16 @@ func testGetAuditLogForLastHour(tag string) func(t *testing.T) { }, } - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now())`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now())`)). WillReturnRows(sqlmock.NewRows([]string{"tag", "time", "data"}).AddRow("system", time.Now(), auditrecord)) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'project' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'project'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'project' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'project'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "cluster")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->'actor'->'account'->>'username' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->'actor'->'account'->>'username'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->'actor'->'account'->>'username' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->'actor'->'account'->>'username'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "username")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'type' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'type'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'type' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'type'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "type")) res, err := as.GetAuditLogByProjects(req) @@ -127,16 +127,16 @@ func testGetAuditLogForDay(tag string) func(t *testing.T) { }, } - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now())`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now())`)). WillReturnRows(sqlmock.NewRows([]string{"tag", "time", "data"}).AddRow(tag, time.Now(), auditrecord).AddRow(tag, time.Now(), auditrecordtwo)) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'project' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'project'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'project' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'project'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "project")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->'actor'->'account'->>'username' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->'actor'->'account'->>'username'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->'actor'->'account'->>'username' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->'actor'->'account'->>'username'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "username")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'type' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'type'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'type' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'type'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "type")) res, err := as.GetAuditLog(req) @@ -184,16 +184,16 @@ func testGetKubectlCommands(tag string) func(t *testing.T) { }, } - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now())`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now())`)). WillReturnRows(sqlmock.NewRows([]string{"tag", "time", "data"}).AddRow(tag, time.Now(), auditrecord).AddRow(tag, time.Now(), auditrecordtwo)) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'project' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'project'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'project' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'project'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "project")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->'actor'->'account'->>'username' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->'actor'->'account'->>'username'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->'actor'->'account'->>'username' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->'actor'->'account'->>'username'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "username")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'type' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (to_timestamp(data->>'timestamp', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'type'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'type' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'project' = '` + project + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'type'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "type")) res, err := as.GetAuditLog(req) diff --git a/pkg/service/cluster.go b/pkg/service/cluster.go index 2c1c6cc..a7499f0 100644 --- a/pkg/service/cluster.go +++ b/pkg/service/cluster.go @@ -477,6 +477,7 @@ func (s *clusterService) prepareClusterResponse(ctx context.Context, clstr *infr func (s *clusterService) Update(ctx context.Context, cluster *infrav3.Cluster) (*infrav3.Cluster, error) { + projectName := cluster.Metadata.Project var errormsg string if cluster.Metadata.Name == "" { @@ -598,7 +599,7 @@ func (s *clusterService) Update(ctx context.Context, cluster *infrav3.Cluster) ( h.OnChange(ev) }*/ - CreateClusterAuditEvent(ctx, s.al, AuditActionUpdate, cluster.GetMetadata().GetName(), cdb.ID, cluster.Metadata.Project) + CreateClusterAuditEvent(ctx, s.al, AuditActionUpdate, cluster.GetMetadata().GetName(), cdb.ID, projectName) return cluster, nil } diff --git a/pkg/service/relay_audit_db_test.go b/pkg/service/relay_audit_db_test.go index 1db047b..09f217c 100644 --- a/pkg/service/relay_audit_db_test.go +++ b/pkg/service/relay_audit_db_test.go @@ -64,22 +64,22 @@ func testGetRelayAuditLogForCluster(tag string) func(t *testing.T) { }, } - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now())`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (time between now() - interval '` + timefrom + `' and now())`)). WillReturnRows(sqlmock.NewRows([]string{"tag", "time", "data"}).AddRow(tag, time.Now(), auditrecord)) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'cn' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'cn'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'cn' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'cn'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "cluster")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'un' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'un'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'un' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'un'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "username")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'n' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'n'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'n' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'n'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "namespace")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'k' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'k'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'k' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'k'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "kind")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'m' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'m'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'m' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'cn' = '` + req.Filter.Cluster + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'m'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "method")) res, err := ras.GetRelayAudit(req) @@ -128,22 +128,22 @@ func testGetRelayAuditLogForKind(tag string) func(t *testing.T) { }, } - mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now())`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT "auditlog"."tag", "auditlog"."time", "auditlog"."data" FROM "audit_logs" AS "auditlog" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (time between now() - interval '` + timefrom + `' and now())`)). WillReturnRows(sqlmock.NewRows([]string{"tag", "time", "data"}).AddRow(tag, time.Now(), auditrecord).AddRow(tag, time.Now(), auditrecordtwo)) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'cn' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'cn'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'cn' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'cn'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "cluster")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'un' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'un'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'un' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'un'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "username")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'n' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'n'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'n' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'n'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "namespace")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'k' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'k'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'k' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'k'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "kind")) - mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'m' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (to_timestamp(data->>'ts', 'YYYY-MM-DD"T"HH:MI:SS') between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'m'`)). + mock.ExpectQuery(regexp.QuoteMeta(`SELECT count(1) as count, data->>'m' as key FROM "audit_logs" WHERE (tag = '` + tag + `') AND (data->>'k' = '` + req.Filter.Kind + `') AND (time between now() - interval '` + timefrom + `' and now()) GROUP BY data->>'m'`)). WillReturnRows(sqlmock.NewRows([]string{"count", "key"}).AddRow(1, "method")) res, err := as.GetRelayAudit(req)