Skip to content

Commit

Permalink
[FAB-2577] Add JSON rendering of configResult
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-2577

FAB-2574 split the config result from the config manager to allow other
pieces fo the system to utilize it.  This CR adds the ability for the
config result to render the config result as JSON to be used in a later
changeset for inspecting the configuration.

Change-Id: Ieeccaf8486706f0a47ea09196eca12caae007a2b
Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
  • Loading branch information
Jason Yellick committed Mar 7, 2017
1 parent 093394b commit 86f65d3
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 0 deletions.
73 changes: 73 additions & 0 deletions common/configtx/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ limitations under the License.
package configtx

import (
"bytes"
"fmt"

"github.com/hyperledger/fabric/common/config"
"github.com/hyperledger/fabric/common/configtx/api"
"github.com/hyperledger/fabric/common/policies"
cb "github.com/hyperledger/fabric/protos/common"

"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
)

Expand All @@ -37,6 +39,77 @@ type configResult struct {
deserializedValues map[string]proto.Message
}

func (cr *configResult) JSON() string {
var buffer bytes.Buffer
buffer.WriteString("{")
cr.bufferJSON(&buffer)
buffer.WriteString("}")
return buffer.String()

}

// bufferJSON takes a buffer and writes a JSON representation of the configResult into the buffer
// Note that we use some mildly ad-hoc JSON encoding because the proto documentation explicitly
// mentions that the encoding/json package does not correctly marshal proto objects, and we
// do not have a proto object (nor can one be defined) which presents the mixed-map style of
// keys mapping to different types of the config
func (cr *configResult) bufferJSON(buffer *bytes.Buffer) {
jpb := &jsonpb.Marshaler{
EmitDefaults: true,
Indent: " ",
}

// "GroupName": {
buffer.WriteString("\"")
buffer.WriteString(cr.groupName)
buffer.WriteString("\": {")

// "Values": {
buffer.WriteString("\"Values\": {")
count := 0
for key, value := range cr.group.Values {
// "Key": {
buffer.WriteString("\"")
buffer.WriteString(key)
buffer.WriteString("\": {")
// "Version": "X",
buffer.WriteString("\"Version\":\"")
buffer.WriteString(fmt.Sprintf("%d", value.Version))
buffer.WriteString("\",")
// "ModPolicy": "foo",
buffer.WriteString("\"ModPolicy\":\"")
buffer.WriteString(value.ModPolicy)
buffer.WriteString("\",")
// "Value": protoAsJSON
buffer.WriteString("\"Value\":")
jpb.Marshal(buffer, cr.deserializedValues[key])
// },
buffer.WriteString("}")
count++
if count < len(cr.group.Values) {
buffer.WriteString(",")
}
}
// },
buffer.WriteString("},")

// "Groups": {
count = 0
buffer.WriteString("\"Groups\": {")
for _, subResult := range cr.subResults {
subResult.bufferJSON(buffer)
count++
if count < len(cr.subResults) {
buffer.WriteString(",")
}
}
// }
buffer.WriteString("}")

// }
buffer.WriteString("}")
}

func (cr *configResult) preCommit() error {
for _, subResult := range cr.subResults {
err := subResult.preCommit()
Expand Down
79 changes: 79 additions & 0 deletions common/configtx/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
Copyright IBM Corp. 2017 All Rights Reserved.
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 configtx

import (
"bytes"
"encoding/json"
"strings"
"testing"

cb "github.com/hyperledger/fabric/protos/common"
ab "github.com/hyperledger/fabric/protos/orderer"

"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/assert"
)

func TestJSON(t *testing.T) {
cr := &configResult{
groupName: "rootGroup",
group: &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
"outer": &cb.ConfigValue{Version: 1, ModPolicy: "mod1"},
},
},
subResults: []*configResult{
&configResult{
groupName: "innerGroup1",
group: &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
"inner1": &cb.ConfigValue{ModPolicy: "mod3"},
},
},
deserializedValues: map[string]proto.Message{
"inner1": &ab.ConsensusType{Type: "inner1"},
},
},
&configResult{
groupName: "innerGroup2",
group: &cb.ConfigGroup{
Values: map[string]*cb.ConfigValue{
"inner2": &cb.ConfigValue{ModPolicy: "mod3"},
},
},
deserializedValues: map[string]proto.Message{
"inner2": &ab.ConsensusType{Type: "inner2"},
},
},
},
deserializedValues: map[string]proto.Message{
"outer": &ab.ConsensusType{Type: "outer"},
},
}

buffer := &bytes.Buffer{}
assert.NoError(t, json.Indent(buffer, []byte(cr.JSON()), "", ""), "JSON should parse nicely")

expected := "{\"rootGroup\":{\"Values\":{\"outer\":{\"Version\":\"1\",\"ModPolicy\":\"mod1\",\"Value\":{\"type\":\"outer\"}}},\"Groups\":{\"innerGroup1\":{\"Values\":{\"inner1\":{\"Version\":\"0\",\"ModPolicy\":\"mod3\",\"Value\":{\"type\":\"inner1\"}}},\"Groups\":{}},\"innerGroup2\":{\"Values\":{\"inner2\":{\"Version\":\"0\",\"ModPolicy\":\"mod3\",\"Value\":{\"type\":\"inner2\"}}},\"Groups\":{}}}}}"

// Remove all newlines and spaces from the JSON
compactedJSON := strings.Replace(strings.Replace(buffer.String(), "\n", "", -1), " ", "", -1)

assert.Equal(t, expected, compactedJSON)

}

0 comments on commit 86f65d3

Please sign in to comment.