-
Notifications
You must be signed in to change notification settings - Fork 106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Presence Containers #645
Presence Containers #645
Conversation
the field of generated Go Struct. When rendering JSON documents, before deleting/omitting empty containers, it checks for this struct field tag. As per the OpenConfig style guide, YANG presence containers are not used, as such this would only be used with 3rd party YANG models. As such a CLI knob is added to generator.go to enable this behavior with -yangpresence=true
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). For more information, open the CLA check for this pull request. |
proposed fix for #329 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks pretty good to me. One other suggestion is to add an integration test by copying testdata/modules/openconfig-simple.yang to a new file, adding a presence container, and a new test case (copy over one of the test cases) in codegen_test.go just to make sure it works end-to-end.
Sorry, another comment is we should mark this flag as "only tested for marshalling JSON". So note to the user that unmarshalling doesn't yet work (at least not until we add tests) |
Could you point me to the test cases for Unmarshaling JSON? I've only come across Line 23 in c15884d
Is this where a test should be defined? In the Unmarshaling case, I'd expect this (an empty value) to be a use/test-case anyhow right? Whether this is a presence container or not, is not known yet at that point? |
There is also TestUnmarshalContainer, the tests are split by node type. That sounds good, if there is no extra implementation involved sounds good to me to just add the unmarshal tests in this PR and then we can say for this flag that "it's supported for JSON marshalling and unmarshalling". In particular this doesn't work with the |
- adding tests in ygot/render_test.go: - testing a presence container in a list entry (ISIS overload usecase) - testing a presence container in a non-presence container (system/ssh-server usecase) - adding tests in ytypes/container_test.go: - adding tests in TestUnmarshalContainer
Done, could you check whether the test's I've added cover enough ground? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks looks pretty good to me, just a couple minor comments.
ytypes/container_test.go
Outdated
want: &ParentContainerStruct{ContainerField: &ContainerStruct{ConfigLeaf1Field: ygot.Int32(41), StateLeaf1Field: ygot.Int32(42), Leaf2Field: ygot.Int32(43), Container2Field: nil}}, | ||
}, | ||
{ | ||
desc: "success overwriting existing fields with presence container", | ||
schema: containerSchema, | ||
parent: &ParentContainerStruct{ContainerField: &ContainerStruct{ConfigLeaf1Field: ygot.Int32(1), StateLeaf1Field: ygot.Int32(2), Container2Field: nil}}, | ||
json: `{ "container-field": { "leaf2-field": 43, "config": { "leaf1-field": 41 } , "state": { "leaf1-field": 42 } , "container2-field": { "leaf3-field": 44 } } }`, | ||
want: &ParentContainerStruct{ContainerField: &ContainerStruct{ConfigLeaf1Field: ygot.Int32(41), StateLeaf1Field: ygot.Int32(42), Leaf2Field: ygot.Int32(43), Container2Field: &Container2Struct{Leaf3Field: ygot.Int32(44)}}}, | ||
}, | ||
{ | ||
desc: "success overwriting existing fields with empty presence container", | ||
schema: containerSchema, | ||
parent: &ParentContainerStruct{ContainerField: &ContainerStruct{ConfigLeaf1Field: ygot.Int32(1), StateLeaf1Field: ygot.Int32(2), Container2Field: nil}}, | ||
json: `{ "container-field": { "leaf2-field": 43, "config": { "leaf1-field": 41 } , "state": { "leaf1-field": 42 } , "container2-field": { } } }`, | ||
want: &ParentContainerStruct{ContainerField: &ContainerStruct{ConfigLeaf1Field: ygot.Int32(41), StateLeaf1Field: ygot.Int32(42), Leaf2Field: ygot.Int32(43), Container2Field: &Container2Struct{}}}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the idea of these tests is to overwrite existing values, Container2Field
should have a non-nil value to begin with, could you add those in the parent:
field?
Looking at this makes me wonder what the behaviour should be if we receive "container2-field": { }
when it already has a value there: should it erase the value? Or should it be a no-op? Per the current behaviour I believe it's a no-op since the semantics of unmarshal is to "update" rather than "replace", which I think makes sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, my bad, a copy-paste error and I overlooked the test-cases. Indeed Container2Field
should have gotten a non-nil value! fixed now.
Considering the semantics, I believe you're right and it's indeed a no-op. I assume "replace" behaviour can be achieved using Merge (MergeOverwriteExistingFields) ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. MergeOverwriteExistingFields is not replace behaviour though. To get that you might just have to do it manually or via SetNode.
ygot/render_test.go
Outdated
}, { | ||
name: "uncompressed device example with presence container encapsulated in regular container eq nil value", | ||
in: &ucExampleDevice{ | ||
Bgp: &ucExampleBgp{}, | ||
System: &ucExampleSystem{ | ||
SshServer: nil, | ||
}, | ||
}, | ||
wantIETF: map[string]interface{}{ | ||
"bgp": map[string]interface{}{}, | ||
}, | ||
wantInternal: map[string]interface{}{ | ||
"bgp": map[string]interface{}{}, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add another test case with SshServer: &ucExampleSystemSshServer{}?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added the empty struct in a test case for SshServer: &ucExampleSystemSshServer{}
, also re-ordered the test cases a bit, so it's uniform testing empty value, nil value and with data in tree.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if diff := pretty.Compare(gotietf, tt.wantIETF); diff != "" {
t.Errorf("ConstructIETFJSON(%v): did not get expected output, diff(-got,+want):\n%v", tt.in, diff)
}
For this block in render_test.go I'm wondering if we should convert to using cmp.Diff
, which is the standard comparison tool which by default differentiates between the empty type and a nil value for comparing map[string]interface{}
.
We could, but existing test-cases would break (not functionally though):
for example:
I have staged the changes of the test-cases, so if It would be your preference to do the conversion in this PR, I'll push it! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since it's existing tests that break this LGTM. If you have the staged changes let's look at them in a separate PR.
This commit adds support for YANG presence containers. It adds a tag to
the field of generated Go Struct. When rendering JSON documents, before
deleting/omitting empty containers, it checks for this struct field tag.
As per the OpenConfig style guide, YANG presence containers are not
used, as such this would only be used with 3rd party YANG models. As
such a CLI knob is added to generator.go to enable this behaviour with
-yangpresence=true