diff --git a/coordinator/role/role.go b/coordinator/role/role.go index 83545f7e8..a95ad8716 100644 --- a/coordinator/role/role.go +++ b/coordinator/role/role.go @@ -1,5 +1,10 @@ package role +import ( + "encoding/json" + "strings" +) + //go:generate stringer -type=Role // Role is a peer's role. @@ -10,3 +15,26 @@ const ( Coordinator Node ) + +// MarshalJSON marshals the Role to JSON string. +func (r Role) MarshalJSON() ([]byte, error) { + return json.Marshal(r.String()) +} + +// UnmarshalJSON unmarshals the Role from JSON string. +func (r *Role) UnmarshalJSON(b []byte) error { + var roleString string + if err := json.Unmarshal(b, &roleString); err != nil { + return err + } + switch strings.ToLower(roleString) { + case "coordinator": + *r = Coordinator + + case "node": + *r = Node + default: + *r = Unknown + } + return nil +} diff --git a/coordinator/role/role_test.go b/coordinator/role/role_test.go new file mode 100644 index 000000000..d771170ae --- /dev/null +++ b/coordinator/role/role_test.go @@ -0,0 +1,96 @@ +package role + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestMarshal(t *testing.T) { + testCases := map[string]struct { + role Role + jsonExpected string + errExpected bool + }{ + "coordinator role": { + role: Coordinator, + jsonExpected: `"Coordinator"`, + }, + "node role": { + role: Node, + jsonExpected: `"Node"`, + }, + "unknown role": { + role: Unknown, + jsonExpected: `"Unknown"`, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + jsonRole, err := tc.role.MarshalJSON() + if tc.errExpected { + assert.Error(err) + return + } + + require.NoError(err) + assert.Equal(tc.jsonExpected, string(jsonRole)) + }) + } +} + +func TestUnmarshal(t *testing.T) { + testCases := map[string]struct { + json string + expectedRole Role + errExpected bool + }{ + "Coordinator can be unmarshaled": { + json: `"Coordinator"`, + expectedRole: Coordinator, + }, + "lowercase coordinator can be unmarshaled": { + json: `"coordinator"`, + expectedRole: Coordinator, + }, + "Node can be unmarshaled": { + json: `"Node"`, + expectedRole: Node, + }, + "lowercase node can be unmarshaled": { + json: `"node"`, + expectedRole: Node, + }, + "other strings unmarshal to the unknown role": { + json: `"anything"`, + expectedRole: Unknown, + }, + "invalid json fails": { + json: `"unterminated string literal`, + errExpected: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + require := require.New(t) + + var role Role + err := role.UnmarshalJSON([]byte(tc.json)) + + if tc.errExpected { + assert.Error(err) + return + } + + require.NoError(err) + assert.Equal(tc.expectedRole, role) + }) + } +}