add Unmarshal method and tests for PostgresStatus

This commit is contained in:
Felix Kunde 2019-04-12 15:55:25 +02:00
parent c3834df57a
commit e2e2441ee1
4 changed files with 101 additions and 6 deletions

View File

@ -69,6 +69,31 @@ func (m *MaintenanceWindow) UnmarshalJSON(data []byte) error {
return nil return nil
} }
// UnmarshalJSON converts a JSON to the status subresource definition.
func (ps *PostgresStatus) UnmarshalJSON(data []byte) error {
var got PostgresStatus
str := string(data)
str = strings.Replace(str, "{", "", -1)
str = strings.Replace(str, "}", "", -1)
str = strings.Replace(str, "\"", "", -1)
parts := strings.Split(str, ":")
if len(parts) == 2 || len(parts) == 3 {
if parts[1] != "" {
got.PostgresClusterStatus = parts[len(parts)-1]
} else {
got.PostgresClusterStatus = ClusterStatusUnknown
}
} else {
return fmt.Errorf("incorrect status field of CR")
}
*ps = got
return nil
}
// UnmarshalJSON converts a JSON into the PostgreSQL object. // UnmarshalJSON converts a JSON into the PostgreSQL object.
func (p *Postgresql) UnmarshalJSON(data []byte) error { func (p *Postgresql) UnmarshalJSON(data []byte) error {
var tmp postgresqlCopy var tmp postgresqlCopy

View File

@ -130,5 +130,5 @@ type UserFlags []string
// PostgresStatus contains status of the PostgreSQL cluster (running, creation failed etc.) // PostgresStatus contains status of the PostgreSQL cluster (running, creation failed etc.)
type PostgresStatus struct { type PostgresStatus struct {
PostgresClusterStatus string `json:"PostgresClusterStatus,omitempty"` PostgresClusterStatus string `json:"PostgresClusterStatus"`
} }

View File

@ -97,5 +97,5 @@ func (postgresStatus PostgresStatus) Running() bool {
} }
func (postgresStatus PostgresStatus) String() string { func (postgresStatus PostgresStatus) String() string {
return string(postgresStatus.PostgresClusterStatus) return fmt.Sprintf(`status=%s`, postgresStatus.PostgresClusterStatus)
} }

View File

@ -111,12 +111,48 @@ var maintenanceWindows = []struct {
{[]byte(`"Mon: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")}} {[]byte(`"Mon:00:00-00:00:00"`), MaintenanceWindow{}, errors.New("could not parse end time: incorrect time format")}}
var postgresStatus = []struct {
in []byte
out PostgresStatus
err error
}{
{[]byte(`"status":"Running"`),
PostgresStatus{PostgresClusterStatus: ClusterStatusRunning}, nil},
{[]byte(`"status":{"PostgresClusterStatus":"Running"}`),
PostgresStatus{PostgresClusterStatus: ClusterStatusRunning}, nil},
{[]byte(`"status":""`),
PostgresStatus{PostgresClusterStatus: ClusterStatusUnknown}, nil},
{[]byte(`"status":{}`),
PostgresStatus{PostgresClusterStatus: ClusterStatusUnknown}, nil},
{[]byte(`"status":`),
PostgresStatus{PostgresClusterStatus: ClusterStatusUnknown}, nil}}
var unmarshalCluster = []struct { var unmarshalCluster = []struct {
in []byte in []byte
out Postgresql out Postgresql
marshal []byte marshal []byte
err error err error
}{ }{
// example with simple status field
{
in: []byte(`{
"kind": "Postgresql","apiVersion": "acid.zalan.do/v1",
"metadata": {"name": "acid-testcluster1"}, "spec": {"teamId": 100}}`),
out: Postgresql{
TypeMeta: metav1.TypeMeta{
Kind: "Postgresql",
APIVersion: "acid.zalan.do/v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "acid-testcluster1",
},
Status: PostgresStatus{PostgresClusterStatus: ClusterStatusInvalid},
// This error message can vary between Go versions, so compute it for the current version.
Error: json.Unmarshal([]byte(`{"teamId": 0}`), &PostgresSpec{}).Error(),
},
marshal: []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,"slots":null},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"","allowedSourceRanges":null,"numberOfInstances":0,"users":null,"clone":{}},"status":"Invalid"}`),
err: nil},
// example with /status subresource
{ {
in: []byte(`{ in: []byte(`{
"kind": "Postgresql","apiVersion": "acid.zalan.do/v1", "kind": "Postgresql","apiVersion": "acid.zalan.do/v1",
@ -135,6 +171,7 @@ var unmarshalCluster = []struct {
}, },
marshal: []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,"slots":null},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"","allowedSourceRanges":null,"numberOfInstances":0,"users":null,"clone":{}},"status":{"PostgresClusterStatus":"Invalid"}}`), marshal: []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,"slots":null},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"","allowedSourceRanges":null,"numberOfInstances":0,"users":null,"clone":{}},"status":{"PostgresClusterStatus":"Invalid"}}`),
err: nil}, err: nil},
// example with detailed input manifest
{ {
in: []byte(`{ in: []byte(`{
"kind": "Postgresql", "kind": "Postgresql",
@ -276,8 +313,9 @@ var unmarshalCluster = []struct {
}, },
Error: "", Error: "",
}, },
marshal: []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,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"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"],"clone":{"cluster":"acid-batman"}},"status":{}}`), marshal: []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,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"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"],"clone":{"cluster":"acid-batman"}},"status":{"PostgresClusterStatus":""}}`),
err: nil}, err: nil},
// example with teamId set in input
{ {
in: []byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1","metadata": {"name": "teapot-testcluster1"}, "spec": {"teamId": "acid"}}`), in: []byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1","metadata": {"name": "teapot-testcluster1"}, "spec": {"teamId": "acid"}}`),
out: Postgresql{ out: Postgresql{
@ -294,6 +332,7 @@ var unmarshalCluster = []struct {
}, },
marshal: []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,"slots":null},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"acid","allowedSourceRanges":null,"numberOfInstances":0,"users":null,"clone":{}},"status":{"PostgresClusterStatus":"Invalid"}}`), marshal: []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,"slots":null},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"acid","allowedSourceRanges":null,"numberOfInstances":0,"users":null,"clone":{}},"status":{"PostgresClusterStatus":"Invalid"}}`),
err: nil}, err: nil},
// clone example
{ {
in: []byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1","metadata": {"name": "acid-testcluster1"}, "spec": {"teamId": "acid", "clone": {"cluster": "team-batman"}}}`), in: []byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1","metadata": {"name": "acid-testcluster1"}, "spec": {"teamId": "acid", "clone": {"cluster": "team-batman"}}}`),
out: Postgresql{ out: Postgresql{
@ -313,8 +352,9 @@ var unmarshalCluster = []struct {
}, },
Error: "", Error: "",
}, },
marshal: []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,"slots":null},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"acid","allowedSourceRanges":null,"numberOfInstances":0,"users":null,"clone":{"cluster":"team-batman"}},"status":{}}`), marshal: []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,"slots":null},"resources":{"requests":{"cpu":"","memory":""},"limits":{"cpu":"","memory":""}},"teamId":"acid","allowedSourceRanges":null,"numberOfInstances":0,"users":null,"clone":{"cluster":"team-batman"}},"status":{"PostgresClusterStatus":""}}`),
err: nil}, err: nil},
// erroneous examples
{ {
in: []byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1"`), in: []byte(`{"kind": "Postgresql","apiVersion": "acid.zalan.do/v1"`),
out: Postgresql{}, out: Postgresql{},
@ -479,6 +519,25 @@ func TestMarshalMaintenanceWindow(t *testing.T) {
} }
} }
func TestUnmarshalPostgresStatus(t *testing.T) {
for _, tt := range postgresStatus {
var ps PostgresStatus
err := ps.UnmarshalJSON(tt.in)
if err != nil {
if tt.err == nil || err.Error() != tt.err.Error() {
t.Errorf("CR status unmarshal expected error: %v, got %v", tt.err, err)
}
continue
//} else if tt.err != nil {
//t.Errorf("Expected error: %v", tt.err)
}
if !reflect.DeepEqual(ps, tt.out) {
t.Errorf("Expected status: %#v, got: %#v", tt.out, ps)
}
}
}
func TestPostgresUnmarshal(t *testing.T) { func TestPostgresUnmarshal(t *testing.T) {
for _, tt := range unmarshalCluster { for _, tt := range unmarshalCluster {
var cluster Postgresql var cluster Postgresql
@ -504,12 +563,23 @@ func TestMarshal(t *testing.T) {
continue continue
} }
// Unmarshal and marshal example to capture api changes
var cluster Postgresql
err := cluster.UnmarshalJSON(tt.marshal)
if err != nil {
if tt.err == nil || err.Error() != tt.err.Error() {
t.Errorf("Unmarshal expected error: %v, got: %v", tt.err, err)
}
continue
}
expected, err := json.Marshal(cluster)
m, err := json.Marshal(tt.out) m, err := json.Marshal(tt.out)
if err != nil { if err != nil {
t.Errorf("Marshal error: %v", err) t.Errorf("Marshal error: %v", err)
} }
if !bytes.Equal(m, tt.marshal) { if !bytes.Equal(m, expected) {
t.Errorf("Marshal Postgresql \nexpected: %q, \ngot: %q", string(tt.marshal), string(m)) t.Errorf("Marshal Postgresql \nexpected: %q, \ngot: %q", string(expected), string(m))
} }
} }
} }