github.com/google/cloudprober@v0.11.3/common/message/message_test.go (about)

     1  // Copyright 2017-2018 The Cloudprober Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package message
    16  
    17  import (
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/golang/protobuf/proto"
    22  	msgpb "github.com/google/cloudprober/common/message/proto"
    23  )
    24  
    25  // createMessage is a helper function for creating a message and fatally failing
    26  // if CreateMessage fails. This is for use in places where we don't expect
    27  // CreateMessage to fail.
    28  func createMessage(t *testing.T, fs *FlowState, ts time.Time) ([]byte, uint64) {
    29  	return createMessageWithPayload(t, fs, ts, nil)
    30  }
    31  
    32  // createMessageWithPayload is a helper function for creating a message and
    33  // fatally failing if CreateMessage fails. This is for use in places where we
    34  // don't expect CreateMessage to fail.
    35  func createMessageWithPayload(t *testing.T, fs *FlowState, ts time.Time, payload []byte) ([]byte, uint64) {
    36  	maxLen := 1024
    37  	msgBytes, msgSeq, err := fs.CreateMessage(ts, payload, maxLen)
    38  	if err != nil {
    39  		t.Fatalf("Error creating message for seq %d: %v", fs.seq+1, err)
    40  	}
    41  	return msgBytes, msgSeq
    42  }
    43  
    44  // TestUint64Conversion tests the conversion of uint64 from and to network byte order.
    45  func TestUint64Conversion(t *testing.T) {
    46  	val := uint64(0)
    47  	for i := uint64(0); i < 10; i++ {
    48  		inp := val + i
    49  		bytes := Uint64ToNetworkBytes(val + i)
    50  		out := NetworkBytesToUint64(bytes)
    51  		if inp != out {
    52  			t.Errorf("Conversion pipeline failed: got %d want %d", out, inp)
    53  		}
    54  		inp = val - i
    55  		bytes = Uint64ToNetworkBytes(inp)
    56  		out = NetworkBytesToUint64(bytes)
    57  		if inp != out {
    58  			t.Errorf("Conversion pipeline failed: got %d want %d", out, inp)
    59  		}
    60  	}
    61  }
    62  
    63  // TestMessageEncodeDecode tests encoding/decoding of properly formed msgs.
    64  func TestMessageEncodeDecode(t *testing.T) {
    65  	txFSM := NewFlowStateMap()
    66  	rxFSM := NewFlowStateMap()
    67  
    68  	src := "aa-src"
    69  	dst := "zz-dst"
    70  	seq := uint64(100)
    71  	ts := time.Now().Truncate(time.Microsecond)
    72  
    73  	txFS := txFSM.FlowState(src, "", dst)
    74  	txFS.seq = seq - 1
    75  	msgBytes, msgSeq := createMessage(t, txFS, ts)
    76  	if msgSeq != seq {
    77  		t.Errorf("Incorrect seq in message: got %d want %d", msgSeq, seq)
    78  	}
    79  
    80  	// Pre-create flow state on the rx side. So we expect success in every step.
    81  	rxFS := rxFSM.FlowState(src, "", dst)
    82  	rxFS.seq = seq - 1
    83  	msg, err := NewMessage(msgBytes)
    84  	if err != nil {
    85  		t.Fatalf("Process message failure: %v", err)
    86  	}
    87  	if msg.Src() != src || msg.Dst() != dst {
    88  		t.Errorf("Message content error (src, dst): got (%s, %s) want (%s, %s)", msg.Src(), msg.Dst(), src, dst)
    89  	}
    90  	res := msg.ProcessOneWay(rxFSM, ts.Add(time.Second))
    91  	if rxFS.seq != seq {
    92  		t.Errorf("Seq number mismatch. got %d want %d. %v %v", rxFS.seq, seq, rxFS, res)
    93  	}
    94  	if !res.Success || res.LostCount > 0 || res.Delayed {
    95  		t.Errorf("Success, lostCount, delayed mismatch. got (%v %v %v) want (%v %v %v)",
    96  			res.Success, res.LostCount, res.Delayed, true, 0, false)
    97  	}
    98  }
    99  
   100  // TestInvalidMessages tests encoding/decoding error paths.
   101  func TestInvalidMessage(t *testing.T) {
   102  	fss := NewFlowStateMap()
   103  
   104  	src := "aa-src"
   105  	dst := "zz-dst"
   106  	seq := uint64(100)
   107  	ts := time.Now().Truncate(time.Microsecond)
   108  	maxLen := 10
   109  
   110  	fs := fss.FlowState(src, "", dst)
   111  	if msgBytes, _, err := fs.CreateMessage(ts, nil, maxLen); err == nil {
   112  		t.Errorf("Message too long(%d) for maxlen(%d) but did not fail.", len(msgBytes), maxLen)
   113  	}
   114  
   115  	// Invalid magic.
   116  	msg := &msgpb.Msg{
   117  		Magic: proto.Uint64(constants.GetMagic() + 1),
   118  		Seq:   Uint64ToNetworkBytes(seq),
   119  		Src: &msgpb.DataNode{
   120  			Name: proto.String(src),
   121  		},
   122  		Dst: &msgpb.DataNode{
   123  			Name: proto.String(dst),
   124  		},
   125  	}
   126  	msgBytes, err := proto.Marshal(msg)
   127  	if err != nil {
   128  		t.Fatalf("Error marshalling message: %v", err)
   129  	}
   130  
   131  	if _, err := NewMessage(msgBytes); err == nil {
   132  		t.Error("ProcessMessage expected to fail due to invalid magic but did not fail")
   133  	}
   134  }
   135  
   136  // TestSeqHandling tests various sequence number cases.
   137  func TestSeqHandling(t *testing.T) {
   138  	txFSM := NewFlowStateMap()
   139  	rxFSM := NewFlowStateMap()
   140  
   141  	src := "aa-src"
   142  	dst := "zz-dst"
   143  	seq := uint64(100)
   144  	pktTS := time.Now().Truncate(time.Microsecond)
   145  	rxTS := pktTS.Add(time.Millisecond)
   146  
   147  	// Create a message and revert it.
   148  	txFS := txFSM.FlowState(src, "1", dst)
   149  	txFS.seq = seq - 1
   150  	msgBytes, msgSeq := createMessage(t, txFS, pktTS)
   151  
   152  	if !txFS.WithdrawMessage(msgSeq) || txFS.seq != seq-1 {
   153  		t.Errorf("WithdrawMessage failed: NextSeq %d msgSeq %d fs.seq %d", seq, msgSeq, txFS.seq)
   154  	}
   155  	// withdraw an older message and expect failure.
   156  	if txFS.WithdrawMessage(seq - 2) {
   157  		t.Errorf("WithdrawMessage succeeded: msgSeq %d fs.seq %d", seq-2, txFS.seq)
   158  	}
   159  
   160  	txFS.seq = seq - 1
   161  	msgBytes, msgSeq = createMessage(t, txFS, pktTS)
   162  	// Receive the message and process it. Seq and srcs should match.
   163  	// This will be the first message for the flow:
   164  	//		=> Flowstate should be created.
   165  	// 		=> We expect success in the result.
   166  	msg, err := NewMessage(msgBytes)
   167  	if err != nil {
   168  		t.Fatalf("Error processing message: %v", err)
   169  	}
   170  	res := msg.ProcessOneWay(rxFSM, rxTS)
   171  	rxFS := res.FS
   172  	if rxFS == nil || rxFSM.FlowState(src, "1", dst) != rxFS {
   173  		t.Errorf("Expected sender to appear in FlowStateMap struct, got %v", rxFSM.FlowState(src, "1", dst))
   174  	}
   175  	if rxFS.src != src {
   176  		t.Errorf("Message content error - src: got %s want %s", rxFS.src, src)
   177  	}
   178  	if rxFS.srcPort != "1" {
   179  		t.Errorf("Message content error - srcPort: got %s want 1", rxFS.srcPort)
   180  	}
   181  	if rxFS.seq != seq {
   182  		t.Errorf("Seq number mismatch. got %d want %d.", rxFS.seq, seq)
   183  	}
   184  	if !res.Success || res.LostCount > 0 || res.Delayed {
   185  		t.Errorf("Success, lostCount, delayed mismatch. got (%v %v %v) want (%v %v %v)",
   186  			res.Success, res.LostCount, res.Delayed, true, 0, false)
   187  	}
   188  
   189  	// Send a message with an older seq number.
   190  	pktTS = pktTS.Add(time.Second)
   191  	rxTS = rxTS.Add(time.Second)
   192  	txFS.seq = seq - 10
   193  	msgBytes, msgSeq = createMessage(t, txFS, pktTS)
   194  	if res.FS.msgTS == pktTS || res.FS.rxTS == rxTS {
   195  		t.Errorf("Timestamps not updated. got (%s, %s) want (%s, %s)", res.FS.msgTS, res.FS.rxTS, pktTS, rxTS)
   196  	}
   197  
   198  	// Send a message with seq+1.
   199  	// 		pktTS = prevPktTS + 1sec.
   200  	// 		rxTS = prevRxTS + 1 sec + 1 millisecond.
   201  	// 		=> ipd = 1 millisecond
   202  	ipd := time.Millisecond
   203  	pktTS = pktTS.Add(time.Second)
   204  	rxTS = rxTS.Add(time.Second + ipd)
   205  	txFS.seq = seq
   206  	msgBytes, msgSeq = createMessage(t, txFS, pktTS)
   207  	if msg, err = NewMessage(msgBytes); err != nil {
   208  		t.Fatalf("Error processing message: %v", err)
   209  	}
   210  	res = msg.ProcessOneWay(rxFSM, rxTS)
   211  	rxFS = res.FS
   212  	if !res.Success {
   213  		t.Errorf("Got failure, want success. tx seq: %d, rx want seq: %d", txFS.seq, rxFS.seq+1)
   214  	}
   215  	if res.InterPktDelay != ipd {
   216  		t.Errorf("InterPktDelay calculation error got %v want %v", res.InterPktDelay, ipd)
   217  	}
   218  	if res.FS.msgTS != pktTS || res.FS.rxTS != rxTS {
   219  		t.Errorf("Timestamps not updated. got (%s, %s) want (%s, %s)", res.FS.msgTS, res.FS.rxTS, pktTS, rxTS)
   220  	}
   221  
   222  	// Send a message with lost packets = 10.
   223  	lost := 10
   224  	txFS.seq += uint64(lost)
   225  	pktTS = pktTS.Add(time.Second)
   226  	rxTS = rxTS.Add(time.Second)
   227  	msgBytes, msgSeq = createMessage(t, txFS, pktTS)
   228  	if msg, err = NewMessage(msgBytes); err != nil {
   229  		t.Fatalf("Error processing message: %v", err)
   230  	}
   231  	res = msg.ProcessOneWay(rxFSM, rxTS)
   232  	rxFS = res.FS
   233  	if res.Success {
   234  		t.Error("Got success, want failure.")
   235  	}
   236  	if res.LostCount != lost {
   237  		t.Errorf("Got lostcount=%d want %d tx seq: %d, rx want seq: %d", res.LostCount, lost, txFS.seq, rxFS.seq+1)
   238  	}
   239  	if res.FS.msgTS != pktTS || res.FS.rxTS != rxTS {
   240  		t.Errorf("Timestamps not updated. got (%s, %s) want (%s, %s)", res.FS.msgTS, res.FS.rxTS, pktTS, rxTS)
   241  	}
   242  }
   243  
   244  // TestMultiplePorts seq handling for multiple src ports.
   245  func TestMultiplePorts(t *testing.T) {
   246  	txFSM := NewFlowStateMap()
   247  	rxFSM := NewFlowStateMap()
   248  
   249  	src := "aa-src"
   250  	dst := "zz-dst"
   251  	seq := uint64(100)
   252  	pktTS := time.Now().Truncate(time.Microsecond)
   253  	rxTS := pktTS.Add(time.Millisecond)
   254  
   255  	// Receive the message and process it. Seq and srcs should match.
   256  	// This will be the first message for the flow => Flowstate should be created.
   257  	txFS1 := txFSM.FlowState(src, "1", dst)
   258  	txFS1.seq = seq - 1
   259  	msgBytes, _ := createMessage(t, txFS1, pktTS)
   260  	msg, err := NewMessage(msgBytes)
   261  	if err != nil {
   262  		t.Fatalf("Error processing message: %v", err)
   263  	}
   264  	res := msg.ProcessOneWay(rxFSM, rxTS)
   265  
   266  	// Send a message with seq+1.
   267  	// 		pktTS = prevPktTS + 1sec.
   268  	// 		rxTS = prevRxTS + 1 sec + 1 millisecond.
   269  	// 		=> ipd = 1 millisecond
   270  	ipd := time.Millisecond
   271  	pktTS = pktTS.Add(time.Second)
   272  	rxTS = rxTS.Add(time.Second + ipd)
   273  	txFS1.seq = seq
   274  	msgBytes, _ = createMessage(t, txFS1, pktTS)
   275  	msg, err = NewMessage(msgBytes)
   276  	if err != nil {
   277  		t.Fatalf("Error processing message: %v", err)
   278  	}
   279  	res = msg.ProcessOneWay(rxFSM, rxTS)
   280  	rxFS1 := res.FS
   281  	if rxFS1 == nil || rxFSM.FlowState(src, "1", dst) != rxFS1 {
   282  		t.Errorf("Expected sender to appear in FlowStateMap struct, got %v", rxFSM.FlowState(src, "1", dst))
   283  	}
   284  	if !res.Success {
   285  		t.Errorf("Got failure, want success. tx seq: %d, rx want seq: %d", txFS1.seq, rxFS1.seq+1)
   286  	}
   287  	if res.InterPktDelay != ipd {
   288  		t.Errorf("InterPktDelay calculation error got %v want %v", res.InterPktDelay, ipd)
   289  	}
   290  	if res.FS.msgTS != pktTS || res.FS.rxTS != rxTS {
   291  		t.Errorf("Timestamps not updated. got (%s, %s) want (%s, %s)", res.FS.msgTS, res.FS.rxTS, pktTS, rxTS)
   292  	}
   293  
   294  	// Send a message with seq+2 on another port.
   295  	//    should not be counted towards port=1 stats.
   296  	pktTS = pktTS.Add(time.Second)
   297  	rxTS = rxTS.Add(time.Second + ipd)
   298  	txFS2 := txFSM.FlowState(src, "2", dst)
   299  	txFS2.seq = seq + 1
   300  	msgBytes, _ = createMessage(t, txFS2, pktTS)
   301  	msg, err = NewMessage(msgBytes)
   302  	if err != nil {
   303  		t.Fatalf("Error processing message: %v", err)
   304  	}
   305  	// Inject flow state on rx side with seq == msg.Seq - 2 (=> one lost pkt).
   306  	rxFS2 := rxFSM.FlowState(src, "2", dst)
   307  	rxFS2.seq = msg.Seq() - 2
   308  	res = msg.ProcessOneWay(rxFSM, rxTS)
   309  	if rxFS2.seq != msg.Seq() {
   310  		t.Errorf("Flow state not updated, seq number mismatch. got %d want %d.", rxFS2.seq, msg.Seq())
   311  	}
   312  	if res.Success || res.LostCount != 1 || res.Delayed {
   313  		t.Errorf("Success, lostCount, delayed mismatch. got (%v %v %v) want (%v %v %v)",
   314  			res.Success, res.LostCount, res.Delayed, false, 1, false)
   315  	}
   316  }
   317  
   318  // TestMessagePayloadHandling tests payload handling of the messages.
   319  func TestMessagePayloadHandling(t *testing.T) {
   320  	txFSM := NewFlowStateMap()
   321  
   322  	testPayload := "cloudprober"
   323  
   324  	src := "aa-src"
   325  	dst := "zz-dst"
   326  	seq := uint64(100)
   327  	ts := time.Now().Truncate(time.Microsecond)
   328  
   329  	txFS := txFSM.FlowState(src, "", dst)
   330  	txFS.seq = seq - 1
   331  	msgBytes, msgSeq := createMessageWithPayload(t, txFS, ts, []byte(testPayload))
   332  	if msgSeq != seq {
   333  		t.Errorf("Incorrect seq in message: got %d want %d", msgSeq, seq)
   334  	}
   335  
   336  	msg, err := NewMessage(msgBytes)
   337  	if err != nil {
   338  		t.Fatalf("Process message failure: %v", err)
   339  	}
   340  	if msg.Src() != src || msg.Dst() != dst {
   341  		t.Errorf("Message content error (src, dst): got (%s, %s) want (%s, %s)", msg.Src(), msg.Dst(), src, dst)
   342  	}
   343  	if string(msg.Payload()) != testPayload {
   344  		t.Errorf("Message payload=%s, want=%s", string(msg.Payload()), testPayload)
   345  	}
   346  }