[WIP] Add set_memory_request_to_limit option (#406)
* Add set_memory_request_to_limit option
This commit is contained in:
parent
f25351c36a
commit
45c89b3da4
|
|
@ -90,6 +90,8 @@ cd postgres-operator
|
||||||
./run_operator_locally.sh
|
./run_operator_locally.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Note we provide the `/manifests` directory as an example only; you should consider adjusting the manifests to your particular setting.
|
||||||
|
|
||||||
## Running and testing the operator
|
## Running and testing the operator
|
||||||
|
|
||||||
The best way to test the operator is to run it locally in [minikube](https://kubernetes.io/docs/getting-started-guides/minikube/). See developer docs(`docs/developer.yaml`) for details.
|
The best way to test the operator is to run it locally in [minikube](https://kubernetes.io/docs/getting-started-guides/minikube/). See developer docs(`docs/developer.yaml`) for details.
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ pipeline:
|
||||||
go version
|
go version
|
||||||
- desc: 'Install Docker'
|
- desc: 'Install Docker'
|
||||||
cmd: |
|
cmd: |
|
||||||
curl -sSL https://get.docker.com/ | sh
|
curl -fLOsS https://delivery.cloud.zalando.com/utils/ensure-docker && sh ensure-docker && rm ensure-docker
|
||||||
- desc: 'Symlink sources into the GOPATH'
|
- desc: 'Symlink sources into the GOPATH'
|
||||||
cmd: |
|
cmd: |
|
||||||
mkdir -p $OPERATOR_TOP_DIR
|
mkdir -p $OPERATOR_TOP_DIR
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,12 @@ manifests:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ kubectl create namespace test
|
$ kubectl create namespace test
|
||||||
$ kubectl config set-context --namespace=test
|
$ kubectl config set-context $(kubectl config current-context) --namespace=test
|
||||||
```
|
```
|
||||||
|
|
||||||
All subsequent `kubectl` commands will work with the `test` namespace. The
|
All subsequent `kubectl` commands will work with the `test` namespace. The
|
||||||
operator will run in this namespace and look up needed resources - such as its
|
operator will run in this namespace and look up needed resources - such as its
|
||||||
config map - there.
|
config map - there. Please note that the namespace for service accounts and cluster role bindings in [operator RBAC rules](manifests/operator-service-account-rbac.yaml) needs to be adjusted to the non-default value.
|
||||||
|
|
||||||
## Specify the namespace to watch
|
## Specify the namespace to watch
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,9 @@ CRD-based configuration.
|
||||||
memory limits for the postgres containers, unless overridden by cluster-specific
|
memory limits for the postgres containers, unless overridden by cluster-specific
|
||||||
settings. The default is `1Gi`.
|
settings. The default is `1Gi`.
|
||||||
|
|
||||||
|
* **set_memory_request_to_limit**
|
||||||
|
Set `memory_request` to `memory_limit` for all Postgres clusters (the default value is also increased). This prevents certain cases of memory overcommitment at the cost of overprovisioning memory and potential scheduling problems for containers with high memory limits due to the lack of memory on Kubernetes cluster nodes. This affects all containers (Postgres, Scalyr sidecar, and other sidecars). The default is `false`.
|
||||||
|
|
||||||
## Operator timeouts
|
## Operator timeouts
|
||||||
|
|
||||||
This set of parameters define various timeouts related to some operator
|
This set of parameters define various timeouts related to some operator
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
teamId: "ACID"
|
teamId: "ACID"
|
||||||
volume:
|
volume:
|
||||||
size: 5Gi
|
size: 1Gi
|
||||||
numberOfInstances: 2
|
numberOfInstances: 2
|
||||||
users: #Application/Robot users
|
users: #Application/Robot users
|
||||||
zalando:
|
zalando:
|
||||||
|
|
@ -31,7 +31,7 @@ spec:
|
||||||
memory: 100Mi
|
memory: 100Mi
|
||||||
limits:
|
limits:
|
||||||
cpu: 300m
|
cpu: 300m
|
||||||
memory: 3000Mi
|
memory: 300Mi
|
||||||
patroni:
|
patroni:
|
||||||
initdb:
|
initdb:
|
||||||
encoding: "UTF8"
|
encoding: "UTF8"
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,12 @@ data:
|
||||||
|
|
||||||
debug_logging: "true"
|
debug_logging: "true"
|
||||||
workers: "4"
|
workers: "4"
|
||||||
docker_image: registry.opensource.zalan.do/acid/spilo-cdp-10:1.4-p29
|
docker_image: registry.opensource.zalan.do/acid/spilo-cdp-10:1.5-p35
|
||||||
pod_service_account_name: "zalando-postgres-operator"
|
pod_service_account_name: "zalando-postgres-operator"
|
||||||
secret_name_template: '{username}.{cluster}.credentials'
|
secret_name_template: '{username}.{cluster}.credentials'
|
||||||
super_username: postgres
|
super_username: postgres
|
||||||
enable_teams_api: "false"
|
enable_teams_api: "false"
|
||||||
|
# set_memory_request_to_limit: "true"
|
||||||
# postgres_superuser_teams: "postgres_superusers"
|
# postgres_superuser_teams: "postgres_superusers"
|
||||||
# enable_team_superuser: "false"
|
# enable_team_superuser: "false"
|
||||||
# team_admin_role: "admin"
|
# team_admin_role: "admin"
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,7 @@ type OperatorConfigurationData struct {
|
||||||
PostgresUsersConfiguration PostgresUsersConfiguration `json:"users"`
|
PostgresUsersConfiguration PostgresUsersConfiguration `json:"users"`
|
||||||
Kubernetes KubernetesMetaConfiguration `json:"kubernetes"`
|
Kubernetes KubernetesMetaConfiguration `json:"kubernetes"`
|
||||||
PostgresPodResources PostgresPodResourcesDefaults `json:"postgres_pod_resources"`
|
PostgresPodResources PostgresPodResourcesDefaults `json:"postgres_pod_resources"`
|
||||||
|
SetMemoryRequestToLimit bool `json:"set_memory_request_to_limit,omitempty"`
|
||||||
Timeouts OperatorTimeouts `json:"timeouts"`
|
Timeouts OperatorTimeouts `json:"timeouts"`
|
||||||
LoadBalancer LoadBalancerConfiguration `json:"load_balancer"`
|
LoadBalancer LoadBalancerConfiguration `json:"load_balancer"`
|
||||||
AWSGCP AWSGCPConfiguration `json:"aws_or_gcp"`
|
AWSGCP AWSGCPConfiguration `json:"aws_or_gcp"`
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ type ResourceDescription struct {
|
||||||
|
|
||||||
// Resources describes requests and limits for the cluster resouces.
|
// Resources describes requests and limits for the cluster resouces.
|
||||||
type Resources struct {
|
type Resources struct {
|
||||||
ResourceRequest ResourceDescription `json:"requests,omitempty"`
|
ResourceRequests ResourceDescription `json:"requests,omitempty"`
|
||||||
ResourceLimits ResourceDescription `json:"limits,omitempty"`
|
ResourceLimits ResourceDescription `json:"limits,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ var unmarshalCluster = []struct {
|
||||||
Slots: map[string]map[string]string{"permanent_logical_1": {"type": "logical", "database": "foo", "plugin": "pgoutput"}},
|
Slots: map[string]map[string]string{"permanent_logical_1": {"type": "logical", "database": "foo", "plugin": "pgoutput"}},
|
||||||
},
|
},
|
||||||
Resources: Resources{
|
Resources: Resources{
|
||||||
ResourceRequest: ResourceDescription{CPU: "10m", Memory: "50Mi"},
|
ResourceRequests: ResourceDescription{CPU: "10m", Memory: "50Mi"},
|
||||||
ResourceLimits: ResourceDescription{CPU: "300m", Memory: "3000Mi"},
|
ResourceLimits: ResourceDescription{CPU: "300m", Memory: "3000Mi"},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -573,7 +573,7 @@ func (in *ResourceDescription) DeepCopy() *ResourceDescription {
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *Resources) DeepCopyInto(out *Resources) {
|
func (in *Resources) DeepCopyInto(out *Resources) {
|
||||||
*out = *in
|
*out = *in
|
||||||
out.ResourceRequest = in.ResourceRequest
|
out.ResourceRequests = in.ResourceRequests
|
||||||
out.ResourceLimits = in.ResourceLimits
|
out.ResourceLimits = in.ResourceLimits
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,18 +92,18 @@ func (c *Cluster) makeDefaultResources() acidv1.Resources {
|
||||||
defaultRequests := acidv1.ResourceDescription{CPU: config.DefaultCPURequest, Memory: config.DefaultMemoryRequest}
|
defaultRequests := acidv1.ResourceDescription{CPU: config.DefaultCPURequest, Memory: config.DefaultMemoryRequest}
|
||||||
defaultLimits := acidv1.ResourceDescription{CPU: config.DefaultCPULimit, Memory: config.DefaultMemoryLimit}
|
defaultLimits := acidv1.ResourceDescription{CPU: config.DefaultCPULimit, Memory: config.DefaultMemoryLimit}
|
||||||
|
|
||||||
return acidv1.Resources{ResourceRequest: defaultRequests, ResourceLimits: defaultLimits}
|
return acidv1.Resources{ResourceRequests: defaultRequests, ResourceLimits: defaultLimits}
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateResourceRequirements(resources acidv1.Resources, defaultResources acidv1.Resources) (*v1.ResourceRequirements, error) {
|
func generateResourceRequirements(resources acidv1.Resources, defaultResources acidv1.Resources) (*v1.ResourceRequirements, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
specRequests := resources.ResourceRequest
|
specRequests := resources.ResourceRequests
|
||||||
specLimits := resources.ResourceLimits
|
specLimits := resources.ResourceLimits
|
||||||
|
|
||||||
result := v1.ResourceRequirements{}
|
result := v1.ResourceRequirements{}
|
||||||
|
|
||||||
result.Requests, err = fillResourceList(specRequests, defaultResources.ResourceRequest)
|
result.Requests, err = fillResourceList(specRequests, defaultResources.ResourceRequests)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not fill resource requests: %v", err)
|
return nil, fmt.Errorf("could not fill resource requests: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -377,8 +377,8 @@ func generateSidecarContainers(sidecars []acidv1.Sidecar,
|
||||||
|
|
||||||
resources, err := generateResourceRequirements(
|
resources, err := generateResourceRequirements(
|
||||||
makeResources(
|
makeResources(
|
||||||
sidecar.Resources.ResourceRequest.CPU,
|
sidecar.Resources.ResourceRequests.CPU,
|
||||||
sidecar.Resources.ResourceRequest.Memory,
|
sidecar.Resources.ResourceRequests.Memory,
|
||||||
sidecar.Resources.ResourceLimits.CPU,
|
sidecar.Resources.ResourceLimits.CPU,
|
||||||
sidecar.Resources.ResourceLimits.Memory,
|
sidecar.Resources.ResourceLimits.Memory,
|
||||||
),
|
),
|
||||||
|
|
@ -625,7 +625,7 @@ func getBucketScopeSuffix(uid string) string {
|
||||||
|
|
||||||
func makeResources(cpuRequest, memoryRequest, cpuLimit, memoryLimit string) acidv1.Resources {
|
func makeResources(cpuRequest, memoryRequest, cpuLimit, memoryLimit string) acidv1.Resources {
|
||||||
return acidv1.Resources{
|
return acidv1.Resources{
|
||||||
ResourceRequest: acidv1.ResourceDescription{
|
ResourceRequests: acidv1.ResourceDescription{
|
||||||
CPU: cpuRequest,
|
CPU: cpuRequest,
|
||||||
Memory: memoryRequest,
|
Memory: memoryRequest,
|
||||||
},
|
},
|
||||||
|
|
@ -644,6 +644,60 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*v1beta1.State
|
||||||
podTemplate *v1.PodTemplateSpec
|
podTemplate *v1.PodTemplateSpec
|
||||||
volumeClaimTemplate *v1.PersistentVolumeClaim
|
volumeClaimTemplate *v1.PersistentVolumeClaim
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if c.OpConfig.SetMemoryRequestToLimit {
|
||||||
|
|
||||||
|
// controller adjusts the default memory request at operator startup
|
||||||
|
|
||||||
|
request := spec.Resources.ResourceRequests.Memory
|
||||||
|
if request == "" {
|
||||||
|
request = c.OpConfig.DefaultMemoryRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
limit := spec.Resources.ResourceLimits.Memory
|
||||||
|
if limit == "" {
|
||||||
|
limit = c.OpConfig.DefaultMemoryLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
isSmaller, err := util.RequestIsSmallerThanLimit(request, limit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if isSmaller {
|
||||||
|
c.logger.Warningf("The memory request of %v for the Postgres container is increased to match the memory limit of %v.", request, limit)
|
||||||
|
spec.Resources.ResourceRequests.Memory = limit
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// controller adjusts the Scalyr sidecar request at operator startup
|
||||||
|
// as this sidecar is managed separately
|
||||||
|
|
||||||
|
// adjust sidecar containers defined for that particular cluster
|
||||||
|
for _, sidecar := range spec.Sidecars {
|
||||||
|
|
||||||
|
// TODO #413
|
||||||
|
sidecarRequest := sidecar.Resources.ResourceRequests.Memory
|
||||||
|
if request == "" {
|
||||||
|
request = c.OpConfig.DefaultMemoryRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
sidecarLimit := sidecar.Resources.ResourceLimits.Memory
|
||||||
|
if limit == "" {
|
||||||
|
limit = c.OpConfig.DefaultMemoryLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
isSmaller, err := util.RequestIsSmallerThanLimit(sidecarRequest, sidecarLimit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if isSmaller {
|
||||||
|
c.logger.Warningf("The memory request of %v for the %v sidecar container is increased to match the memory limit of %v.", sidecar.Resources.ResourceRequests.Memory, sidecar.Name, sidecar.Resources.ResourceLimits.Memory)
|
||||||
|
sidecar.Resources.ResourceRequests.Memory = sidecar.Resources.ResourceLimits.Memory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
defaultResources := c.makeDefaultResources()
|
defaultResources := c.makeDefaultResources()
|
||||||
|
|
||||||
resourceRequirements, err := generateResourceRequirements(spec.Resources, defaultResources)
|
resourceRequirements, err := generateResourceRequirements(spec.Resources, defaultResources)
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,29 @@ func (c *Controller) initOperatorConfig() {
|
||||||
c.opConfig = config.NewFromMap(configMapData)
|
c.opConfig = config.NewFromMap(configMapData)
|
||||||
c.warnOnDeprecatedOperatorParameters()
|
c.warnOnDeprecatedOperatorParameters()
|
||||||
|
|
||||||
|
if c.opConfig.SetMemoryRequestToLimit {
|
||||||
|
|
||||||
|
isSmaller, err := util.RequestIsSmallerThanLimit(c.opConfig.DefaultMemoryRequest, c.opConfig.DefaultMemoryLimit)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if isSmaller {
|
||||||
|
c.logger.Warningf("The default memory request of %v for Postgres containers is increased to match the default memory limit of %v.", c.opConfig.DefaultMemoryRequest, c.opConfig.DefaultMemoryLimit)
|
||||||
|
c.opConfig.DefaultMemoryRequest = c.opConfig.DefaultMemoryLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
isSmaller, err = util.RequestIsSmallerThanLimit(c.opConfig.ScalyrMemoryRequest, c.opConfig.ScalyrMemoryLimit)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if isSmaller {
|
||||||
|
c.logger.Warningf("The memory request of %v for the Scalyr sidecar container is increased to match the memory limit of %v.", c.opConfig.ScalyrMemoryRequest, c.opConfig.ScalyrMemoryLimit)
|
||||||
|
c.opConfig.ScalyrMemoryRequest = c.opConfig.ScalyrMemoryLimit
|
||||||
|
}
|
||||||
|
|
||||||
|
// generateStatefulSet adjusts values for individual Postgres clusters
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Controller) modifyConfigFromEnvironment() {
|
func (c *Controller) modifyConfigFromEnvironment() {
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||||
result.DefaultMemoryRequest = fromCRD.PostgresPodResources.DefaultMemoryRequest
|
result.DefaultMemoryRequest = fromCRD.PostgresPodResources.DefaultMemoryRequest
|
||||||
result.DefaultCPULimit = fromCRD.PostgresPodResources.DefaultCPULimit
|
result.DefaultCPULimit = fromCRD.PostgresPodResources.DefaultCPULimit
|
||||||
result.DefaultMemoryLimit = fromCRD.PostgresPodResources.DefaultMemoryLimit
|
result.DefaultMemoryLimit = fromCRD.PostgresPodResources.DefaultMemoryLimit
|
||||||
|
result.SetMemoryRequestToLimit = fromCRD.SetMemoryRequestToLimit
|
||||||
|
|
||||||
result.ResourceCheckInterval = time.Duration(fromCRD.Timeouts.ResourceCheckInterval)
|
result.ResourceCheckInterval = time.Duration(fromCRD.Timeouts.ResourceCheckInterval)
|
||||||
result.ResourceCheckTimeout = time.Duration(fromCRD.Timeouts.ResourceCheckTimeout)
|
result.ResourceCheckTimeout = time.Duration(fromCRD.Timeouts.ResourceCheckTimeout)
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ type Config struct {
|
||||||
PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"`
|
PodTerminateGracePeriod time.Duration `name:"pod_terminate_grace_period" default:"5m"`
|
||||||
ProtectedRoles []string `name:"protected_role_names" default:"admin"`
|
ProtectedRoles []string `name:"protected_role_names" default:"admin"`
|
||||||
PostgresSuperuserTeams []string `name:"postgres_superuser_teams" default:""`
|
PostgresSuperuserTeams []string `name:"postgres_superuser_teams" default:""`
|
||||||
|
SetMemoryRequestToLimit bool `name:"set_memory_request_to_limit" defaults:"false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// MustMarshal marshals the config or panics
|
// MustMarshal marshals the config or panics
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,14 @@ package util
|
||||||
import (
|
import (
|
||||||
"crypto/md5" // #nosec we need it to for PostgreSQL md5 passwords
|
"crypto/md5" // #nosec we need it to for PostgreSQL md5 passwords
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/motomux/pretty"
|
"github.com/motomux/pretty"
|
||||||
|
resource "k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
"github.com/zalando-incubator/postgres-operator/pkg/spec"
|
"github.com/zalando-incubator/postgres-operator/pkg/spec"
|
||||||
|
|
@ -127,3 +129,19 @@ func Coalesce(val, defaultVal string) string {
|
||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequestIsSmallerThanLimit
|
||||||
|
func RequestIsSmallerThanLimit(requestStr, limitStr string) (bool, error) {
|
||||||
|
|
||||||
|
request, err := resource.ParseQuantity(requestStr)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("could not parse memory request %v : %v", requestStr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
limit, err2 := resource.ParseQuantity(limitStr)
|
||||||
|
if err2 != nil {
|
||||||
|
return false, fmt.Errorf("could not parse memory limit %v : %v", limitStr, err2)
|
||||||
|
}
|
||||||
|
|
||||||
|
return request.Cmp(limit) == -1, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,17 @@ var substringMatch = []struct {
|
||||||
{regexp.MustCompile(`aaaa (\d+) bbbb`), "aaaa 123 bbbb", nil},
|
{regexp.MustCompile(`aaaa (\d+) bbbb`), "aaaa 123 bbbb", nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var requestIsSmallerThanLimitTests = []struct {
|
||||||
|
request string
|
||||||
|
limit string
|
||||||
|
out bool
|
||||||
|
}{
|
||||||
|
{"1G", "2G", true},
|
||||||
|
{"1G", "1Gi", true}, // G is 1000^3 bytes, Gi is 1024^3 bytes
|
||||||
|
{"1024Mi", "1G", false},
|
||||||
|
{"1e9", "1G", false}, // 1e9 bytes == 1G
|
||||||
|
}
|
||||||
|
|
||||||
func TestRandomPassword(t *testing.T) {
|
func TestRandomPassword(t *testing.T) {
|
||||||
const pwdLength = 10
|
const pwdLength = 10
|
||||||
pwd := RandomPassword(pwdLength)
|
pwd := RandomPassword(pwdLength)
|
||||||
|
|
@ -143,3 +154,15 @@ func TestMapContains(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRequestIsSmallerThanLimit(t *testing.T) {
|
||||||
|
for _, tt := range requestIsSmallerThanLimitTests {
|
||||||
|
res, err := RequestIsSmallerThanLimit(tt.request, tt.limit)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("RequestIsSmallerThanLimit returned unexpected error: %#v", err)
|
||||||
|
}
|
||||||
|
if res != tt.out {
|
||||||
|
t.Errorf("RequestIsSmallerThanLimit expected: %#v, got: %#v", tt.out, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue