openconfig / ygot

A YANG-centric Go toolkit - Go/Protobuf Code Generation; Validation; Marshaling/Unmarshaling
Apache License 2.0
286 stars 107 forks source link

ytypes.Unmarshal errors for IETFJSONtree map into corresponding GoStruct #372

Closed gsindigi closed 4 years ago

gsindigi commented 4 years ago

The GoStructs are generated in package "oc" for OpenConfig*yang modules, using generator tool as described. Seeing issues when tried to unmarshal a json-tree using ytypes.Unmarshal

func TestYtypesUnmarshal(t *testing.T) {
    vgss := []ygot.ValidatedGoStruct{
        &oc.OpenconfigInterfaces_Interfaces_Interface_State{Mtu: ygot.Uint16(4086)},
        &oc.OpenconfigInterfaces_Interfaces_Interface_State_Counters{InOctets: ygot.Uint64(64)},
        &oc.OpenconfigBgp_Bgp_Neighbors_Neighbor_State{LocalAs: ygot.Uint32(100)},
    }
    for _, vgs := range vgss {
        log.Infof("Testing with %T", vgs)
        assert.NotNil(t, vgs)
        //m, e := ygot.ConstructInternalJSON(vgs) // with internal-json form all above fails
        m, e := ygot.ConstructIETFJSON(vgs, &ygot.RFC7951JSONConfig{AppendModuleName: false}) // with IETF, Mtu & LocalAs fails
        assert.Nil(t, e)
        assert.NotNil(t, m)
        log.Infof("IETFJSON Map: %v", m)
        for k, v := range m {
            log.Infof("Key=%v; Value=%v (%T)", k, v, v)
        }
        tn := reflect.TypeOf(vgs).Elem().Name()
        schema, ok := yoc.SchemaTree[tn]
        require.Truef(t, ok, "could not find schema for type %s", tn)
        e = ytypes.Unmarshal(schema, vgs, m)
        assert.Nil(t, e, "unmarshal to same gostruct should pass")
        if e == nil {
            log.Infof("%v unmarshaled into %T", m, vgs)
        }
    }
}
  1. With IETF-JSON map, I see below 2 errors
    • for Mtu: "got uint16 type for field mtu, expect float64"
    • for LocalAs: "got uint32 type for field local-as, expect float64"
  2. With InternalJSON map, I see below 3 errors
    • for Mtu: "got uint16 type for field mtu, expect float64"
    • for LocalAs: "got uint32 type for field local-as, expect float64"
    • for InOctets: "got uint64 type for field in-octets, expect string"

However, when the such maps are json.Marshaled and generated []byte is used as value for func Unmarshal(data []byte, destStruct ygot.GoStruct, opts ...ytypes.UnmarshalOpt) error , I do not see above issues.

I was hoping the maps can be directly used with ytypes.Unamarshal, which does seem to be having issues. Is this not right usage ? I was expecting the maps to work seamlessly, as they were having right type of values for the fields.

Is it always preferred to json.Marshal and use marshaled value? Wouldn't this call for an extra step that can be avoided ?

robshakir commented 4 years ago

Yes, you should call json.Marshal on the ConstructIETFJSON output. If you're wanting to skip this step, then the EmitJSON API that we provide would be preferred. We keep the ConstructIETFJSON public because there are cases where the user might want the map[string]interface{} format.

wenovus commented 4 years ago

Closing this issue due to inactivity.