Move pkg/kubectl/util to staging
Kubernetes-commit: 7083332c634d540c2769b48e32fc4afb8f4f6cd7
This commit is contained in:
parent
08c6807d9a
commit
29453805d1
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes 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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// LookupContainerPortNumberByName find containerPort number by its named port name
|
||||
func LookupContainerPortNumberByName(pod v1.Pod, name string) (int32, error) {
|
||||
for _, ctr := range pod.Spec.Containers {
|
||||
for _, ctrportspec := range ctr.Ports {
|
||||
if ctrportspec.Name == name {
|
||||
return ctrportspec.ContainerPort, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return int32(-1), fmt.Errorf("Pod '%s' does not have a named port '%s'", pod.Name, name)
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes 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 util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
func TestLookupContainerPortNumberByName(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pod v1.Pod
|
||||
portname string
|
||||
portnum int32
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
name: "test success 1",
|
||||
pod: v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "https",
|
||||
ContainerPort: int32(443)},
|
||||
{
|
||||
Name: "http",
|
||||
ContainerPort: int32(80)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
portname: "http",
|
||||
portnum: int32(80),
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "test faulure 1",
|
||||
pod: v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "https",
|
||||
ContainerPort: int32(443)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
portname: "www",
|
||||
portnum: int32(0),
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
portnum, err := LookupContainerPortNumberByName(tt.pod, tt.portname)
|
||||
if err != nil {
|
||||
if tt.err {
|
||||
return
|
||||
}
|
||||
|
||||
t.Errorf("%v: unexpected error: %v", tt.name, err)
|
||||
return
|
||||
}
|
||||
|
||||
if tt.err {
|
||||
t.Errorf("%v: unexpected success", tt.name)
|
||||
return
|
||||
}
|
||||
|
||||
if portnum != tt.portnum {
|
||||
t.Errorf("%v: expected port number %v; got %v", tt.name, tt.portnum, portnum)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes 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 util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
// LookupContainerPortNumberByServicePort implements
|
||||
// the handling of resolving container named port, as well as ignoring targetPort when clusterIP=None
|
||||
// It returns an error when a named port can't find a match (with -1 returned), or when the service does not
|
||||
// declare such port (with the input port number returned).
|
||||
func LookupContainerPortNumberByServicePort(svc v1.Service, pod v1.Pod, port int32) (int32, error) {
|
||||
for _, svcportspec := range svc.Spec.Ports {
|
||||
if svcportspec.Port != port {
|
||||
continue
|
||||
}
|
||||
if svc.Spec.ClusterIP == v1.ClusterIPNone {
|
||||
return port, nil
|
||||
}
|
||||
if svcportspec.TargetPort.Type == intstr.Int {
|
||||
if svcportspec.TargetPort.IntValue() == 0 {
|
||||
// targetPort is omitted, and the IntValue() would be zero
|
||||
return svcportspec.Port, nil
|
||||
}
|
||||
return int32(svcportspec.TargetPort.IntValue()), nil
|
||||
}
|
||||
return LookupContainerPortNumberByName(pod, svcportspec.TargetPort.String())
|
||||
}
|
||||
return port, fmt.Errorf("Service %s does not have a service port %d", svc.Name, port)
|
||||
}
|
||||
|
||||
// LookupServicePortNumberByName find service port number by its named port name
|
||||
func LookupServicePortNumberByName(svc v1.Service, name string) (int32, error) {
|
||||
for _, svcportspec := range svc.Spec.Ports {
|
||||
if svcportspec.Name == name {
|
||||
return svcportspec.Port, nil
|
||||
}
|
||||
}
|
||||
|
||||
return int32(-1), fmt.Errorf("Service '%s' does not have a named port '%s'", svc.Name, name)
|
||||
}
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
Copyright 2018 The Kubernetes 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 util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/util/intstr"
|
||||
)
|
||||
|
||||
func TestLookupContainerPortNumberByServicePort(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
svc v1.Service
|
||||
pod v1.Pod
|
||||
port int32
|
||||
containerPort int32
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
name: "test success 1 (int port)",
|
||||
svc: v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Ports: []v1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromInt(8080),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pod: v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "http",
|
||||
ContainerPort: int32(8080)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
port: 80,
|
||||
containerPort: 8080,
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "test success 2 (clusterIP: None)",
|
||||
svc: v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
ClusterIP: v1.ClusterIPNone,
|
||||
Ports: []v1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromInt(8080),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pod: v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "http",
|
||||
ContainerPort: int32(8080)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
port: 80,
|
||||
containerPort: 80,
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "test success 3 (named port)",
|
||||
svc: v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Ports: []v1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromString("http"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pod: v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "http",
|
||||
ContainerPort: int32(8080)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
port: 80,
|
||||
containerPort: 8080,
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "test success (targetPort omitted)",
|
||||
svc: v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Ports: []v1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pod: v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "http",
|
||||
ContainerPort: int32(80)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
port: 80,
|
||||
containerPort: 80,
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "test failure 1 (cannot find a matching named port)",
|
||||
svc: v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Ports: []v1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromString("http"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pod: v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "https",
|
||||
ContainerPort: int32(443)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
port: 80,
|
||||
containerPort: -1,
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "test failure 2 (cannot find a matching service port)",
|
||||
svc: v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
Ports: []v1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromString("http"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pod: v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "https",
|
||||
ContainerPort: int32(443)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
port: 443,
|
||||
containerPort: 443,
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "test failure 2 (cannot find a matching service port, but ClusterIP: None)",
|
||||
svc: v1.Service{
|
||||
Spec: v1.ServiceSpec{
|
||||
ClusterIP: v1.ClusterIPNone,
|
||||
Ports: []v1.ServicePort{
|
||||
{
|
||||
Port: 80,
|
||||
TargetPort: intstr.FromString("http"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
pod: v1.Pod{
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{
|
||||
{
|
||||
Ports: []v1.ContainerPort{
|
||||
{
|
||||
Name: "http",
|
||||
ContainerPort: int32(80)},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
port: 443,
|
||||
containerPort: 443,
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
containerPort, err := LookupContainerPortNumberByServicePort(tt.svc, tt.pod, tt.port)
|
||||
if err != nil {
|
||||
if tt.err {
|
||||
if containerPort != tt.containerPort {
|
||||
t.Errorf("%v: expected port %v; got %v", tt.name, tt.containerPort, containerPort)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
t.Errorf("%v: unexpected error: %v", tt.name, err)
|
||||
return
|
||||
}
|
||||
|
||||
if tt.err {
|
||||
t.Errorf("%v: unexpected success", tt.name)
|
||||
return
|
||||
}
|
||||
|
||||
if containerPort != tt.containerPort {
|
||||
t.Errorf("%v: expected port %v; got %v", tt.name, tt.containerPort, containerPort)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// +build !windows
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes 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 util
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Umask is a wrapper for `unix.Umask()` on non-Windows platforms
|
||||
func Umask(mask int) (old int, err error) {
|
||||
return unix.Umask(mask), nil
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// +build windows
|
||||
|
||||
/*
|
||||
Copyright 2014 The Kubernetes 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 util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// Umask returns an error on Windows
|
||||
func Umask(mask int) (int, error) {
|
||||
return 0, errors.New("platform and architecture is not supported")
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
Copyright 2017 The Kubernetes 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 util
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// ParseRFC3339 parses an RFC3339 date in either RFC3339Nano or RFC3339 format.
|
||||
func ParseRFC3339(s string, nowFn func() metav1.Time) (metav1.Time, error) {
|
||||
if t, timeErr := time.Parse(time.RFC3339Nano, s); timeErr == nil {
|
||||
return metav1.Time{Time: t}, nil
|
||||
}
|
||||
t, err := time.Parse(time.RFC3339, s)
|
||||
if err != nil {
|
||||
return metav1.Time{}, err
|
||||
}
|
||||
return metav1.Time{Time: t}, nil
|
||||
}
|
||||
|
||||
// HashObject returns the hash of a Object hash by a Codec
|
||||
func HashObject(obj runtime.Object, codec runtime.Codec) (string, error) {
|
||||
data, err := runtime.Encode(codec, obj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%x", md5.Sum(data)), nil
|
||||
}
|
||||
|
||||
// ParseFileSource parses the source given.
|
||||
//
|
||||
// Acceptable formats include:
|
||||
// 1. source-path: the basename will become the key name
|
||||
// 2. source-name=source-path: the source-name will become the key name and
|
||||
// source-path is the path to the key file.
|
||||
//
|
||||
// Key names cannot include '='.
|
||||
func ParseFileSource(source string) (keyName, filePath string, err error) {
|
||||
numSeparators := strings.Count(source, "=")
|
||||
switch {
|
||||
case numSeparators == 0:
|
||||
return path.Base(filepath.ToSlash(source)), source, nil
|
||||
case numSeparators == 1 && strings.HasPrefix(source, "="):
|
||||
return "", "", fmt.Errorf("key name for file path %v missing", strings.TrimPrefix(source, "="))
|
||||
case numSeparators == 1 && strings.HasSuffix(source, "="):
|
||||
return "", "", fmt.Errorf("file path for key name %v missing", strings.TrimSuffix(source, "="))
|
||||
case numSeparators > 1:
|
||||
return "", "", errors.New("Key names or file paths cannot contain '='")
|
||||
default:
|
||||
components := strings.Split(source, "=")
|
||||
return components[0], components[1], nil
|
||||
}
|
||||
}
|
||||
|
||||
// ParseLiteralSource parses the source key=val pair into its component pieces.
|
||||
// This functionality is distinguished from strings.SplitN(source, "=", 2) since
|
||||
// it returns an error in the case of empty keys, values, or a missing equals sign.
|
||||
func ParseLiteralSource(source string) (keyName, value string, err error) {
|
||||
// leading equal is invalid
|
||||
if strings.Index(source, "=") == 0 {
|
||||
return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
|
||||
}
|
||||
// split after the first equal (so values can have the = character)
|
||||
items := strings.SplitN(source, "=", 2)
|
||||
if len(items) != 2 {
|
||||
return "", "", fmt.Errorf("invalid literal source %v, expected key=value", source)
|
||||
}
|
||||
|
||||
return items[0], items[1], nil
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
Copyright 2016 The Kubernetes 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 util
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestParseFileSource(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
key string
|
||||
filepath string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
name: "success 1",
|
||||
input: "boo=zoo",
|
||||
key: "boo",
|
||||
filepath: "zoo",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "success 2",
|
||||
input: "boo=/path/to/zoo",
|
||||
key: "boo",
|
||||
filepath: "/path/to/zoo",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "success 3",
|
||||
input: "boo-2=/1/2/3/4/5/zab.txt",
|
||||
key: "boo-2",
|
||||
filepath: "/1/2/3/4/5/zab.txt",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "success 4",
|
||||
input: "boo-=this/seems/weird.txt",
|
||||
key: "boo-",
|
||||
filepath: "this/seems/weird.txt",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "success 5",
|
||||
input: "-key=some/path",
|
||||
key: "-key",
|
||||
filepath: "some/path",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "invalid 1",
|
||||
input: "key==some/path",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "invalid 2",
|
||||
input: "=key=some/path",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "invalid 3",
|
||||
input: "==key=/some/other/path",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "invalid 4",
|
||||
input: "=key",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "invalid 5",
|
||||
input: "key=",
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
key, filepath, err := ParseFileSource(tt.input)
|
||||
if err != nil {
|
||||
if tt.err {
|
||||
return
|
||||
}
|
||||
|
||||
t.Errorf("%v: unexpected error: %v", tt.name, err)
|
||||
return
|
||||
}
|
||||
|
||||
if tt.err {
|
||||
t.Errorf("%v: unexpected success", tt.name)
|
||||
return
|
||||
}
|
||||
|
||||
if e, a := tt.key, key; e != a {
|
||||
t.Errorf("%v: expected key %v; got %v", tt.name, e, a)
|
||||
return
|
||||
}
|
||||
|
||||
if e, a := tt.filepath, filepath; e != a {
|
||||
t.Errorf("%v: expected filepath %v; got %v", tt.name, e, a)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseLiteralSource(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
key string
|
||||
value string
|
||||
err bool
|
||||
}{
|
||||
{
|
||||
name: "success 1",
|
||||
input: "key=value",
|
||||
key: "key",
|
||||
value: "value",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "success 2",
|
||||
input: "key=value/with/slashes",
|
||||
key: "key",
|
||||
value: "value/with/slashes",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "err 1",
|
||||
input: "key==value",
|
||||
key: "key",
|
||||
value: "=value",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "err 2",
|
||||
input: "key=value=",
|
||||
key: "key",
|
||||
value: "value=",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "err 3",
|
||||
input: "key2=value==",
|
||||
key: "key2",
|
||||
value: "value==",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "err 4",
|
||||
input: "==key",
|
||||
err: true,
|
||||
},
|
||||
{
|
||||
name: "err 5",
|
||||
input: "=key=",
|
||||
err: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
key, value, err := ParseLiteralSource(tt.input)
|
||||
if err != nil {
|
||||
if tt.err {
|
||||
return
|
||||
}
|
||||
|
||||
t.Errorf("%v: unexpected error: %v", tt.name, err)
|
||||
return
|
||||
}
|
||||
|
||||
if tt.err {
|
||||
t.Errorf("%v: unexpected success", tt.name)
|
||||
return
|
||||
}
|
||||
|
||||
if e, a := tt.key, key; e != a {
|
||||
t.Errorf("%v: expected key %v; got %v", tt.name, e, a)
|
||||
return
|
||||
}
|
||||
|
||||
if e, a := tt.value, value; e != a {
|
||||
t.Errorf("%v: expected value %v; got %v", tt.name, e, a)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue