3
0

Added profiler to apigw

This commit is contained in:
Peter Grlica
2022-02-17 16:05:23 +01:00
parent 046855cb30
commit 476084a3bf
32 changed files with 1865 additions and 46 deletions

View File

@@ -1822,6 +1822,39 @@ endpoints:
title: Proxy auth definitions
path: "/proxy_auth/def"
- title: API Gateway profiler
path: "/apigw/profiler"
entrypoint: apigwProfiler
authentication: []
apis:
- name: aggregation
method: GET
title: List aggregated list of routes
path: "/"
parameters:
get:
- { name: path, type: "string", title: "Filter by request path" }
- { name: before, type: "string", title: "Entries before specified route" }
- { name: sort, type: "string", title: "Sort items" }
- { name: limit, type: "uint", title: "Limit" }
- name: route
method: GET
title: List hits per route
path: "/route/{routeID}"
parameters:
path:
- { name: routeID, type: "string", title: "Route ID", required: true }
get:
- { name: path, type: "string", title: "Filter by request path" }
- { name: before, type: "string", title: "Entries before specified hit ID" }
- { name: sort, type: "string", title: "Sort items" }
- { name: limit, type: "uint", title: "Limit" }
- name: hit
method: GET
title: Hit details
path: "/hit/{hitID}"
parameters: { path: [ { name: hitID, type: string, required: true, title: "Hit ID" } ] }
- title: Locale
entrypoint: locale
path: "/locale"

View File

@@ -0,0 +1,158 @@
package rest
import (
"context"
"github.com/cortezaproject/corteza-server/pkg/filter"
"github.com/cortezaproject/corteza-server/system/rest/request"
"github.com/cortezaproject/corteza-server/system/service"
"github.com/cortezaproject/corteza-server/system/types"
)
type (
profilerService interface {
Hits(context.Context, types.ApigwProfilerFilter) (types.ApigwProfilerHitSet, types.ApigwProfilerFilter, error)
HitsAggregated(context.Context, types.ApigwProfilerFilter) (types.ApigwProfilerAggregationSet, types.ApigwProfilerFilter, error)
}
ApigwProfiler struct {
svc profilerService
ac templateAccessController
}
profilerRoutePayload struct {
*types.ApigwProfilerHit
}
profilerHitPayload struct {
*types.ApigwProfilerAggregation
}
profilerRouteSetPayload struct {
Filter types.ApigwProfilerFilter `json:"filter"`
Set []*profilerRoutePayload `json:"set"`
}
profilerHitSetPayload struct {
Filter types.ApigwProfilerFilter `json:"filter"`
Set []*profilerHitPayload `json:"set"`
}
)
func (ApigwProfiler) New() *ApigwProfiler {
return &ApigwProfiler{
svc: service.DefaultApigwRoute,
ac: service.DefaultAccessControl,
}
}
// List displays the the aggregated list of routes
func (ctrl *ApigwProfiler) Aggregation(ctx context.Context, r *request.ApigwProfilerAggregation) (interface{}, error) {
var (
err error
f = types.ApigwProfilerFilter{
Path: r.Path,
Before: r.Before,
}
)
if f.Sorting, err = filter.NewSorting(r.Sort); err != nil {
return nil, err
}
if f.Paging, err = filter.NewPaging(r.Limit, ""); err != nil {
return nil, err
}
set, f, err := ctrl.svc.HitsAggregated(ctx, f)
return ctrl.makeFilterPayload(ctx, set, f, err)
}
// Route displays the list of hits per-route
func (ctrl *ApigwProfiler) Route(ctx context.Context, r *request.ApigwProfilerRoute) (interface{}, error) {
var (
err error
f = types.ApigwProfilerFilter{
Path: r.RouteID,
Before: r.Before,
}
)
if f.Sorting, err = filter.NewSorting(r.Sort); err != nil {
return nil, err
}
if f.Paging, err = filter.NewPaging(r.Limit, ""); err != nil {
return nil, err
}
set, f, err := ctrl.svc.Hits(ctx, f)
return ctrl.makeRouteFilterPayload(ctx, set, f, err)
}
// Hit displays the details of a certain hit on a route
func (ctrl *ApigwProfiler) Hit(ctx context.Context, r *request.ApigwProfilerHit) (interface{}, error) {
var (
f = types.ApigwProfilerFilter{
Hit: r.HitID,
}
)
set, f, err := ctrl.svc.Hits(ctx, f)
if len(set) != 1 {
return nil, nil
}
return ctrl.makeRoutePayload(ctx, set[0], err)
}
func (ctrl *ApigwProfiler) makePayload(ctx context.Context, q *types.ApigwProfilerAggregation, err error) (*profilerHitPayload, error) {
if err != nil || q == nil {
return nil, err
}
qq := &profilerHitPayload{
ApigwProfilerAggregation: q,
}
return qq, nil
}
func (ctrl *ApigwProfiler) makeFilterPayload(ctx context.Context, nn types.ApigwProfilerAggregationSet, f types.ApigwProfilerFilter, err error) (*profilerHitSetPayload, error) {
if err != nil {
return nil, err
}
msp := &profilerHitSetPayload{Filter: f, Set: make([]*profilerHitPayload, len(nn))}
for i := range nn {
msp.Set[i], _ = ctrl.makePayload(ctx, nn[i], nil)
}
return msp, nil
}
func (ctrl *ApigwProfiler) makeRoutePayload(ctx context.Context, q *types.ApigwProfilerHit, err error) (*profilerRoutePayload, error) {
if err != nil || q == nil {
return nil, err
}
return &profilerRoutePayload{q}, nil
}
func (ctrl *ApigwProfiler) makeRouteFilterPayload(ctx context.Context, nn types.ApigwProfilerHitSet, f types.ApigwProfilerFilter, err error) (*profilerRouteSetPayload, error) {
if err != nil {
return nil, err
}
msp := &profilerRouteSetPayload{Filter: f, Set: make([]*profilerRoutePayload, len(nn))}
for i := range nn {
msp.Set[i], _ = ctrl.makeRoutePayload(ctx, nn[i], nil)
}
return msp, nil
}

View File

@@ -0,0 +1,95 @@
package handlers
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
//
import (
"context"
"github.com/cortezaproject/corteza-server/pkg/api"
"github.com/cortezaproject/corteza-server/system/rest/request"
"github.com/go-chi/chi/v5"
"net/http"
)
type (
// Internal API interface
ApigwProfilerAPI interface {
Aggregation(context.Context, *request.ApigwProfilerAggregation) (interface{}, error)
Route(context.Context, *request.ApigwProfilerRoute) (interface{}, error)
Hit(context.Context, *request.ApigwProfilerHit) (interface{}, error)
}
// HTTP API interface
ApigwProfiler struct {
Aggregation func(http.ResponseWriter, *http.Request)
Route func(http.ResponseWriter, *http.Request)
Hit func(http.ResponseWriter, *http.Request)
}
)
func NewApigwProfiler(h ApigwProfilerAPI) *ApigwProfiler {
return &ApigwProfiler{
Aggregation: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewApigwProfilerAggregation()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.Aggregation(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
Route: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewApigwProfilerRoute()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.Route(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
Hit: func(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
params := request.NewApigwProfilerHit()
if err := params.Fill(r); err != nil {
api.Send(w, r, err)
return
}
value, err := h.Hit(r.Context(), params)
if err != nil {
api.Send(w, r, err)
return
}
api.Send(w, r, value)
},
}
}
func (h ApigwProfiler) MountRoutes(r chi.Router, middlewares ...func(http.Handler) http.Handler) {
r.Group(func(r chi.Router) {
r.Use(middlewares...)
r.Get("/apigw/profiler/", h.Aggregation)
r.Get("/apigw/profiler/route/{routeID}", h.Route)
r.Get("/apigw/profiler/hit/{hitID}", h.Hit)
})
}

View File

@@ -0,0 +1,286 @@
package request
// This file is auto-generated.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
//
// Definitions file that controls how this file is generated:
//
import (
"encoding/json"
"fmt"
"github.com/cortezaproject/corteza-server/pkg/payload"
"github.com/go-chi/chi/v5"
"io"
"mime/multipart"
"net/http"
"strings"
)
// dummy vars to prevent
// unused imports complain
var (
_ = chi.URLParam
_ = multipart.ErrMessageTooLarge
_ = payload.ParseUint64s
_ = strings.ToLower
_ = io.EOF
_ = fmt.Errorf
_ = json.NewEncoder
)
type (
// Internal API interface
ApigwProfilerAggregation struct {
// Path GET parameter
//
// Filter by request path
Path string
// Before GET parameter
//
// Entries before specified route
Before string
// Sort GET parameter
//
// Sort items
Sort string
// Limit GET parameter
//
// Limit
Limit uint
}
ApigwProfilerRoute struct {
// RouteID PATH parameter
//
// Route ID
RouteID string
// Path GET parameter
//
// Filter by request path
Path string
// Before GET parameter
//
// Entries before specified hit ID
Before string
// Sort GET parameter
//
// Sort items
Sort string
// Limit GET parameter
//
// Limit
Limit uint
}
ApigwProfilerHit struct {
// HitID PATH parameter
//
// Hit ID
HitID string
}
)
// NewApigwProfilerAggregation request
func NewApigwProfilerAggregation() *ApigwProfilerAggregation {
return &ApigwProfilerAggregation{}
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerAggregation) Auditable() map[string]interface{} {
return map[string]interface{}{
"path": r.Path,
"before": r.Before,
"sort": r.Sort,
"limit": r.Limit,
}
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerAggregation) GetPath() string {
return r.Path
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerAggregation) GetBefore() string {
return r.Before
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerAggregation) GetSort() string {
return r.Sort
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerAggregation) GetLimit() uint {
return r.Limit
}
// Fill processes request and fills internal variables
func (r *ApigwProfilerAggregation) Fill(req *http.Request) (err error) {
{
// GET params
tmp := req.URL.Query()
if val, ok := tmp["path"]; ok && len(val) > 0 {
r.Path, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["before"]; ok && len(val) > 0 {
r.Before, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["sort"]; ok && len(val) > 0 {
r.Sort, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["limit"]; ok && len(val) > 0 {
r.Limit, err = payload.ParseUint(val[0]), nil
if err != nil {
return err
}
}
}
return err
}
// NewApigwProfilerRoute request
func NewApigwProfilerRoute() *ApigwProfilerRoute {
return &ApigwProfilerRoute{}
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerRoute) Auditable() map[string]interface{} {
return map[string]interface{}{
"routeID": r.RouteID,
"path": r.Path,
"before": r.Before,
"sort": r.Sort,
"limit": r.Limit,
}
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerRoute) GetRouteID() string {
return r.RouteID
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerRoute) GetPath() string {
return r.Path
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerRoute) GetBefore() string {
return r.Before
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerRoute) GetSort() string {
return r.Sort
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerRoute) GetLimit() uint {
return r.Limit
}
// Fill processes request and fills internal variables
func (r *ApigwProfilerRoute) Fill(req *http.Request) (err error) {
{
// GET params
tmp := req.URL.Query()
if val, ok := tmp["path"]; ok && len(val) > 0 {
r.Path, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["before"]; ok && len(val) > 0 {
r.Before, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["sort"]; ok && len(val) > 0 {
r.Sort, err = val[0], nil
if err != nil {
return err
}
}
if val, ok := tmp["limit"]; ok && len(val) > 0 {
r.Limit, err = payload.ParseUint(val[0]), nil
if err != nil {
return err
}
}
}
{
var val string
// path params
val = chi.URLParam(req, "routeID")
r.RouteID, err = val, nil
if err != nil {
return err
}
}
return err
}
// NewApigwProfilerHit request
func NewApigwProfilerHit() *ApigwProfilerHit {
return &ApigwProfilerHit{}
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerHit) Auditable() map[string]interface{} {
return map[string]interface{}{
"hitID": r.HitID,
}
}
// Auditable returns all auditable/loggable parameters
func (r ApigwProfilerHit) GetHitID() string {
return r.HitID
}
// Fill processes request and fills internal variables
func (r *ApigwProfilerHit) Fill(req *http.Request) (err error) {
{
var val string
// path params
val = chi.URLParam(req, "hitID")
r.HitID, err = val, nil
if err != nil {
return err
}
}
return err
}

View File

@@ -43,6 +43,7 @@ func MountRoutes() func(r chi.Router) {
handlers.NewQueues(Queue{}.New()).MountRoutes(r)
handlers.NewApigwRoute(ApigwRoute{}.New()).MountRoutes(r)
handlers.NewApigwFilter(ApigwFilter{}.New()).MountRoutes(r)
handlers.NewApigwProfiler(ApigwProfiler{}.New()).MountRoutes(r)
})
}
}

View File

@@ -2,9 +2,15 @@ package service
import (
"context"
"encoding/base64"
"errors"
"io/ioutil"
"math"
"time"
"github.com/cortezaproject/corteza-server/pkg/actionlog"
"github.com/cortezaproject/corteza-server/pkg/apigw"
"github.com/cortezaproject/corteza-server/pkg/apigw/profiler"
a "github.com/cortezaproject/corteza-server/pkg/auth"
"github.com/cortezaproject/corteza-server/store"
@@ -253,3 +259,160 @@ func (svc *apigwRoute) Search(ctx context.Context, filter types.ApigwRouteFilter
return r, f, svc.recordAction(ctx, aProps, ApigwRouteActionSearch, err)
}
// HitsAggregated fetches a list of hits from integration gateway profiler
func (svc *apigwRoute) Hits(ctx context.Context, filter types.ApigwProfilerFilter) (r types.ApigwProfilerHitSet, f types.ApigwProfilerFilter, err error) {
f = filter
r = make(types.ApigwProfilerHitSet, 0)
uDec, err := base64.URLEncoding.DecodeString(filter.Path)
if err != nil {
return
}
filter.Path = string(uDec)
if filter.Path == "" && filter.Hit == "" {
err = errors.New("fetching all hits (no route and hit specified) not supported")
return
}
var sorting = profiler.Sort{
Hit: filter.Hit,
Path: filter.Path,
Before: filter.Before,
}
var (
list = apigw.Service().Profiler().Hits(sorting)
)
var pp = ""
for k, _ := range list {
if filter.Hit != "" {
pp = k
break
}
if filter.Path != "" && k == filter.Path {
pp = k
break
}
}
if pp == "" {
return
}
for _, h := range list[pp] {
hh := &types.ApigwProfilerHit{
ID: h.ID,
Route: h.Route,
Status: h.Status,
Request: *h.R,
Ts: h.Ts,
Tf: h.Tf,
D: h.D,
Dr: float64(h.D.Microseconds()) / 1000,
}
// fetch body only on hit details
if filter.Hit != "" {
hh.Body, _ = ioutil.ReadAll(hh.Request.Body)
}
r = append(r, hh)
}
// sort
profiler.SortHits(&r, &f)
// filter sorted
profiler.FilterHits(&r, &f)
return
}
// HitsAggregated fetches a list of hits from integration gateway profiler
// and aggregates them with assigned filters
func (svc *apigwRoute) HitsAggregated(ctx context.Context, filter types.ApigwProfilerFilter) (r types.ApigwProfilerAggregationSet, f types.ApigwProfilerFilter, err error) {
f = filter
r = make(types.ApigwProfilerAggregationSet, 0)
uDec, err := base64.URLEncoding.DecodeString(filter.Path)
if err != nil {
return
}
filter.Path = string(uDec)
var (
list = apigw.Service().Profiler().Hits(profiler.Sort{
Path: filter.Path,
Before: filter.Before,
})
tsum, tmin, tmax time.Duration
ssum, smin, smax int64
i uint64 = 1
)
for p, v := range list {
tmin, tmax, tsum = time.Hour, 0, 0
smin, smax, ssum = math.MaxInt64, 0, 0
i = 0
for _, vv := range v {
var (
d = *vv.D
s = vv.R.ContentLength
)
if d < tmin {
tmin = d
}
if d > tmax {
tmax = d
}
if s < smin {
smin = s
}
if s > smax {
smax = s
}
tsum += d
ssum += s
i++
}
r = append(r, &types.ApigwProfilerAggregation{
Path: p,
Count: i,
Tmin: float64(tmin.Microseconds()) / 1000,
Tmax: float64(tmax.Microseconds()) / 1000,
Tavg: float64(tsum.Microseconds()) / float64(i) / 1000,
Smin: smin,
Smax: smax,
Savg: float64(ssum) / float64(i),
})
}
// sort
profiler.SortAggregation(&r, &f)
// filter
profiler.FilterAggregation(&r, &f)
return
}

View File

@@ -6,6 +6,7 @@ import (
"time"
"github.com/cortezaproject/corteza-server/pkg/filter"
h "github.com/cortezaproject/corteza-server/pkg/http"
"github.com/pkg/errors"
)
@@ -26,6 +27,31 @@ type (
DeletedBy uint64 `json:"deletedBy,string,omitempty" `
}
ApigwProfilerHit struct {
ID string `json:"ID"`
Body []byte `json:"body"`
Request h.Request `json:"request"`
Route uint64 `json:"route,string"`
Status int `json:"http_status_code,string"`
Ts *time.Time `json:"time_start"`
Tf *time.Time `json:"time_finish"`
D *time.Duration `json:"-"`
Dr float64 `json:"time_duration"`
}
ApigwProfilerAggregation struct {
Path string `json:"path"`
Count uint64 `json:"count"`
Smin int64 `json:"size_min"`
Smax int64 `json:"size_max"`
Savg float64 `json:"size_avg"`
Tmin float64 `json:"time_min"`
Tmax float64 `json:"time_max"`
Tavg float64 `json:"time_avg"`
}
ApigwRouteMeta struct {
Debug bool `json:"debug"`
Async bool `json:"async"`
@@ -47,6 +73,16 @@ type (
filter.Sorting
filter.Paging
}
ApigwProfilerFilter struct {
Hit string `json:"hit,omitempty"`
Path string `json:"path,omitempty"`
Before string `json:"before,omitempty"`
Next string `json:"next,omitempty"`
filter.Sorting
filter.Paging
}
)
func (cc *ApigwRouteMeta) Scan(value interface{}) error {
@@ -67,3 +103,162 @@ func (cc *ApigwRouteMeta) Scan(value interface{}) error {
func (cc ApigwRouteMeta) Value() (driver.Value, error) {
return json.Marshal(cc)
}
// sorting methods
type (
ByPath ApigwProfilerAggregationSet
ByCount ApigwProfilerAggregationSet
BySizeMin ApigwProfilerAggregationSet
BySizeMax ApigwProfilerAggregationSet
BySizeAvg ApigwProfilerAggregationSet
ByTimeMin ApigwProfilerAggregationSet
ByTimeMax ApigwProfilerAggregationSet
ByTimeAvg ApigwProfilerAggregationSet
BySTime ApigwProfilerHitSet
ByFTime ApigwProfilerHitSet
ByDuration ApigwProfilerHitSet
)
func (h ByPath) Len() int {
return len(h)
}
func (h ByPath) Less(i, j int) bool {
return h[i].Path < h[j].Path
}
func (h ByPath) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h ByCount) Len() int {
return len(h)
}
func (h ByCount) Less(i, j int) bool {
return h[i].Count < h[j].Count
}
func (h ByCount) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h BySizeMin) Len() int {
return len(h)
}
func (h BySizeMin) Less(i, j int) bool {
return h[i].Smin < h[j].Smin
}
func (h BySizeMin) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h BySizeMax) Len() int {
return len(h)
}
func (h BySizeMax) Less(i, j int) bool {
return h[i].Smax < h[j].Smax
}
func (h BySizeMax) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h BySizeAvg) Len() int {
return len(h)
}
func (h BySizeAvg) Less(i, j int) bool {
return h[i].Savg < h[j].Savg
}
func (h BySizeAvg) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h ByTimeAvg) Len() int {
return len(h)
}
func (h ByTimeAvg) Less(i, j int) bool {
return h[i].Tavg < h[j].Tavg
}
func (h ByTimeAvg) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h ByTimeMax) Len() int {
return len(h)
}
func (h ByTimeMax) Less(i, j int) bool {
return h[i].Tmax < h[j].Tmax
}
func (h ByTimeMax) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h ByTimeMin) Len() int {
return len(h)
}
func (h ByTimeMin) Less(i, j int) bool {
return h[i].Tmin < h[j].Tmin
}
func (h ByTimeMin) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h BySTime) Len() int {
return len(h)
}
func (h BySTime) Less(i, j int) bool {
return h[j].Ts.After(*h[i].Ts)
}
func (h BySTime) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h ByFTime) Len() int {
return len(h)
}
func (h ByFTime) Less(i, j int) bool {
return h[j].Tf.After(*h[i].Tf)
}
func (h ByFTime) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}
func (h ByDuration) Len() int {
return len(h)
}
func (h ByDuration) Less(i, j int) bool {
return h[i].D.Microseconds() > h[j].D.Microseconds()
}
func (h ByDuration) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
return
}

View File

@@ -207,6 +207,13 @@ type (
Enabled bool `kv:"-" json:"enabled"`
} `kv:"federation" json:"federation"`
// Federation settings
Apigw struct {
// This only holds the value of APIGW_PROFILER_ENABLED for now
//
ProfilerEnabled bool `kv:"-" json:"profilerEnabled"`
} `kv:"apigw" json:"apigw"`
// UserInterface settings
UI struct {
MainLogo string `kv:"main-logo" json:"mainLogo"`

View File

@@ -15,6 +15,16 @@ type (
// This type is auto-generated.
ApigwFilterSet []*ApigwFilter
// ApigwProfilerAggregationSet slice of ApigwProfilerAggregation
//
// This type is auto-generated.
ApigwProfilerAggregationSet []*ApigwProfilerAggregation
// ApigwProfilerHitSet slice of ApigwProfilerHit
//
// This type is auto-generated.
ApigwProfilerHitSet []*ApigwProfilerHit
// ApigwRouteSet slice of ApigwRoute
//
// This type is auto-generated.
@@ -162,6 +172,66 @@ func (set ApigwFilterSet) IDs() (IDs []uint64) {
return
}
// Walk iterates through every slice item and calls w(ApigwProfilerAggregation) err
//
// This function is auto-generated.
func (set ApigwProfilerAggregationSet) Walk(w func(*ApigwProfilerAggregation) error) (err error) {
for i := range set {
if err = w(set[i]); err != nil {
return
}
}
return
}
// Filter iterates through every slice item, calls f(ApigwProfilerAggregation) (bool, err) and return filtered slice
//
// This function is auto-generated.
func (set ApigwProfilerAggregationSet) Filter(f func(*ApigwProfilerAggregation) (bool, error)) (out ApigwProfilerAggregationSet, err error) {
var ok bool
out = ApigwProfilerAggregationSet{}
for i := range set {
if ok, err = f(set[i]); err != nil {
return
} else if ok {
out = append(out, set[i])
}
}
return
}
// Walk iterates through every slice item and calls w(ApigwProfilerHit) err
//
// This function is auto-generated.
func (set ApigwProfilerHitSet) Walk(w func(*ApigwProfilerHit) error) (err error) {
for i := range set {
if err = w(set[i]); err != nil {
return
}
}
return
}
// Filter iterates through every slice item, calls f(ApigwProfilerHit) (bool, err) and return filtered slice
//
// This function is auto-generated.
func (set ApigwProfilerHitSet) Filter(f func(*ApigwProfilerHit) (bool, error)) (out ApigwProfilerHitSet, err error) {
var ok bool
out = ApigwProfilerHitSet{}
for i := range set {
if ok, err = f(set[i]); err != nil {
return
} else if ok {
out = append(out, set[i])
}
}
return
}
// Walk iterates through every slice item and calls w(ApigwRoute) err
//
// This function is auto-generated.

View File

@@ -104,6 +104,118 @@ func TestApigwFilterSetIDs(t *testing.T) {
}
}
func TestApigwProfilerAggregationSetWalk(t *testing.T) {
var (
value = make(ApigwProfilerAggregationSet, 3)
req = require.New(t)
)
// check walk with no errors
{
err := value.Walk(func(*ApigwProfilerAggregation) error {
return nil
})
req.NoError(err)
}
// check walk with error
req.Error(value.Walk(func(*ApigwProfilerAggregation) error { return fmt.Errorf("walk error") }))
}
func TestApigwProfilerAggregationSetFilter(t *testing.T) {
var (
value = make(ApigwProfilerAggregationSet, 3)
req = require.New(t)
)
// filter nothing
{
set, err := value.Filter(func(*ApigwProfilerAggregation) (bool, error) {
return true, nil
})
req.NoError(err)
req.Equal(len(set), len(value))
}
// filter one item
{
found := false
set, err := value.Filter(func(*ApigwProfilerAggregation) (bool, error) {
if !found {
found = true
return found, nil
}
return false, nil
})
req.NoError(err)
req.Len(set, 1)
}
// filter error
{
_, err := value.Filter(func(*ApigwProfilerAggregation) (bool, error) {
return false, fmt.Errorf("filter error")
})
req.Error(err)
}
}
func TestApigwProfilerHitSetWalk(t *testing.T) {
var (
value = make(ApigwProfilerHitSet, 3)
req = require.New(t)
)
// check walk with no errors
{
err := value.Walk(func(*ApigwProfilerHit) error {
return nil
})
req.NoError(err)
}
// check walk with error
req.Error(value.Walk(func(*ApigwProfilerHit) error { return fmt.Errorf("walk error") }))
}
func TestApigwProfilerHitSetFilter(t *testing.T) {
var (
value = make(ApigwProfilerHitSet, 3)
req = require.New(t)
)
// filter nothing
{
set, err := value.Filter(func(*ApigwProfilerHit) (bool, error) {
return true, nil
})
req.NoError(err)
req.Equal(len(set), len(value))
}
// filter one item
{
found := false
set, err := value.Filter(func(*ApigwProfilerHit) (bool, error) {
if !found {
found = true
return found, nil
}
return false, nil
})
req.NoError(err)
req.Len(set, 1)
}
// filter error
{
_, err := value.Filter(func(*ApigwProfilerHit) (bool, error) {
return false, fmt.Errorf("filter error")
})
req.Error(err)
}
}
func TestApigwRouteSetWalk(t *testing.T) {
var (
value = make(ApigwRouteSet, 3)

View File

@@ -23,6 +23,10 @@ types:
labelResourceType: template
ApigwRoute: {}
ApigwFilter: {}
ApigwProfilerHit:
noIdField: true
ApigwProfilerAggregation:
noIdField: true
Report:
labelResourceType: report
ResourceTranslation: {}