github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/burst_test.go (about)

     1  /*
     2   * Copyright (c) 2020, Psiphon Inc.
     3   * All rights reserved.
     4   *
     5   * This program is free software: you can redistribute it and/or modify
     6   * it under the terms of the GNU General Public License as published by
     7   * the Free Software Foundation, either version 3 of the License, or
     8   * (at your option) any later version.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package common
    21  
    22  import (
    23  	"testing"
    24  	"time"
    25  )
    26  
    27  func TestBurstMonitoredConn(t *testing.T) {
    28  
    29  	upstreamTargetBytes := int64(100000)
    30  	downstreamTargetBytes := int64(1000000)
    31  	burstDeadline := 1 * time.Second
    32  
    33  	baseTime := time.Now()
    34  
    35  	dummy := &dummyConn{}
    36  
    37  	conn := NewBurstMonitoredConn(
    38  		dummy,
    39  		true,
    40  		upstreamTargetBytes,
    41  		burstDeadline,
    42  		downstreamTargetBytes,
    43  		burstDeadline)
    44  
    45  	// Simulate 128KB/s up, 1MB/s down; transmit >= min bytes in segments; sets "first" and "min"
    46  
    47  	dummy.SetRateLimits(131072, 1048576)
    48  
    49  	segments := 10
    50  
    51  	b := make([]byte, int(upstreamTargetBytes)/segments)
    52  	firstReadStart := time.Now()
    53  	for i := 0; i < segments; i++ {
    54  		conn.Read(b)
    55  	}
    56  	firstReadEnd := time.Now()
    57  
    58  	b = make([]byte, int(downstreamTargetBytes)/segments)
    59  	firstWriteStart := time.Now()
    60  	for i := 0; i < segments; i++ {
    61  		conn.Write(b)
    62  	}
    63  	firstWriteEnd := time.Now()
    64  
    65  	time.Sleep(burstDeadline * 2)
    66  
    67  	// Simulate 1MB/s up, 10MB/s down; repeatedly transmit < min bytes before deadline; ignored
    68  
    69  	dummy.SetRateLimits(1048576, 10485760)
    70  
    71  	b = make([]byte, 1)
    72  	segments = 1000
    73  	for i := 0; i < segments; i++ {
    74  		conn.Read(b)
    75  	}
    76  	for i := 0; i < segments; i++ {
    77  		conn.Write(b)
    78  	}
    79  
    80  	time.Sleep(burstDeadline * 2)
    81  
    82  	// Simulate 512Kb/s up, 5MB/s down; transmit >= min bytes; sets "max"
    83  
    84  	dummy.SetRateLimits(524288, 5242880)
    85  
    86  	maxReadStart := time.Now()
    87  	conn.Read(make([]byte, upstreamTargetBytes))
    88  	maxReadEnd := time.Now()
    89  
    90  	maxWriteStart := time.Now()
    91  	conn.Write(make([]byte, downstreamTargetBytes))
    92  	maxWriteEnd := time.Now()
    93  
    94  	time.Sleep(burstDeadline * 2)
    95  
    96  	// Simulate 256Kb/s up, 2MB/s down;, transmit >= min bytes; sets "last"
    97  
    98  	dummy.SetRateLimits(262144, 2097152)
    99  
   100  	lastReadStart := time.Now()
   101  	conn.Read(make([]byte, upstreamTargetBytes))
   102  	lastReadEnd := time.Now()
   103  
   104  	lastWriteStart := time.Now()
   105  	conn.Write(make([]byte, downstreamTargetBytes))
   106  	lastWriteEnd := time.Now()
   107  
   108  	time.Sleep(burstDeadline * 2)
   109  
   110  	conn.Close()
   111  
   112  	t.Logf("upstream first:    %d bytes in %s; %d bytes/s",
   113  		conn.readBursts.first.bytes, conn.readBursts.first.duration(), conn.readBursts.first.rate())
   114  	t.Logf("upstream last:     %d bytes in %s; %d bytes/s",
   115  		conn.readBursts.last.bytes, conn.readBursts.last.duration(), conn.readBursts.last.rate())
   116  	t.Logf("upstream min:      %d bytes in %s; %d bytes/s",
   117  		conn.readBursts.min.bytes, conn.readBursts.min.duration(), conn.readBursts.min.rate())
   118  	t.Logf("upstream max:      %d bytes in %s; %d bytes/s",
   119  		conn.readBursts.max.bytes, conn.readBursts.max.duration(), conn.readBursts.max.rate())
   120  	t.Logf("downstream first:  %d bytes in %s; %d bytes/s",
   121  		conn.writeBursts.first.bytes, conn.writeBursts.first.duration(), conn.writeBursts.first.rate())
   122  	t.Logf("downstream last:   %d bytes in %s; %d bytes/s",
   123  		conn.writeBursts.last.bytes, conn.writeBursts.last.duration(), conn.writeBursts.last.rate())
   124  	t.Logf("downstream min:    %d bytes in %s; %d bytes/s",
   125  		conn.writeBursts.min.bytes, conn.writeBursts.min.duration(), conn.writeBursts.min.rate())
   126  	t.Logf("downstream max:    %d bytes in %s; %d bytes/s",
   127  		conn.writeBursts.max.bytes, conn.writeBursts.max.duration(), conn.writeBursts.max.rate())
   128  
   129  	logFields := conn.GetMetrics(baseTime)
   130  
   131  	if len(logFields) != 32 {
   132  		t.Errorf("unexpected metric count: %d", len(logFields))
   133  	}
   134  
   135  	for name, expectedValue := range map[string]int64{
   136  		"burst_upstream_first_offset":     int64(firstReadStart.Sub(baseTime) / time.Millisecond),
   137  		"burst_upstream_first_duration":   int64(firstReadEnd.Sub(firstReadStart) / time.Millisecond),
   138  		"burst_upstream_first_bytes":      upstreamTargetBytes,
   139  		"burst_upstream_first_rate":       131072,
   140  		"burst_upstream_last_offset":      int64(lastReadStart.Sub(baseTime) / time.Millisecond),
   141  		"burst_upstream_last_duration":    int64(lastReadEnd.Sub(lastReadStart) / time.Millisecond),
   142  		"burst_upstream_last_bytes":       upstreamTargetBytes,
   143  		"burst_upstream_last_rate":        262144,
   144  		"burst_upstream_min_offset":       int64(firstReadStart.Sub(baseTime) / time.Millisecond),
   145  		"burst_upstream_min_duration":     int64(firstReadEnd.Sub(firstReadStart) / time.Millisecond),
   146  		"burst_upstream_min_bytes":        upstreamTargetBytes,
   147  		"burst_upstream_min_rate":         131072,
   148  		"burst_upstream_max_offset":       int64(maxReadStart.Sub(baseTime) / time.Millisecond),
   149  		"burst_upstream_max_duration":     int64(maxReadEnd.Sub(maxReadStart) / time.Millisecond),
   150  		"burst_upstream_max_bytes":        upstreamTargetBytes,
   151  		"burst_upstream_max_rate":         524288,
   152  		"burst_downstream_first_offset":   int64(firstWriteStart.Sub(baseTime) / time.Millisecond),
   153  		"burst_downstream_first_duration": int64(firstWriteEnd.Sub(firstWriteStart) / time.Millisecond),
   154  		"burst_downstream_first_bytes":    downstreamTargetBytes,
   155  		"burst_downstream_first_rate":     1048576,
   156  		"burst_downstream_last_offset":    int64(lastWriteStart.Sub(baseTime) / time.Millisecond),
   157  		"burst_downstream_last_duration":  int64(lastWriteEnd.Sub(lastWriteStart) / time.Millisecond),
   158  		"burst_downstream_last_bytes":     downstreamTargetBytes,
   159  		"burst_downstream_last_rate":      2097152,
   160  		"burst_downstream_min_offset":     int64(firstWriteStart.Sub(baseTime) / time.Millisecond),
   161  		"burst_downstream_min_duration":   int64(firstWriteEnd.Sub(firstWriteStart) / time.Millisecond),
   162  		"burst_downstream_min_bytes":      downstreamTargetBytes,
   163  		"burst_downstream_min_rate":       1048576,
   164  		"burst_downstream_max_offset":     int64(maxWriteStart.Sub(baseTime) / time.Millisecond),
   165  		"burst_downstream_max_duration":   int64(maxWriteEnd.Sub(maxWriteStart) / time.Millisecond),
   166  		"burst_downstream_max_bytes":      downstreamTargetBytes,
   167  		"burst_downstream_max_rate":       5242880,
   168  	} {
   169  		value, ok := logFields[name]
   170  		if !ok {
   171  			t.Errorf("missing expected metric: %s", name)
   172  			continue
   173  		}
   174  		valueInt64, ok := value.(int64)
   175  		if !ok {
   176  			t.Errorf("missing expected metric type: %s (%T)", name, value)
   177  			continue
   178  		}
   179  		minAcceptable := int64(float64(expectedValue) * 0.90)
   180  		maxAcceptable := int64(float64(expectedValue) * 1.10)
   181  		if valueInt64 < minAcceptable || valueInt64 > maxAcceptable {
   182  			t.Errorf("unexpected metric value: %s (%v <= %v <= %v)",
   183  				name, minAcceptable, valueInt64, maxAcceptable)
   184  			continue
   185  		}
   186  	}
   187  }