Commit f15d8528 authored by k8s-merge-robot's avatar k8s-merge-robot

Merge pull request #21603 from madhusudancs/scale-internal-autoscale

Auto commit by PR queue bot
parents bc37f34c b69ec9fa
......@@ -41,7 +41,8 @@ func init() {
}
testapi.Groups[testgroup.SchemeGroupVersion.Group] = testapi.NewTestGroup(
registered.GroupOrDie(testgroup.SchemeGroupVersion.Group).GroupVersion,
testgroup.SchemeGroupVersion)
testgroup.SchemeGroupVersion,
api.Scheme.KnownTypes(testgroup.SchemeGroupVersion))
testHelper = testapi.Groups[testgroup.SchemeGroupVersion.Group]
}
......
......@@ -153,7 +153,7 @@ func TestRoundTripTypes(t *testing.T) {
// defer api.Scheme.Log(nil)
for groupKey, group := range testapi.Groups {
for kind := range api.Scheme.KnownTypes(group.InternalGroupVersion()) {
for kind := range group.InternalTypes() {
t.Logf("working on %v in %v", kind, groupKey)
if nonRoundTrippableTypes.Has(kind) {
continue
......
......@@ -20,6 +20,7 @@ package testapi
import (
"fmt"
"os"
"reflect"
"strings"
"k8s.io/kubernetes/pkg/api"
......@@ -50,6 +51,7 @@ var (
type TestGroup struct {
externalGroupVersion unversioned.GroupVersion
internalGroupVersion unversioned.GroupVersion
internalTypes map[string]reflect.Type
}
func init() {
......@@ -62,9 +64,11 @@ func init() {
panic(fmt.Sprintf("Error parsing groupversion %v: %v", gvString, err))
}
internalGroupVersion := unversioned.GroupVersion{Group: groupVersion.Group, Version: runtime.APIVersionInternal}
Groups[groupVersion.Group] = TestGroup{
externalGroupVersion: groupVersion,
internalGroupVersion: unversioned.GroupVersion{Group: groupVersion.Group, Version: runtime.APIVersionInternal},
internalGroupVersion: internalGroupVersion,
internalTypes: api.Scheme.KnownTypes(internalGroupVersion),
}
}
}
......@@ -73,24 +77,49 @@ func init() {
Groups[api.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: api.GroupName, Version: registered.GroupOrDie(api.GroupName).GroupVersion.Version},
internalGroupVersion: api.SchemeGroupVersion,
internalTypes: api.Scheme.KnownTypes(api.SchemeGroupVersion),
}
}
if _, ok := Groups[extensions.GroupName]; !ok {
Groups[extensions.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: extensions.GroupName, Version: registered.GroupOrDie(extensions.GroupName).GroupVersion.Version},
internalGroupVersion: extensions.SchemeGroupVersion,
internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion),
}
}
if _, ok := Groups[autoscaling.GroupName]; !ok {
internalTypes := make(map[string]reflect.Type)
for k, t := range api.Scheme.KnownTypes(extensions.SchemeGroupVersion) {
if k == "Scale" {
continue
}
internalTypes[k] = t
}
Groups[autoscaling.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: autoscaling.GroupName, Version: registered.GroupOrDie(autoscaling.GroupName).GroupVersion.Version},
internalGroupVersion: extensions.SchemeGroupVersion,
internalTypes: internalTypes,
}
}
if _, ok := Groups[autoscaling.GroupName+"IntraGroup"]; !ok {
internalTypes := make(map[string]reflect.Type)
for k, t := range api.Scheme.KnownTypes(extensions.SchemeGroupVersion) {
if k == "Scale" {
internalTypes[k] = t
break
}
}
Groups[autoscaling.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: autoscaling.GroupName, Version: registered.GroupOrDie(autoscaling.GroupName).GroupVersion.Version},
internalGroupVersion: autoscaling.SchemeGroupVersion,
internalTypes: internalTypes,
}
}
if _, ok := Groups[batch.GroupName]; !ok {
Groups[batch.GroupName] = TestGroup{
externalGroupVersion: unversioned.GroupVersion{Group: batch.GroupName, Version: registered.GroupOrDie(batch.GroupName).GroupVersion.Version},
internalGroupVersion: extensions.SchemeGroupVersion,
internalTypes: api.Scheme.KnownTypes(extensions.SchemeGroupVersion),
}
}
......@@ -115,6 +144,11 @@ func (g TestGroup) InternalGroupVersion() unversioned.GroupVersion {
return g.internalGroupVersion
}
// InternalTypes returns a map of internal API types' kind names to their Go types.
func (g TestGroup) InternalTypes() map[string]reflect.Type {
return g.internalTypes
}
// Codec returns the codec for the API version to test against, as set by the
// KUBE_TEST_API env var.
func (g TestGroup) Codec() runtime.Codec {
......@@ -228,6 +262,6 @@ func GetCodecForObject(obj runtime.Object) (runtime.Codec, error) {
return nil, fmt.Errorf("unexpected kind: %v", kind)
}
func NewTestGroup(external, internal unversioned.GroupVersion) TestGroup {
return TestGroup{external, internal}
func NewTestGroup(external, internal unversioned.GroupVersion, internalTypes map[string]reflect.Type) TestGroup {
return TestGroup{external, internal, internalTypes}
}
......@@ -47,8 +47,11 @@ func AddToScheme(scheme *runtime.Scheme) {
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) {
scheme.AddKnownTypes(SchemeGroupVersion,
&Scale{},
&extensions.HorizontalPodAutoscaler{},
&extensions.HorizontalPodAutoscalerList{},
&api.ListOptions{},
)
}
func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 autoscaling
import (
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/unversioned"
)
// Scale represents a scaling request for a resource.
type Scale struct {
unversioned.TypeMeta `json:",inline"`
// Standard object metadata; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata.
api.ObjectMeta `json:"metadata,omitempty"`
// defines the behavior of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status.
Spec ScaleSpec `json:"spec,omitempty"`
// current status of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. Read-only.
Status ScaleStatus `json:"status,omitempty"`
}
// ScaleSpec describes the attributes of a scale subresource.
type ScaleSpec struct {
// desired number of instances for the scaled object.
Replicas int `json:"replicas,omitempty"`
}
// ScaleStatus represents the current status of a scale subresource.
type ScaleStatus struct {
// actual number of observed instances of the scaled object.
Replicas int `json:"replicas"`
// label query over pods that should match the replicas count. This is same
// as the label selector but in the string format to avoid introspection
// by clients. The string will be in the same format as the query-param syntax.
// More info: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
Selector string `json:"selector,omitempty"`
}
......@@ -24,6 +24,7 @@ import (
api "k8s.io/kubernetes/pkg/api"
unversioned "k8s.io/kubernetes/pkg/api/unversioned"
v1 "k8s.io/kubernetes/pkg/api/v1"
autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling"
extensions "k8s.io/kubernetes/pkg/apis/extensions"
conversion "k8s.io/kubernetes/pkg/conversion"
)
......@@ -132,6 +133,54 @@ func Convert_v1_ObjectMeta_To_api_ObjectMeta(in *v1.ObjectMeta, out *api.ObjectM
return autoConvert_v1_ObjectMeta_To_api_ObjectMeta(in, out, s)
}
func autoConvert_autoscaling_Scale_To_v1_Scale(in *autoscaling.Scale, out *Scale, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*autoscaling.Scale))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := Convert_api_ObjectMeta_To_v1_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
if err := Convert_autoscaling_ScaleSpec_To_v1_ScaleSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_autoscaling_ScaleStatus_To_v1_ScaleStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_autoscaling_Scale_To_v1_Scale(in *autoscaling.Scale, out *Scale, s conversion.Scope) error {
return autoConvert_autoscaling_Scale_To_v1_Scale(in, out, s)
}
func autoConvert_autoscaling_ScaleSpec_To_v1_ScaleSpec(in *autoscaling.ScaleSpec, out *ScaleSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*autoscaling.ScaleSpec))(in)
}
out.Replicas = int32(in.Replicas)
return nil
}
func Convert_autoscaling_ScaleSpec_To_v1_ScaleSpec(in *autoscaling.ScaleSpec, out *ScaleSpec, s conversion.Scope) error {
return autoConvert_autoscaling_ScaleSpec_To_v1_ScaleSpec(in, out, s)
}
func autoConvert_autoscaling_ScaleStatus_To_v1_ScaleStatus(in *autoscaling.ScaleStatus, out *ScaleStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*autoscaling.ScaleStatus))(in)
}
out.Replicas = int32(in.Replicas)
out.Selector = in.Selector
return nil
}
func Convert_autoscaling_ScaleStatus_To_v1_ScaleStatus(in *autoscaling.ScaleStatus, out *ScaleStatus, s conversion.Scope) error {
return autoConvert_autoscaling_ScaleStatus_To_v1_ScaleStatus(in, out, s)
}
func autoConvert_v1_HorizontalPodAutoscaler_To_extensions_HorizontalPodAutoscaler(in *HorizontalPodAutoscaler, out *extensions.HorizontalPodAutoscaler, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*HorizontalPodAutoscaler))(in)
......@@ -232,6 +281,54 @@ func Convert_v1_HorizontalPodAutoscalerStatus_To_extensions_HorizontalPodAutosca
return autoConvert_v1_HorizontalPodAutoscalerStatus_To_extensions_HorizontalPodAutoscalerStatus(in, out, s)
}
func autoConvert_v1_Scale_To_autoscaling_Scale(in *Scale, out *autoscaling.Scale, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*Scale))(in)
}
if err := api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
return err
}
if err := Convert_v1_ObjectMeta_To_api_ObjectMeta(&in.ObjectMeta, &out.ObjectMeta, s); err != nil {
return err
}
if err := Convert_v1_ScaleSpec_To_autoscaling_ScaleSpec(&in.Spec, &out.Spec, s); err != nil {
return err
}
if err := Convert_v1_ScaleStatus_To_autoscaling_ScaleStatus(&in.Status, &out.Status, s); err != nil {
return err
}
return nil
}
func Convert_v1_Scale_To_autoscaling_Scale(in *Scale, out *autoscaling.Scale, s conversion.Scope) error {
return autoConvert_v1_Scale_To_autoscaling_Scale(in, out, s)
}
func autoConvert_v1_ScaleSpec_To_autoscaling_ScaleSpec(in *ScaleSpec, out *autoscaling.ScaleSpec, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ScaleSpec))(in)
}
out.Replicas = int(in.Replicas)
return nil
}
func Convert_v1_ScaleSpec_To_autoscaling_ScaleSpec(in *ScaleSpec, out *autoscaling.ScaleSpec, s conversion.Scope) error {
return autoConvert_v1_ScaleSpec_To_autoscaling_ScaleSpec(in, out, s)
}
func autoConvert_v1_ScaleStatus_To_autoscaling_ScaleStatus(in *ScaleStatus, out *autoscaling.ScaleStatus, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*ScaleStatus))(in)
}
out.Replicas = int(in.Replicas)
out.Selector = in.Selector
return nil
}
func Convert_v1_ScaleStatus_To_autoscaling_ScaleStatus(in *ScaleStatus, out *autoscaling.ScaleStatus, s conversion.Scope) error {
return autoConvert_v1_ScaleStatus_To_autoscaling_ScaleStatus(in, out, s)
}
func autoConvert_extensions_HorizontalPodAutoscaler_To_v1_HorizontalPodAutoscaler(in *extensions.HorizontalPodAutoscaler, out *HorizontalPodAutoscaler, s conversion.Scope) error {
if defaulting, found := s.DefaultingInterface(reflect.TypeOf(*in)); found {
defaulting.(func(*extensions.HorizontalPodAutoscaler))(in)
......@@ -335,6 +432,9 @@ func Convert_extensions_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutosca
func init() {
err := api.Scheme.AddGeneratedConversionFuncs(
autoConvert_api_ObjectMeta_To_v1_ObjectMeta,
autoConvert_autoscaling_ScaleSpec_To_v1_ScaleSpec,
autoConvert_autoscaling_ScaleStatus_To_v1_ScaleStatus,
autoConvert_autoscaling_Scale_To_v1_Scale,
autoConvert_extensions_HorizontalPodAutoscalerList_To_v1_HorizontalPodAutoscalerList,
autoConvert_extensions_HorizontalPodAutoscalerSpec_To_v1_HorizontalPodAutoscalerSpec,
autoConvert_extensions_HorizontalPodAutoscalerStatus_To_v1_HorizontalPodAutoscalerStatus,
......@@ -344,6 +444,9 @@ func init() {
autoConvert_v1_HorizontalPodAutoscalerStatus_To_extensions_HorizontalPodAutoscalerStatus,
autoConvert_v1_HorizontalPodAutoscaler_To_extensions_HorizontalPodAutoscaler,
autoConvert_v1_ObjectMeta_To_api_ObjectMeta,
autoConvert_v1_ScaleSpec_To_autoscaling_ScaleSpec,
autoConvert_v1_ScaleStatus_To_autoscaling_ScaleStatus,
autoConvert_v1_Scale_To_autoscaling_Scale,
)
if err != nil {
// If one of the conversion functions is malformed, detect it immediately.
......
......@@ -181,6 +181,33 @@ func deepCopy_v1_HorizontalPodAutoscalerStatus(in HorizontalPodAutoscalerStatus,
return nil
}
func deepCopy_v1_Scale(in Scale, out *Scale, c *conversion.Cloner) error {
if err := deepCopy_unversioned_TypeMeta(in.TypeMeta, &out.TypeMeta, c); err != nil {
return err
}
if err := deepCopy_v1_ObjectMeta(in.ObjectMeta, &out.ObjectMeta, c); err != nil {
return err
}
if err := deepCopy_v1_ScaleSpec(in.Spec, &out.Spec, c); err != nil {
return err
}
if err := deepCopy_v1_ScaleStatus(in.Status, &out.Status, c); err != nil {
return err
}
return nil
}
func deepCopy_v1_ScaleSpec(in ScaleSpec, out *ScaleSpec, c *conversion.Cloner) error {
out.Replicas = in.Replicas
return nil
}
func deepCopy_v1_ScaleStatus(in ScaleStatus, out *ScaleStatus, c *conversion.Cloner) error {
out.Replicas = in.Replicas
out.Selector = in.Selector
return nil
}
func init() {
err := api.Scheme.AddGeneratedDeepCopyFuncs(
deepCopy_unversioned_ListMeta,
......@@ -192,6 +219,9 @@ func init() {
deepCopy_v1_HorizontalPodAutoscalerList,
deepCopy_v1_HorizontalPodAutoscalerSpec,
deepCopy_v1_HorizontalPodAutoscalerStatus,
deepCopy_v1_Scale,
deepCopy_v1_ScaleSpec,
deepCopy_v1_ScaleStatus,
)
if err != nil {
// if one of the deep copy functions is malformed, detect it immediately.
......
......@@ -39,9 +39,11 @@ func addKnownTypes(scheme *runtime.Scheme) {
scheme.AddKnownTypes(SchemeGroupVersion,
&HorizontalPodAutoscaler{},
&HorizontalPodAutoscalerList{},
&Scale{},
&v1.ListOptions{},
)
}
func (obj *HorizontalPodAutoscaler) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *HorizontalPodAutoscalerList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
func (obj *Scale) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
......@@ -86,3 +86,34 @@ type HorizontalPodAutoscalerList struct {
// list of horizontal pod autoscaler objects.
Items []HorizontalPodAutoscaler `json:"items"`
}
// Scale represents a scaling request for a resource.
type Scale struct {
unversioned.TypeMeta `json:",inline"`
// Standard object metadata; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata.
v1.ObjectMeta `json:"metadata,omitempty"`
// defines the behavior of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status.
Spec ScaleSpec `json:"spec,omitempty"`
// current status of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. Read-only.
Status ScaleStatus `json:"status,omitempty"`
}
// ScaleSpec describes the attributes of a scale subresource.
type ScaleSpec struct {
// desired number of instances for the scaled object.
Replicas int32 `json:"replicas,omitempty"`
}
// ScaleStatus represents the current status of a scale subresource.
type ScaleStatus struct {
// actual number of observed instances of the scaled object.
Replicas int32 `json:"replicas"`
// label query over pods that should match the replicas count. This is same
// as the label selector but in the string format to avoid introspection
// by clients. The string will be in the same format as the query-param syntax.
// More info about label selectors: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors
Selector string `json:"selector,omitempty"`
}
......@@ -84,4 +84,34 @@ func (HorizontalPodAutoscalerStatus) SwaggerDoc() map[string]string {
return map_HorizontalPodAutoscalerStatus
}
var map_Scale = map[string]string{
"": "Scale represents a scaling request for a resource.",
"metadata": "Standard object metadata; More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata.",
"spec": "defines the behavior of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status.",
"status": "current status of the scale. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#spec-and-status. Read-only.",
}
func (Scale) SwaggerDoc() map[string]string {
return map_Scale
}
var map_ScaleSpec = map[string]string{
"": "ScaleSpec describes the attributes of a scale subresource.",
"replicas": "desired number of instances for the scaled object.",
}
func (ScaleSpec) SwaggerDoc() map[string]string {
return map_ScaleSpec
}
var map_ScaleStatus = map[string]string{
"": "ScaleStatus represents the current status of a scale subresource.",
"replicas": "actual number of observed instances of the scaled object.",
"selector": "label query over pods that should match the replicas count. This is same as the label selector but in the string format to avoid introspection by clients. The string will be in the same format as the query-param syntax. More info about label selectors: http://releases.k8s.io/HEAD/docs/user-guide/labels.md#label-selectors",
}
func (ScaleStatus) SwaggerDoc() map[string]string {
return map_ScaleStatus
}
// AUTO-GENERATED FUNCTIONS END HERE
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 validation
import (
apivalidation "k8s.io/kubernetes/pkg/api/validation"
"k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/util/validation/field"
)
func ValidateScale(scale *autoscaling.Scale) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&scale.ObjectMeta, true, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...)
if scale.Spec.Replicas < 0 {
allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "replicas"), scale.Spec.Replicas, "must be greater than or equal to 0"))
}
return allErrs
}
/*
Copyright 2016 The Kubernetes Authors All rights reserved.
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 validation
import (
"strings"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/apis/autoscaling"
)
func TestValidateScale(t *testing.T) {
successCases := []autoscaling.Scale{
{
ObjectMeta: api.ObjectMeta{
Name: "frontend",
Namespace: api.NamespaceDefault,
},
Spec: autoscaling.ScaleSpec{
Replicas: 1,
},
},
{
ObjectMeta: api.ObjectMeta{
Name: "frontend",
Namespace: api.NamespaceDefault,
},
Spec: autoscaling.ScaleSpec{
Replicas: 10,
},
},
{
ObjectMeta: api.ObjectMeta{
Name: "frontend",
Namespace: api.NamespaceDefault,
},
Spec: autoscaling.ScaleSpec{
Replicas: 0,
},
},
}
for _, successCase := range successCases {
if errs := ValidateScale(&successCase); len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
}
errorCases := []struct {
scale autoscaling.Scale
msg string
}{
{
scale: autoscaling.Scale{
ObjectMeta: api.ObjectMeta{
Name: "frontend",
Namespace: api.NamespaceDefault,
},
Spec: autoscaling.ScaleSpec{
Replicas: -1,
},
},
msg: "must be greater than or equal to 0",
},
}
for _, c := range errorCases {
if errs := ValidateScale(&c.scale); len(errs) == 0 {
t.Errorf("expected failure for %s", c.msg)
} else if !strings.Contains(errs[0].Error(), c.msg) {
t.Errorf("unexpected error: %v, expected: %s", errs[0], c.msg)
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment