Added suggestions from @SwampDragons to the parsers from the vmware builders, included unit-tests and sample file for fusion's networking file, and fixed a few situations where the channel wasn't being closed.

This commit is contained in:
Ali Rizvi-Santiago 2020-06-04 05:07:07 -05:00
parent 0609909f1a
commit 898321bcfe
3 changed files with 263 additions and 6 deletions

View File

@ -704,6 +704,7 @@ func parseParameter(val tkParameter) (pParameter, error) {
}
address := net.ParseIP(cidr[0])
bits, err := strconv.Atoi(cidr[1])
if err != nil {
return nil, err
@ -1038,10 +1039,12 @@ func (e *configDeclaration) IP4() (net.IP, error) {
return nil, fmt.Errorf("No IP4 addresses found")
}
// Try and parse it as an IP4. If so, then it's good to return it as-is.
if res := net.ParseIP(result[0]); res != nil {
return res, nil
}
// Otherwise make an attempt to resolve it to an address.
res, err := net.ResolveIPAddr("ip4", result[0])
if err != nil {
return nil, err
@ -1069,10 +1072,12 @@ func (e *configDeclaration) IP6() (net.IP, error) {
return nil, fmt.Errorf("No IP6 addresses found")
}
// If we were able to parse it into an IP, then we can just return it.
if res := net.ParseIP(result[0]); res != nil {
return res, nil
}
// Otherwise, try to resolve it into an address.
res, err := net.ResolveIPAddr("ip6", result[0])
if err != nil {
return nil, err
@ -1277,8 +1282,6 @@ func tokenizeNetworkingConfig(in chan byte) chan string {
}
switch by {
case '\r':
fallthrough
case '\t':
fallthrough
case ' ':
@ -1290,16 +1293,20 @@ func tokenizeNetworkingConfig(in chan byte) chan string {
out <- state
state = ""
case '\r':
// If windows has tampered with our newlines, then we normalize
// things by converting its value from 0x0d to 0x0a.
fallthrough
case '\n':
// Newlines can repeat, so this case is responsible for writing
// to the chan, and consolidating multiple newlines into singles.
// to the chan, and consolidating multiple newlines into a single.
if repeat_newline {
continue
}
if len(state) > 0 {
out <- state
}
out <- string(by)
out <- "\n"
state = ""
repeat_newline = true
continue
@ -1317,6 +1324,7 @@ func tokenizeNetworkingConfig(in chan byte) chan string {
if len(state) > 0 {
out <- state
}
close(out)
}(out)
return out
}
@ -1355,6 +1363,7 @@ func splitNetworkingConfig(in chan string) chan []string {
if len(row) > 0 {
out <- row
}
close(out)
}(out)
return out
}
@ -1698,7 +1707,7 @@ func parseNetworkingCommand_add_dhcp_mac_to_ip(row []string) (*networkingCommand
}
ip := net.ParseIP(row[2])
if ip != nil {
if ip == nil {
return nil, fmt.Errorf("Unable to parse third argument as ipv4. : %v", row[2])
}
@ -1850,6 +1859,7 @@ func parseNetworkingConfig(rows chan []string) chan networkingCommandEntry {
out <- *entry
}
}
close(out)
}(rows, out)
return out
}
@ -2197,7 +2207,7 @@ This consumes bytes within a pair of some bytes, like parentheses, brackets, bra
We start by reading bytes until we encounter openByte. These will be returned as
the first parameter. Then we can enter a goro and consume bytes until we get to
closeByte. At that point we're done, and suicide.
closeByte. At that point we're done, and we can exit.
**/
func consumeOpenClosePair(openByte, closeByte byte, in chan byte) ([]byte, chan byte) {
result := make([]byte, 0)

View File

@ -7,6 +7,7 @@ import (
"encoding/hex"
"os"
"path/filepath"
"strings"
)
func consumeString(s string) (out chan byte) {
@ -20,6 +21,13 @@ func consumeString(s string) (out chan byte) {
return
}
func collectIntoStringList(in chan string) (result []string) {
for item := range in {
result = append(result, item)
}
return
}
func uncommentFromString(s string) string {
inCh := consumeString(s)
out := uncomment(inCh)
@ -856,3 +864,223 @@ func TestParserReadDhcpdLeases(t *testing.T) {
}
}
}
func TestParserTokenizeNetworkingConfig(t *testing.T) {
tests := []string{
"words words words",
"newlines\n\n\n\n\n\n\n\nnewlines\r\r\r\r\r\r\r\rnewlines\n\n\n\n",
" newline-less",
}
expects := [][]string{
[]string{"words", "words", "words"},
[]string{"newlines", "\n", "newlines", "\n", "newlines", "\n"},
[]string{"newline-less"},
}
for testnum := 0; testnum < len(tests); testnum += 1 {
inCh := consumeString(tests[testnum])
outCh := tokenizeNetworkingConfig(inCh)
result := collectIntoStringList(outCh)
expected := expects[testnum]
if len(result) != len(expected) {
t.Errorf("test %d expected %d items, got %d instead", 1+testnum, len(expected), len(result))
continue
}
ok := true
for index := 0; index < len(expected); index += 1 {
if result[index] != expected[index] {
ok = false
}
}
if !ok {
t.Errorf("test %d expected %#v, got %#v", 1+testnum, expects[testnum], result)
}
}
}
func TestParserSplitNetworkingConfig(t *testing.T) {
tests := []string{
"this is a story\n\n\nabout some newlines",
"\n\n\nthat can begin and end with newlines\n\n\n",
" in\n\n\nsome\ncases\nit\ncan\nend\nwith\nan\nempty\nstring\n\n\n\n",
"\n\n\nand\nbegin\nwith\nan\nempty\nstring ",
}
expects := [][]string{
[]string{"this is a story", "about some newlines"},
[]string{"that can begin and end with newlines"},
[]string{"in", "some", "cases", "it", "can", "end", "with", "an", "empty", "string"},
[]string{"and", "begin", "with", "an", "empty", "string"},
}
for testnum := 0; testnum < len(tests); testnum += 1 {
inCh := consumeString(tests[testnum])
stringCh := tokenizeNetworkingConfig(inCh)
outCh := splitNetworkingConfig(stringCh)
result := make([]string, 0)
for item := range outCh {
result = append(result, strings.Join(item, " "))
}
expected := expects[testnum]
if len(result) != len(expected) {
t.Errorf("test %d expected %d items, got %d instead", 1+testnum, len(expected), len(result))
continue
}
ok := true
for index := 0; index < len(expected); index += 1 {
if result[index] != expected[index] {
ok = false
}
}
if !ok {
t.Errorf("test %d expected %#v, got %#v", 1+testnum, expects[testnum], result)
}
}
}
func TestParserParseNetworkingConfigVersion(t *testing.T) {
success_tests := []string{"VERSION=4,2"}
failure_tests := []string{
"VERSION=1=2",
"VERSION=3,4,5",
"VERSION=a,b",
}
for testnum := 0; testnum < len(success_tests); testnum += 1 {
test := []string{success_tests[testnum]}
if _, err := networkingReadVersion(test); err != nil {
t.Errorf("success-test %d parsing failed: %v", 1+testnum, err)
}
}
for testnum := 0; testnum < len(success_tests); testnum += 1 {
test := []string{failure_tests[testnum]}
if _, err := networkingReadVersion(test); err == nil {
t.Errorf("failure-test %d should have failed", 1+testnum)
}
}
}
func TestParserParseNetworkingConfigEntries(t *testing.T) {
tests := []string{
"answer VNET_999_ANYTHING option",
"remove_answer VNET_123_ALSOANYTHING",
"add_nat_portfwd 24 udp 42 127.0.0.1 24",
"remove_nat_portfwd 42 tcp 2502",
"add_dhcp_mac_to_ip 57005 00:0d:0e:0a:0d:00 127.0.0.2",
"remove_dhcp_mac_to_ip 57005 00:0d:0e:0a:0d:00",
"add_bridge_mapping string 51",
"remove_bridge_mapping string",
"add_nat_prefix 57005 /24",
"remove_nat_prefix 57005 /31",
}
for testnum := 0; testnum < len(tests); testnum += 1 {
test := strings.Split(tests[testnum], " ")
parser := NetworkingParserByCommand(test[0])
if parser == nil {
t.Errorf("test %d unable to parse command: %#v", 1+testnum, test)
continue
}
operand_parser := *parser
_, err := operand_parser(test[1:])
if err != nil {
t.Errorf("test %d unable to parse command parameters %#v: %v", 1+testnum, test, err)
}
}
}
func TestParserReadNetworingConfig(t *testing.T) {
expected_answer_vnet_1 := map[string]string{
"DHCP": "yes",
"DHCP_CFG_HASH": "01F4CE0D79A1599698B6E5814CCB68058BB0ED5E",
"HOSTONLY_NETMASK": "255.255.255.0",
"HOSTONLY_SUBNET": "192.168.70.0",
"NAT": "no",
"VIRTUAL_ADAPTER": "yes",
}
f, err := os.Open(filepath.Join("testdata", "networking-example"))
if err != nil {
t.Fatalf("Unable to open networking-example sample: %v", err)
}
defer f.Close()
config, err := ReadNetworkingConfig(f)
if err != nil {
t.Fatalf("error parsing networking-example: %v", err)
}
if vnet, ok := config.answer[1]; ok {
for ans_key := range expected_answer_vnet_1 {
result, ok := vnet[ans_key]
if !ok {
t.Errorf("unable to find key %s in VNET_%d answer", ans_key, 1)
continue
}
if result != expected_answer_vnet_1[ans_key] {
t.Errorf("expected key %s for VNET_%d to be %v, got %v", ans_key, 1, expected_answer_vnet_1[ans_key], result)
}
}
} else {
t.Errorf("unable to find VNET_%d answer", 1)
}
expected_answer_vnet_8 := map[string]string{
"DHCP": "yes",
"DHCP_CFG_HASH": "C30F14F65A0FE4B5DCC6C67497D7A8A33E5E538C",
"HOSTONLY_NETMASK": "255.255.255.0",
"HOSTONLY_SUBNET": "172.16.41.0",
"NAT": "yes",
"VIRTUAL_ADAPTER": "yes",
}
if vnet, ok := config.answer[8]; ok {
for ans_key := range expected_answer_vnet_8 {
result, ok := vnet[ans_key]
if !ok {
t.Errorf("unable to find key %s in VNET_%d answer", ans_key, 8)
continue
}
if result != expected_answer_vnet_8[ans_key] {
t.Errorf("expected key %s for VNET_%d to be %v, got %v", ans_key, 8, expected_answer_vnet_8[ans_key], result)
}
}
} else {
t.Errorf("unable to find VNET_%d answer", 8)
}
expected_nat_portfwd_8 := map[string]string{
"tcp/2200": "172.16.41.129:3389",
"tcp/2201": "172.16.41.129:3389",
"tcp/2222": "172.16.41.129:22",
"tcp/3389": "172.16.41.131:3389",
"tcp/55985": "172.16.41.129:5985",
"tcp/55986": "172.16.41.129:5986",
}
if vnet, ok := config.nat_portfwd[8-1]; ok {
for nat_key := range expected_nat_portfwd_8 {
result, ok := vnet[nat_key]
if !ok {
t.Errorf("unable to find key %s in VNET_%d nat_portfwd", nat_key, 8)
continue
}
if result != expected_nat_portfwd_8[nat_key] {
t.Errorf("expected key %s for VNET_%d to be %v, got %v", nat_key, 8, expected_nat_portfwd_8[nat_key], result)
}
}
} else {
t.Errorf("unable to find VNET_%d answer", 8-1)
}
}

View File

@ -0,0 +1,19 @@
VERSION=1,0
answer VNET_1_DHCP yes
answer VNET_1_DHCP_CFG_HASH 01F4CE0D79A1599698B6E5814CCB68058BB0ED5E
answer VNET_1_HOSTONLY_NETMASK 255.255.255.0
answer VNET_1_HOSTONLY_SUBNET 192.168.70.0
answer VNET_1_NAT no
answer VNET_1_VIRTUAL_ADAPTER yes
answer VNET_8_DHCP yes
answer VNET_8_DHCP_CFG_HASH C30F14F65A0FE4B5DCC6C67497D7A8A33E5E538C
answer VNET_8_HOSTONLY_NETMASK 255.255.255.0
answer VNET_8_HOSTONLY_SUBNET 172.16.41.0
answer VNET_8_NAT yes
answer VNET_8_VIRTUAL_ADAPTER yes
add_nat_portfwd 8 tcp 2200 172.16.41.129 3389
add_nat_portfwd 8 tcp 2201 172.16.41.129 3389
add_nat_portfwd 8 tcp 2222 172.16.41.129 22
add_nat_portfwd 8 tcp 3389 172.16.41.131 3389
add_nat_portfwd 8 tcp 55985 172.16.41.129 5985
add_nat_portfwd 8 tcp 55986 172.16.41.129 5986