package openvpn import ( "fmt" "testing" ) // A key requirement of our event parsing is that it must never cause a // panic, even if the OpenVPN process sends us malformed garbage. // // Therefore most of the tests in here are testing various tortured error // cases, which are all expected to produce an event object, though the // contents of that event object will be nonsensical if the OpenVPN server // sends something nonsensical. func TestMalformedEvent(t *testing.T) { testCases := [][]byte{ []byte(""), []byte("HTTP/1.1 200 OK"), []byte(" "), []byte("\x00"), } for i, testCase := range testCases { event := upgradeEvent(testCase) var malformed *MalformedEvent var ok bool if malformed, ok = event.(*MalformedEvent); !ok { t.Errorf("test %d got %T; want %T", i, event, malformed) continue } wantString := fmt.Sprintf("Malformed Event %q", testCase) if gotString := malformed.String(); gotString != wantString { t.Errorf("test %d String returned %q; want %q", i, gotString, wantString) } } } func TestUnknownEvent(t *testing.T) { type TestCase struct { Input []byte WantType string WantBody string } testCases := []TestCase{ { Input: []byte("DUMMY:baz"), WantType: "DUMMY", WantBody: "baz", }, { Input: []byte("DUMMY:"), WantType: "DUMMY", WantBody: "", }, { Input: []byte("DUMMY:abc,123,456"), WantType: "DUMMY", WantBody: "abc,123,456", }, } for i, testCase := range testCases { event := upgradeEvent(testCase.Input) var unk *UnknownEvent var ok bool if unk, ok = event.(*UnknownEvent); !ok { t.Errorf("test %d got %T; want %T", i, event, unk) continue } if got, want := unk.Type(), testCase.WantType; got != want { t.Errorf("test %d Type returned %q; want %q", i, got, want) } if got, want := unk.Body(), testCase.WantBody; got != want { t.Errorf("test %d Body returned %q; want %q", i, got, want) } } } func TestHoldEvent(t *testing.T) { testCases := [][]byte{ []byte("HOLD:"), []byte("HOLD:waiting for hold release"), } for i, testCase := range testCases { event := upgradeEvent(testCase) var hold *HoldEvent var ok bool if hold, ok = event.(*HoldEvent); !ok { t.Errorf("test %d got %T; want %T", i, event, hold) continue } } } func TestEchoEvent(t *testing.T) { type TestCase struct { Input []byte WantTimestamp string WantMessage string } testCases := []TestCase{ { Input: []byte("ECHO:123,foo"), WantTimestamp: "123", WantMessage: "foo", }, { Input: []byte("ECHO:123,"), WantTimestamp: "123", WantMessage: "", }, { Input: []byte("ECHO:,foo"), WantTimestamp: "", WantMessage: "foo", }, { Input: []byte("ECHO:,"), WantTimestamp: "", WantMessage: "", }, { Input: []byte("ECHO:"), WantTimestamp: "", WantMessage: "", }, } for i, testCase := range testCases { event := upgradeEvent(testCase.Input) var echo *EchoEvent var ok bool if echo, ok = event.(*EchoEvent); !ok { t.Errorf("test %d got %T; want %T", i, event, echo) continue } if got, want := echo.RawTimestamp(), testCase.WantTimestamp; got != want { t.Errorf("test %d RawTimestamp returned %q; want %q", i, got, want) } if got, want := echo.Message(), testCase.WantMessage; got != want { t.Errorf("test %d Message returned %q; want %q", i, got, want) } } } func TestStateEvent(t *testing.T) { type TestCase struct { Input []byte WantTimestamp string WantState string WantDesc string WantLocalAddr string WantRemoteAddr string } testCases := []TestCase{ { Input: []byte("STATE:"), WantTimestamp: "", WantState: "", WantDesc: "", WantLocalAddr: "", WantRemoteAddr: "", }, { Input: []byte("STATE:,"), WantTimestamp: "", WantState: "", WantDesc: "", WantLocalAddr: "", WantRemoteAddr: "", }, { Input: []byte("STATE:,,,,"), WantTimestamp: "", WantState: "", WantDesc: "", WantLocalAddr: "", WantRemoteAddr: "", }, { Input: []byte("STATE:123,CONNECTED,good,172.16.0.1,192.168.4.1"), WantTimestamp: "123", WantState: "CONNECTED", WantDesc: "good", WantLocalAddr: "172.16.0.1", WantRemoteAddr: "192.168.4.1", }, { Input: []byte("STATE:123,RECONNECTING,SIGHUP,,"), WantTimestamp: "123", WantState: "RECONNECTING", WantDesc: "SIGHUP", WantLocalAddr: "", WantRemoteAddr: "", }, { Input: []byte("STATE:123,RECONNECTING,SIGHUP,,,extra"), WantTimestamp: "123", WantState: "RECONNECTING", WantDesc: "SIGHUP", WantLocalAddr: "", WantRemoteAddr: "", }, } for i, testCase := range testCases { event := upgradeEvent(testCase.Input) var st *StateEvent var ok bool if st, ok = event.(*StateEvent); !ok { t.Errorf("test %d got %T; want %T", i, event, st) continue } if got, want := st.RawTimestamp(), testCase.WantTimestamp; got != want { t.Errorf("test %d RawTimestamp returned %q; want %q", i, got, want) } if got, want := st.NewState(), testCase.WantState; got != want { t.Errorf("test %d NewState returned %q; want %q", i, got, want) } if got, want := st.Description(), testCase.WantDesc; got != want { t.Errorf("test %d Description returned %q; want %q", i, got, want) } if got, want := st.LocalTunnelAddr(), testCase.WantLocalAddr; got != want { t.Errorf("test %d LocalTunnelAddr returned %q; want %q", i, got, want) } if got, want := st.RemoteAddr(), testCase.WantRemoteAddr; got != want { t.Errorf("test %d RemoteAddr returned %q; want %q", i, got, want) } } } func TestByteCountEvent(t *testing.T) { type TestCase struct { Input []byte WantClientId string WantBytesIn int WantBytesOut int } testCases := []TestCase{ { Input: []byte("BYTECOUNT:"), WantClientId: "", WantBytesIn: 0, WantBytesOut: 0, }, { Input: []byte("BYTECOUNT:123,456"), WantClientId: "", WantBytesIn: 123, WantBytesOut: 456, }, { Input: []byte("BYTECOUNT:,"), WantClientId: "", WantBytesIn: 0, WantBytesOut: 0, }, { Input: []byte("BYTECOUNT:5,"), WantClientId: "", WantBytesIn: 5, WantBytesOut: 0, }, { Input: []byte("BYTECOUNT:,6"), WantClientId: "", WantBytesIn: 0, WantBytesOut: 6, }, { Input: []byte("BYTECOUNT:6"), WantClientId: "", WantBytesIn: 6, WantBytesOut: 0, }, { Input: []byte("BYTECOUNT:wrong,bad"), WantClientId: "", WantBytesIn: 0, WantBytesOut: 0, }, { Input: []byte("BYTECOUNT:1,2,3"), WantClientId: "", WantBytesIn: 1, WantBytesOut: 2, }, { // Intentionally malformed BYTECOUNT event sent as BYTECOUNT_CLI Input: []byte("BYTECOUNT_CLI:123,456"), WantClientId: "123", WantBytesIn: 456, WantBytesOut: 0, }, { Input: []byte("BYTECOUNT_CLI:"), WantClientId: "", WantBytesIn: 0, WantBytesOut: 0, }, { Input: []byte("BYTECOUNT_CLI:abc123,123,456"), WantClientId: "abc123", WantBytesIn: 123, WantBytesOut: 456, }, { Input: []byte("BYTECOUNT_CLI:abc123,123"), WantClientId: "abc123", WantBytesIn: 123, WantBytesOut: 0, }, } for i, testCase := range testCases { event := upgradeEvent(testCase.Input) var bc *ByteCountEvent var ok bool if bc, ok = event.(*ByteCountEvent); !ok { t.Errorf("test %d got %T; want %T", i, event, bc) continue } if got, want := bc.ClientId(), testCase.WantClientId; got != want { t.Errorf("test %d ClientId returned %q; want %q", i, got, want) } if got, want := bc.BytesIn(), testCase.WantBytesIn; got != want { t.Errorf("test %d BytesIn returned %d; want %d", i, got, want) } if got, want := bc.BytesOut(), testCase.WantBytesOut; got != want { t.Errorf("test %d BytesOut returned %d; want %d", i, got, want) } } }