resources: Add resource sorting and clean tests
Resource sorting is needed for comparing resource groups.
This commit is contained in:
@@ -115,11 +115,13 @@ type ResData struct {
|
|||||||
// The Base interface is everything that is common to all resources.
|
// The Base interface is everything that is common to all resources.
|
||||||
// Everything here only needs to be implemented once, in the BaseRes.
|
// Everything here only needs to be implemented once, in the BaseRes.
|
||||||
type Base interface {
|
type Base interface {
|
||||||
|
fmt.Stringer // String() string
|
||||||
|
|
||||||
GetName() string // can't be named "Name()" because of struct field
|
GetName() string // can't be named "Name()" because of struct field
|
||||||
SetName(string)
|
SetName(string)
|
||||||
SetKind(string)
|
SetKind(string)
|
||||||
GetKind() string
|
GetKind() string
|
||||||
String() string
|
|
||||||
Meta() *MetaParams
|
Meta() *MetaParams
|
||||||
Events() chan *event.Event
|
Events() chan *event.Event
|
||||||
Data() *ResData
|
Data() *ResData
|
||||||
|
|||||||
@@ -18,9 +18,6 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/gob"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,83 +64,6 @@ func TestCompare2(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMiscEncodeDecode1(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
//gob.Register( &NoopRes{} ) // happens in noop.go : init()
|
|
||||||
//gob.Register( &FileRes{} ) // happens in file.go : init()
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// encode
|
|
||||||
var input interface{} = &FileRes{}
|
|
||||||
b1 := bytes.Buffer{}
|
|
||||||
e := gob.NewEncoder(&b1)
|
|
||||||
err = e.Encode(&input) // pass with &
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Gob failed to Encode: %v", err)
|
|
||||||
}
|
|
||||||
str := base64.StdEncoding.EncodeToString(b1.Bytes())
|
|
||||||
|
|
||||||
// decode
|
|
||||||
var output interface{}
|
|
||||||
bb, err := base64.StdEncoding.DecodeString(str)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Base64 failed to Decode: %v", err)
|
|
||||||
}
|
|
||||||
b2 := bytes.NewBuffer(bb)
|
|
||||||
d := gob.NewDecoder(b2)
|
|
||||||
err = d.Decode(&output) // pass with &
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Gob failed to Decode: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
res1, ok := input.(Res)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("Input %v is not a Res", res1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res2, ok := output.(Res)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("Output %v is not a Res", res2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !res1.Compare(res2) {
|
|
||||||
t.Error("The input and output Res values do not match!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMiscEncodeDecode2(t *testing.T) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// encode
|
|
||||||
input, _ := NewResource("file")
|
|
||||||
|
|
||||||
b64, err := ResToB64(input)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Can't encode: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
output, err := B64ToRes(b64)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Can't decode: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res1, ok := input.(Res)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("Input %v is not a Res", res1)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
res2, ok := output.(Res)
|
|
||||||
if !ok {
|
|
||||||
t.Errorf("Output %v is not a Res", res2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !res1.Compare(res2) {
|
|
||||||
t.Error("The input and output Res values do not match!")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIFF(t *testing.T) {
|
func TestIFF(t *testing.T) {
|
||||||
uid := &BaseUID{Name: "/tmp/unit-test"}
|
uid := &BaseUID{Name: "/tmp/unit-test"}
|
||||||
same := &BaseUID{Name: "/tmp/unit-test"}
|
same := &BaseUID{Name: "/tmp/unit-test"}
|
||||||
|
|||||||
@@ -22,10 +22,30 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
errwrap "github.com/pkg/errors"
|
errwrap "github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ResourceSlice is a linear list of resources. It can be sorted.
|
||||||
|
type ResourceSlice []Res
|
||||||
|
|
||||||
|
func (rs ResourceSlice) Len() int { return len(rs) }
|
||||||
|
func (rs ResourceSlice) Swap(i, j int) { rs[i], rs[j] = rs[j], rs[i] }
|
||||||
|
func (rs ResourceSlice) Less(i, j int) bool { return rs[i].String() < rs[j].String() }
|
||||||
|
|
||||||
|
// Sort the list of resources and return a copy without modifying the input.
|
||||||
|
func Sort(rs []Res) []Res {
|
||||||
|
resources := []Res{}
|
||||||
|
for _, r := range rs { // copy
|
||||||
|
resources = append(resources, r)
|
||||||
|
}
|
||||||
|
sort.Sort(ResourceSlice(resources))
|
||||||
|
return resources
|
||||||
|
// sort.Sort(ResourceSlice(rs)) // this is wrong, it would modify input!
|
||||||
|
//return rs
|
||||||
|
}
|
||||||
|
|
||||||
// ResToB64 encodes a resource to a base64 encoded string (after serialization).
|
// ResToB64 encodes a resource to a base64 encoded string (after serialization).
|
||||||
func ResToB64(res Res) (string, error) {
|
func ResToB64(res Res) (string, error) {
|
||||||
b := bytes.Buffer{}
|
b := bytes.Buffer{}
|
||||||
|
|||||||
154
resources/util_test.go
Normal file
154
resources/util_test.go
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
// Mgmt
|
||||||
|
// Copyright (C) 2013-2017+ James Shubin and the project contributors
|
||||||
|
// Written by James Shubin <james@shubin.ca> and the project contributors
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Affero General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Affero General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Affero General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package resources
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/gob"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSort0(t *testing.T) {
|
||||||
|
rs := []Res{}
|
||||||
|
s := Sort(rs)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(s, []Res{}) {
|
||||||
|
t.Errorf("sort failed!")
|
||||||
|
if s == nil {
|
||||||
|
t.Logf("output is nil!")
|
||||||
|
} else {
|
||||||
|
str := "Got:"
|
||||||
|
for _, r := range s {
|
||||||
|
str += " " + r.String()
|
||||||
|
}
|
||||||
|
t.Errorf(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSort1(t *testing.T) {
|
||||||
|
r1, _ := NewResource("noop")
|
||||||
|
r1.SetName("noop1")
|
||||||
|
r2, _ := NewResource("noop")
|
||||||
|
r2.SetName("noop2")
|
||||||
|
r3, _ := NewResource("noop")
|
||||||
|
r3.SetName("noop3")
|
||||||
|
r4, _ := NewResource("noop")
|
||||||
|
r4.SetName("noop4")
|
||||||
|
r5, _ := NewResource("noop")
|
||||||
|
r5.SetName("noop5")
|
||||||
|
r6, _ := NewResource("noop")
|
||||||
|
r6.SetName("noop6")
|
||||||
|
|
||||||
|
rs := []Res{r3, r2, r6, r1, r5, r4}
|
||||||
|
s := Sort(rs)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(s, []Res{r1, r2, r3, r4, r5, r6}) {
|
||||||
|
t.Errorf("sort failed!")
|
||||||
|
str := "Got:"
|
||||||
|
for _, r := range s {
|
||||||
|
str += " " + r.String()
|
||||||
|
}
|
||||||
|
t.Errorf(str)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(rs, []Res{r3, r2, r6, r1, r5, r4}) {
|
||||||
|
t.Errorf("sort modified input!")
|
||||||
|
str := "Got:"
|
||||||
|
for _, r := range rs {
|
||||||
|
str += " " + r.String()
|
||||||
|
}
|
||||||
|
t.Errorf(str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMiscEncodeDecode1(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// encode
|
||||||
|
var input interface{} = &FileRes{}
|
||||||
|
b1 := bytes.Buffer{}
|
||||||
|
e := gob.NewEncoder(&b1)
|
||||||
|
err = e.Encode(&input) // pass with &
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Gob failed to Encode: %v", err)
|
||||||
|
}
|
||||||
|
str := base64.StdEncoding.EncodeToString(b1.Bytes())
|
||||||
|
|
||||||
|
// decode
|
||||||
|
var output interface{}
|
||||||
|
bb, err := base64.StdEncoding.DecodeString(str)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Base64 failed to Decode: %v", err)
|
||||||
|
}
|
||||||
|
b2 := bytes.NewBuffer(bb)
|
||||||
|
d := gob.NewDecoder(b2)
|
||||||
|
err = d.Decode(&output) // pass with &
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Gob failed to Decode: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
res1, ok := input.(Res)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Input %v is not a Res", res1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res2, ok := output.(Res)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Output %v is not a Res", res2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !res1.Compare(res2) {
|
||||||
|
t.Error("The input and output Res values do not match!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMiscEncodeDecode2(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// encode
|
||||||
|
input, _ := NewResource("file")
|
||||||
|
|
||||||
|
b64, err := ResToB64(input)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Can't encode: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := B64ToRes(b64)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Can't decode: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res1, ok := input.(Res)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Input %v is not a Res", res1)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res2, ok := output.(Res)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Output %v is not a Res", res2)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !res1.Compare(res2) {
|
||||||
|
t.Error("The input and output Res values do not match!")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user