Tests for Specs and Teams API
This commit is contained in:
parent
bc0e9ab4bc
commit
bdc2db97ac
|
|
@ -0,0 +1,485 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/client-go/pkg/api/unversioned"
|
||||||
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
var parseTimeTests = []struct {
|
||||||
|
in string
|
||||||
|
out time.Time
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"16:08", mustParseTime("16:08"), nil},
|
||||||
|
{"11:00", mustParseTime("11:00"), nil},
|
||||||
|
{"23:59", mustParseTime("23:59"), nil},
|
||||||
|
|
||||||
|
{"26:09", time.Now(), errors.New(`parsing time "26:09": hour out of range`)},
|
||||||
|
{"23:69", time.Now(), errors.New(`parsing time "23:69": minute out of range`)},
|
||||||
|
}
|
||||||
|
|
||||||
|
var parseWeekdayTests = []struct {
|
||||||
|
in string
|
||||||
|
out time.Weekday
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"Wed", time.Wednesday, nil},
|
||||||
|
{"Sunday", time.Weekday(0), errors.New("incorrect weekday")},
|
||||||
|
{"", time.Weekday(0), errors.New("incorrect weekday")},
|
||||||
|
}
|
||||||
|
|
||||||
|
var clusterNames = []struct {
|
||||||
|
in string
|
||||||
|
inTeam string
|
||||||
|
clusterName string
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"acid-test", "acid", "test", nil},
|
||||||
|
{"test-my-name", "test", "my-name", nil},
|
||||||
|
{"my-team-another-test", "my-team", "another-test", nil},
|
||||||
|
{"------strange-team-cluster", "-----", "strange-team-cluster", nil},
|
||||||
|
{"acid-test", "test", "", errors.New("name must match {TEAM}-{NAME} format")},
|
||||||
|
{"-test", "", "", errors.New("team name is empty")},
|
||||||
|
{"-test", "-", "", errors.New("name must match {TEAM}-{NAME} format")},
|
||||||
|
{"", "-", "", errors.New("name is too short")},
|
||||||
|
{"-", "-", "", errors.New("name is too short")},
|
||||||
|
}
|
||||||
|
|
||||||
|
var maintenanceWindows = []struct {
|
||||||
|
in []byte
|
||||||
|
out MaintenanceWindow
|
||||||
|
err error
|
||||||
|
}{{[]byte(`"Tue:10:00-20:00"`),
|
||||||
|
MaintenanceWindow{
|
||||||
|
Everyday: false,
|
||||||
|
Weekday: time.Tuesday,
|
||||||
|
StartTime: mustParseTime("10:00"),
|
||||||
|
EndTime: mustParseTime("20:00"),
|
||||||
|
}, nil},
|
||||||
|
{[]byte(`"Mon:10:00-10:00"`),
|
||||||
|
MaintenanceWindow{
|
||||||
|
Everyday: false,
|
||||||
|
Weekday: time.Monday,
|
||||||
|
StartTime: mustParseTime("10:00"),
|
||||||
|
EndTime: mustParseTime("10:00"),
|
||||||
|
}, nil},
|
||||||
|
{[]byte(`"Sun:00:00-00:00"`),
|
||||||
|
MaintenanceWindow{
|
||||||
|
Everyday: false,
|
||||||
|
Weekday: time.Sunday,
|
||||||
|
StartTime: mustParseTime("00:00"),
|
||||||
|
EndTime: mustParseTime("00:00"),
|
||||||
|
}, nil},
|
||||||
|
{[]byte(`"01:00-10:00"`),
|
||||||
|
MaintenanceWindow{
|
||||||
|
Everyday: true,
|
||||||
|
Weekday: time.Sunday,
|
||||||
|
StartTime: mustParseTime("01:00"),
|
||||||
|
EndTime: mustParseTime("10:00"),
|
||||||
|
}, nil},
|
||||||
|
{[]byte(`"Mon:12:00-11:00"`), MaintenanceWindow{}, errors.New(`'From' time must be prior to the 'To' time`)},
|
||||||
|
{[]byte(`"Wed:33:00-00:00"`), MaintenanceWindow{}, errors.New(`could not parse start time: parsing time "33:00": hour out of range`)},
|
||||||
|
{[]byte(`"Wed:00:00-26:00"`), MaintenanceWindow{}, errors.New(`could not parse end time: parsing time "26:00": hour out of range`)},
|
||||||
|
{[]byte(`"Sunday:00:00-00:00"`), MaintenanceWindow{}, errors.New(`could not parse weekday: incorrect weekday`)},
|
||||||
|
{[]byte(`":00:00-10:00"`), MaintenanceWindow{}, errors.New(`could not parse weekday: incorrect weekday`)},
|
||||||
|
{[]byte(`"Mon:10:00-00:00"`), MaintenanceWindow{}, errors.New(`'From' time must be prior to the 'To' time`)},
|
||||||
|
{[]byte(`"Mon:00:00:00-10:00:00"`), MaintenanceWindow{}, errors.New(`incorrect maintenance window format`)},
|
||||||
|
{[]byte(`"Mon:00:00"`), MaintenanceWindow{}, errors.New("incorrect maintenance window format")},
|
||||||
|
{[]byte(`"Mon:00:00-00:00:00"`), MaintenanceWindow{}, errors.New("could not parse end time: incorrect time format")}}
|
||||||
|
|
||||||
|
var unmarshalCluster = []struct {
|
||||||
|
in []byte
|
||||||
|
out Postgresql
|
||||||
|
marshal []byte
|
||||||
|
err error
|
||||||
|
}{{
|
||||||
|
[]byte(`{
|
||||||
|
"kind": "Postgresql","apiVersion": "acid.zalan.do/v1",
|
||||||
|
"metadata": {"name": "acid-testcluster1"}, "spec": {"teamId": 100}}`),
|
||||||
|
Postgresql{
|
||||||
|
TypeMeta: unversioned.TypeMeta{
|
||||||
|
Kind: "Postgresql",
|
||||||
|
APIVersion: "acid.zalan.do/v1",
|
||||||
|
},
|
||||||
|
Metadata: v1.ObjectMeta{
|
||||||
|
Name: "acid-testcluster1",
|
||||||
|
},
|
||||||
|
Status: ClusterStatusInvalid,
|
||||||
|
Error: &json.UnmarshalTypeError{
|
||||||
|
Value: "number",
|
||||||
|
Type: reflect.TypeOf(""),
|
||||||
|
Offset: 126,
|
||||||
|
Struct: "PostgresSpec",
|
||||||
|
Field: "teamId",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"","parameters":null},"volume":{"size":"","storageClass":""},"patroni":{"initdb":null,"pg_hba":null,"ttl":0,"loop_wait":0,"retry_timeout":0,"maximum_lag_on_failover":0},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"","allowedSourceRanges":null,"numberOfInstances":0,"users":null},"status":"Invalid"}`), nil},
|
||||||
|
{[]byte(`{
|
||||||
|
"kind": "Postgresql",
|
||||||
|
"apiVersion": "acid.zalan.do/v1",
|
||||||
|
"metadata": {
|
||||||
|
"name": "acid-testcluster1"
|
||||||
|
},
|
||||||
|
"spec": {
|
||||||
|
"teamId": "ACID",
|
||||||
|
"volume": {
|
||||||
|
"size": "5Gi",
|
||||||
|
"storageClass": "SSD"
|
||||||
|
},
|
||||||
|
"numberOfInstances": 2,
|
||||||
|
"users": {
|
||||||
|
"zalando": [
|
||||||
|
"superuser",
|
||||||
|
"createdb"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"allowedSourceRanges": [
|
||||||
|
"127.0.0.1/32"
|
||||||
|
],
|
||||||
|
"postgresql": {
|
||||||
|
"version": "9.6",
|
||||||
|
"parameters": {
|
||||||
|
"shared_buffers": "32MB",
|
||||||
|
"max_connections": "10",
|
||||||
|
"log_statement": "all"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resources": {
|
||||||
|
"requests": {
|
||||||
|
"cpu": "10m",
|
||||||
|
"memory": "50Mi"
|
||||||
|
},
|
||||||
|
"limits": {
|
||||||
|
"cpu": "300m",
|
||||||
|
"memory": "3000Mi"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patroni": {
|
||||||
|
"initdb": {
|
||||||
|
"encoding": "UTF8",
|
||||||
|
"locale": "en_US.UTF-8",
|
||||||
|
"data-checksums": "true"
|
||||||
|
},
|
||||||
|
"pg_hba": [
|
||||||
|
"hostssl all all 0.0.0.0/0 md5",
|
||||||
|
"host all all 0.0.0.0/0 md5"
|
||||||
|
],
|
||||||
|
"ttl": 30,
|
||||||
|
"loop_wait": 10,
|
||||||
|
"retry_timeout": 10,
|
||||||
|
"maximum_lag_on_failover": 33554432
|
||||||
|
},
|
||||||
|
"maintenanceWindows": [
|
||||||
|
"Mon:01:00-06:00",
|
||||||
|
"Sat:00:00-04:00",
|
||||||
|
"05:00-05:15"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}`),
|
||||||
|
Postgresql{
|
||||||
|
TypeMeta: unversioned.TypeMeta{
|
||||||
|
Kind: "Postgresql",
|
||||||
|
APIVersion: "acid.zalan.do/v1",
|
||||||
|
},
|
||||||
|
Metadata: v1.ObjectMeta{
|
||||||
|
Name: "acid-testcluster1",
|
||||||
|
},
|
||||||
|
Spec: PostgresSpec{
|
||||||
|
PostgresqlParam: PostgresqlParam{
|
||||||
|
PgVersion: "9.6",
|
||||||
|
Parameters: map[string]string{
|
||||||
|
"shared_buffers": "32MB",
|
||||||
|
"max_connections": "10",
|
||||||
|
"log_statement": "all",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Volume: Volume{
|
||||||
|
Size: "5Gi",
|
||||||
|
StorageClass: "SSD",
|
||||||
|
},
|
||||||
|
Patroni: Patroni{
|
||||||
|
InitDB: map[string]string{
|
||||||
|
"encoding": "UTF8",
|
||||||
|
"locale": "en_US.UTF-8",
|
||||||
|
"data-checksums": "true",
|
||||||
|
},
|
||||||
|
PgHba: []string{"hostssl all all 0.0.0.0/0 md5", "host all all 0.0.0.0/0 md5"},
|
||||||
|
TTL: 30,
|
||||||
|
LoopWait: 10,
|
||||||
|
RetryTimeout: 10,
|
||||||
|
MaximumLagOnFailover: 33554432,
|
||||||
|
},
|
||||||
|
Resources: Resources{
|
||||||
|
ResourceRequest: ResourceDescription{CPU: "10m", Memory: "50Mi"},
|
||||||
|
ResourceLimits: ResourceDescription{CPU: "300m", Memory: "3000Mi"},
|
||||||
|
},
|
||||||
|
TeamID: "ACID",
|
||||||
|
AllowedSourceRanges: []string{"127.0.0.1/32"},
|
||||||
|
NumberOfInstances: 2,
|
||||||
|
Users: map[string]UserFlags{"zalando": {"superuser", "createdb"}},
|
||||||
|
MaintenanceWindows: []MaintenanceWindow{{
|
||||||
|
Everyday: false,
|
||||||
|
Weekday: time.Monday,
|
||||||
|
StartTime: mustParseTime("01:00"),
|
||||||
|
EndTime: mustParseTime("06:00"),
|
||||||
|
}, {
|
||||||
|
Everyday: false,
|
||||||
|
Weekday: time.Saturday,
|
||||||
|
StartTime: mustParseTime("00:00"),
|
||||||
|
EndTime: mustParseTime("04:00"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Everyday: true,
|
||||||
|
Weekday: time.Sunday,
|
||||||
|
StartTime: mustParseTime("05:00"),
|
||||||
|
EndTime: mustParseTime("05:15"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ClusterName: "testcluster1",
|
||||||
|
},
|
||||||
|
Error: nil,
|
||||||
|
},
|
||||||
|
[]byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"9.6","parameters":{"log_statement":"all","max_connections":"10","shared_buffers":"32MB"}},"volume":{"size":"5Gi","storageClass":"SSD"},"patroni":{"initdb":{"data-checksums":"true","encoding":"UTF8","locale":"en_US.UTF-8"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432},"resources":{"requests":{"cpu":"10m","memory":"50Mi"},"limits":{"cpu":"300m","memory":"3000Mi"}},"teamId":"ACID","allowedSourceRanges":["127.0.0.1/32"],"numberOfInstances":2,"users":{"zalando":["superuser","createdb"]},"maintenanceWindows":["Mon:01:00-06:00","Sat:00:00-04:00","05:00-05:15"]}}`), nil},
|
||||||
|
{
|
||||||
|
[]byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1","metadata": {"name": "teapot-testcluster1"}, "spec": {"teamId": "acid"}}`),
|
||||||
|
Postgresql{
|
||||||
|
TypeMeta: unversioned.TypeMeta{
|
||||||
|
Kind: "Postgresql",
|
||||||
|
APIVersion: "acid.zalan.do/v1",
|
||||||
|
},
|
||||||
|
Metadata: v1.ObjectMeta{
|
||||||
|
Name: "teapot-testcluster1",
|
||||||
|
},
|
||||||
|
Spec: PostgresSpec{TeamID: "acid"},
|
||||||
|
Status: ClusterStatusInvalid,
|
||||||
|
Error: errors.New("name must match {TEAM}-{NAME} format"),
|
||||||
|
},
|
||||||
|
[]byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"teapot-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"","parameters":null},"volume":{"size":"","storageClass":""},"patroni":{"initdb":null,"pg_hba":null,"ttl":0,"loop_wait":0,"retry_timeout":0,"maximum_lag_on_failover":0},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"acid","allowedSourceRanges":null,"numberOfInstances":0,"users":null},"status":"Invalid"}`), nil},
|
||||||
|
{[]byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1"`),
|
||||||
|
Postgresql{},
|
||||||
|
[]byte{},
|
||||||
|
errors.New("unexpected end of JSON input")},
|
||||||
|
{[]byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster","creationTimestamp":qaz},"spec":{"postgresql":{"version":"","parameters":null},"volume":{"size":"","storageClass":""},"patroni":{"initdb":null,"pg_hba":null,"ttl":0,"loop_wait":0,"retry_timeout":0,"maximum_lag_on_failover":0},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"acid","allowedSourceRanges":null,"numberOfInstances":0,"users":null},"status":"Invalid"}`),
|
||||||
|
Postgresql{},
|
||||||
|
[]byte{},
|
||||||
|
errors.New("invalid character 'q' looking for beginning of value")}}
|
||||||
|
|
||||||
|
var postgresqlList = []struct {
|
||||||
|
in []byte
|
||||||
|
out PostgresqlList
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{[]byte(`{"apiVersion":"v1","items":[{"apiVersion":"acid.zalan.do/v1","kind":"Postgresql","metadata":{"labels":{"team":"acid"},"name":"acid-testcluster42","namespace":"default","resourceVersion":"30446957","selfLink":"/apis/acid.zalan.do/v1/namespaces/default/postgresqls/acid-testcluster42","uid":"857cd208-33dc-11e7-b20a-0699041e4b03"},"spec":{"allowedSourceRanges":["185.85.220.0/22"],"numberOfInstances":1,"postgresql":{"version":"9.6"},"teamId":"acid","volume":{"size":"10Gi"}},"status":"Running"}],"kind":"List","metadata":{},"resourceVersion":"","selfLink":""}`),
|
||||||
|
PostgresqlList{
|
||||||
|
TypeMeta: unversioned.TypeMeta{
|
||||||
|
Kind: "List",
|
||||||
|
APIVersion: "v1",
|
||||||
|
},
|
||||||
|
Items: []Postgresql{Postgresql{
|
||||||
|
TypeMeta: unversioned.TypeMeta{
|
||||||
|
Kind: "Postgresql",
|
||||||
|
APIVersion: "acid.zalan.do/v1",
|
||||||
|
},
|
||||||
|
Metadata: v1.ObjectMeta{
|
||||||
|
Name: "acid-testcluster42",
|
||||||
|
Namespace: "default",
|
||||||
|
Labels: map[string]string{"team": "acid"},
|
||||||
|
ResourceVersion: "30446957",
|
||||||
|
SelfLink: "/apis/acid.zalan.do/v1/namespaces/default/postgresqls/acid-testcluster42",
|
||||||
|
UID: "857cd208-33dc-11e7-b20a-0699041e4b03",
|
||||||
|
},
|
||||||
|
Spec: PostgresSpec{
|
||||||
|
ClusterName: "testcluster42",
|
||||||
|
PostgresqlParam: PostgresqlParam{PgVersion: "9.6"},
|
||||||
|
Volume: Volume{Size: "10Gi"},
|
||||||
|
TeamID: "acid",
|
||||||
|
AllowedSourceRanges: []string{"185.85.220.0/22"},
|
||||||
|
NumberOfInstances: 1,
|
||||||
|
},
|
||||||
|
Status: ClusterStatusRunning,
|
||||||
|
Error: nil,
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
nil},
|
||||||
|
{[]byte(`{"apiVersion":"v1","items":[{"apiVersion":"acid.zalan.do/v1","kind":"Postgresql","metadata":{"labels":{"team":"acid"},"name":"acid-testcluster42","namespace"`),
|
||||||
|
PostgresqlList{},
|
||||||
|
errors.New("unexpected end of JSON input")}}
|
||||||
|
|
||||||
|
func mustParseTime(s string) time.Time {
|
||||||
|
v, err := time.Parse("15:04", s)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.UTC()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseTime(t *testing.T) {
|
||||||
|
for _, tt := range parseTimeTests {
|
||||||
|
aTime, err := parseTime(tt.in)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() != tt.err.Error() {
|
||||||
|
t.Errorf("ParseTime expected error: %v, got: %v", tt.err, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if aTime != tt.out {
|
||||||
|
t.Errorf("Expected time: %v, got: %v", tt.out, aTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWeekdayTime(t *testing.T) {
|
||||||
|
for _, tt := range parseWeekdayTests {
|
||||||
|
aTime, err := parseWeekday(tt.in)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() != tt.err.Error() {
|
||||||
|
t.Errorf("ParseWeekday expected error: %v, got: %v", tt.err, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if aTime != tt.out {
|
||||||
|
t.Errorf("Expected weekday: %v, got: %v", tt.out, aTime)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestClusterName(t *testing.T) {
|
||||||
|
for _, tt := range clusterNames {
|
||||||
|
name, err := extractClusterName(tt.in, tt.inTeam)
|
||||||
|
if err != nil && err.Error() != tt.err.Error() {
|
||||||
|
t.Errorf("extractClusterName expected error: %v, got: %v", tt.err, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if name != tt.clusterName {
|
||||||
|
t.Errorf("Expected cluserName: %s, got: %s", tt.clusterName, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalMaintenanceWindow(t *testing.T) {
|
||||||
|
for _, tt := range maintenanceWindows {
|
||||||
|
var m MaintenanceWindow
|
||||||
|
err := m.UnmarshalJSON(tt.in)
|
||||||
|
if err != nil && err.Error() != tt.err.Error() {
|
||||||
|
t.Errorf("MaintenanceWindow unmarshal expected error: %v, got %v", tt.err, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tt.err != nil && err == nil {
|
||||||
|
t.Errorf("Expected error")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(m, tt.out) {
|
||||||
|
t.Errorf("Expected maintenace window: %#v, got: %#v", tt.out, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshalMaintenanceWindow(t *testing.T) {
|
||||||
|
for _, tt := range maintenanceWindows {
|
||||||
|
if tt.err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := tt.out.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Marshal Error: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(s, tt.in) {
|
||||||
|
t.Errorf("Expected Marshal: %s, got: %s", string(tt.in), string(s))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostgresUnmarshal(t *testing.T) {
|
||||||
|
for _, tt := range unmarshalCluster {
|
||||||
|
var cluster Postgresql
|
||||||
|
err := cluster.UnmarshalJSON(tt.in)
|
||||||
|
if err != nil {
|
||||||
|
if err.Error() != tt.err.Error() {
|
||||||
|
t.Errorf("Unmarshal expected error: %v, got: %v", tt.err, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(cluster, tt.out) {
|
||||||
|
t.Errorf("Expected Postgresql: %#v, got %#v", tt.out, cluster)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMarshal(t *testing.T) {
|
||||||
|
for _, tt := range unmarshalCluster {
|
||||||
|
if tt.err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := json.Marshal(tt.out)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Marshal error: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !bytes.Equal(m, tt.marshal) {
|
||||||
|
t.Errorf("Marshal Postgresql expected: %s, got: %s", string(tt.marshal), string(m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostgresMeta(t *testing.T) {
|
||||||
|
for _, tt := range unmarshalCluster {
|
||||||
|
if a := tt.out.GetObjectKind(); a != &tt.out.TypeMeta {
|
||||||
|
t.Errorf("GetObjectKindMeta expected: %v, got: %v", tt.out.TypeMeta, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a := tt.out.GetObjectMeta(); reflect.DeepEqual(a, tt.out.Metadata) {
|
||||||
|
t.Errorf("GetObjectMeta expected: %v, got: %v", tt.out.Metadata, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUnmarshalPostgresList(t *testing.T) {
|
||||||
|
for _, tt := range postgresqlList {
|
||||||
|
var list PostgresqlList
|
||||||
|
err := list.UnmarshalJSON(tt.in)
|
||||||
|
if err != nil && err.Error() != tt.err.Error() {
|
||||||
|
t.Errorf("PostgresqlList unmarshal expected error: %v, got: %v", tt.err, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(list, tt.out) {
|
||||||
|
t.Errorf("Postgresql list unmarshall expected: %#v, got: %#v", tt.out, list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostgresListMeta(t *testing.T) {
|
||||||
|
for _, tt := range postgresqlList {
|
||||||
|
if tt.err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if a := tt.out.GetObjectKind(); a != &tt.out.TypeMeta {
|
||||||
|
t.Errorf("GetObjectKindMeta expected: %v, got: %v", tt.out.TypeMeta, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a := tt.out.GetListMeta(); reflect.DeepEqual(a, tt.out.Metadata) {
|
||||||
|
t.Errorf("GetObjectMeta expected: %v, got: %v", tt.out.Metadata, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,8 @@ package spec
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"k8s.io/client-go/pkg/api/v1"
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
"k8s.io/client-go/pkg/types"
|
"k8s.io/client-go/pkg/types"
|
||||||
|
|
@ -72,10 +74,6 @@ type UserSyncer interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n NamespacedName) String() string {
|
func (n NamespacedName) String() string {
|
||||||
if n.Namespace == "" && n.Name == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
return types.NamespacedName(n).String()
|
return types.NamespacedName(n).String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,9 +85,16 @@ func (n NamespacedName) MarshalJSON() ([]byte, error) {
|
||||||
// Decode converts a (possibly unqualified) string into the namespaced name object.
|
// Decode converts a (possibly unqualified) string into the namespaced name object.
|
||||||
func (n *NamespacedName) Decode(value string) error {
|
func (n *NamespacedName) Decode(value string) error {
|
||||||
name := types.NewNamespacedNameFromString(value)
|
name := types.NewNamespacedNameFromString(value)
|
||||||
if value != "" && name == (types.NamespacedName{}) {
|
|
||||||
|
if strings.Trim(value, string(types.Separator)) != "" && name == (types.NamespacedName{}) {
|
||||||
name.Name = value
|
name.Name = value
|
||||||
name.Namespace = v1.NamespaceDefault
|
name.Namespace = v1.NamespaceDefault
|
||||||
|
} else if name.Namespace == "" {
|
||||||
|
name.Namespace = v1.NamespaceDefault
|
||||||
|
}
|
||||||
|
|
||||||
|
if name.Name == "" {
|
||||||
|
return fmt.Errorf("Incorrect namespaced name")
|
||||||
}
|
}
|
||||||
|
|
||||||
*n = NamespacedName(name)
|
*n = NamespacedName(name)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var nnTests = []struct {
|
||||||
|
s string
|
||||||
|
expected NamespacedName
|
||||||
|
expectedMarshal []byte
|
||||||
|
}{
|
||||||
|
{`acid/cluster`, NamespacedName{Namespace: "acid", Name: "cluster"}, []byte(`"acid/cluster"`)},
|
||||||
|
{`/name`, NamespacedName{Namespace: "default", Name: "name"}, []byte(`"default/name"`)},
|
||||||
|
{`test`, NamespacedName{Namespace: "default", Name: "test"}, []byte(`"default/test"`)},
|
||||||
|
}
|
||||||
|
|
||||||
|
var nnErr = []string{"test/", "/", "", "//"}
|
||||||
|
|
||||||
|
func TestNamespacedNameDecode(t *testing.T) {
|
||||||
|
for _, tt := range nnTests {
|
||||||
|
var actual NamespacedName
|
||||||
|
err := actual.Decode(tt.s)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Decode error: %v", err)
|
||||||
|
}
|
||||||
|
if actual != tt.expected {
|
||||||
|
t.Errorf("Expected: %v, got %#v", tt.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamespacedNameMarshal(t *testing.T) {
|
||||||
|
for _, tt := range nnTests {
|
||||||
|
var actual NamespacedName
|
||||||
|
|
||||||
|
m, err := actual.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Marshal error: %v", err)
|
||||||
|
}
|
||||||
|
if bytes.Equal(m, tt.expectedMarshal) {
|
||||||
|
t.Errorf("Expected marshal: %v, got %#v", tt.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNamespacedNameError(t *testing.T) {
|
||||||
|
for _, tt := range nnErr {
|
||||||
|
var actual NamespacedName
|
||||||
|
err := actual.Decode(tt)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Error expected for '%s', got: %#v", tt, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,118 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/client-go/pkg/api/v1"
|
||||||
|
|
||||||
|
"github.com/zalando-incubator/postgres-operator/pkg/spec"
|
||||||
|
)
|
||||||
|
|
||||||
|
var pgUsers = []struct {
|
||||||
|
in spec.PgUser
|
||||||
|
out string
|
||||||
|
}{{spec.PgUser{
|
||||||
|
Name: "test",
|
||||||
|
Password: "password",
|
||||||
|
Flags: []string{},
|
||||||
|
MemberOf: []string{}},
|
||||||
|
"md587f77988ccb5aa917c93201ba314fcd4"},
|
||||||
|
{spec.PgUser{
|
||||||
|
Name: "test",
|
||||||
|
Password: "md592f413f3974bdf3799bb6fecb5f9f2c6",
|
||||||
|
Flags: []string{},
|
||||||
|
MemberOf: []string{}},
|
||||||
|
"md592f413f3974bdf3799bb6fecb5f9f2c6"}}
|
||||||
|
|
||||||
|
var prettyTest = []struct {
|
||||||
|
in interface{}
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{pgUsers, `[{{test password [] []} md587f77988ccb5aa917c93201ba314fcd4} {{test md592f413f3974bdf3799bb6fecb5f9f2c6 [] []} md592f413f3974bdf3799bb6fecb5f9f2c6}]`},
|
||||||
|
}
|
||||||
|
|
||||||
|
var prettyDiffTest = []struct {
|
||||||
|
inA interface{}
|
||||||
|
inB interface{}
|
||||||
|
out string
|
||||||
|
}{
|
||||||
|
{[]int{1, 2, 3, 4}, []int{1, 2, 3}, "[]int[4] != []int[3]"},
|
||||||
|
{[]int{1, 2, 3, 4}, []int{1, 2, 3, 4}, ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
var substractTest = []struct {
|
||||||
|
inA []string
|
||||||
|
inB []string
|
||||||
|
out []string
|
||||||
|
outEqual bool
|
||||||
|
}{
|
||||||
|
{[]string{"a", "b", "c", "d"}, []string{"a", "b", "c", "d"}, []string{}, true},
|
||||||
|
{[]string{"a", "b", "c", "d"}, []string{"a", "bb", "c", "d"}, []string{"b"}, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRandomPassword(t *testing.T) {
|
||||||
|
const pwdLength = 10
|
||||||
|
pwd := RandomPassword(pwdLength)
|
||||||
|
if a := len(pwd); a != pwdLength {
|
||||||
|
t.Errorf("Password length expected: %d, got: %d", pwdLength, a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNameFromMeta(t *testing.T) {
|
||||||
|
meta := v1.ObjectMeta{
|
||||||
|
Name: "testcluster",
|
||||||
|
Namespace: "default",
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := spec.NamespacedName{
|
||||||
|
Name: "testcluster",
|
||||||
|
Namespace: "default",
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := NameFromMeta(meta)
|
||||||
|
if actual != expected {
|
||||||
|
t.Errorf("NameFromMeta expected: %#v, got: %#v", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPGUserPassword(t *testing.T) {
|
||||||
|
for _, tt := range pgUsers {
|
||||||
|
pwd := PGUserPassword(tt.in)
|
||||||
|
if pwd != tt.out {
|
||||||
|
t.Errorf("PgUserPassword expected: %s, got: %s", tt.out, pwd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPretty(t *testing.T) {
|
||||||
|
for _, tt := range prettyTest {
|
||||||
|
if actual := Pretty(tt.in); fmt.Sprintf("%v", actual) != tt.out {
|
||||||
|
t.Errorf("Pretty expected: %s, got: %s", tt.out, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrettyDiff(t *testing.T) {
|
||||||
|
for _, tt := range prettyDiffTest {
|
||||||
|
if actual := PrettyDiff(tt.inA, tt.inB); actual != tt.out {
|
||||||
|
t.Errorf("PrettyDiff expected: %s, got: %s", tt.out, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSubstractSlices(t *testing.T) {
|
||||||
|
for _, tt := range substractTest {
|
||||||
|
actualRes, actualEqual := SubstractStringSlices(tt.inA, tt.inB)
|
||||||
|
if actualEqual != tt.outEqual {
|
||||||
|
t.Errorf("SubstractStringSlices expected equal: %t, got: %t", tt.outEqual, actualEqual)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(actualRes) == 0 && len(tt.out) == 0 {
|
||||||
|
continue
|
||||||
|
} else if !reflect.DeepEqual(actualRes, tt.out) {
|
||||||
|
t.Errorf("SubstractStringSlices expected res: %v, got: %v", tt.out, actualRes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue