github.com/nats-io/nats-server/v2@v2.11.0-preview.2/server/util_test.go (about)

     1  // Copyright 2012-2018 The NATS Authors
     2  // Licensed under the Apache License, Version 2.0 (the "License");
     3  // you may not use this file except in compliance with the License.
     4  // You may obtain a copy of the License at
     5  //
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package server
    15  
    16  import (
    17  	"math"
    18  	"math/rand"
    19  	"net/url"
    20  	"reflect"
    21  	"strconv"
    22  	"sync"
    23  	"testing"
    24  	"time"
    25  )
    26  
    27  func TestParseSize(t *testing.T) {
    28  	if parseSize(nil) != -1 {
    29  		t.Fatal("Should error on nil byte slice")
    30  	}
    31  	n := []byte("12345678")
    32  	if pn := parseSize(n); pn != 12345678 {
    33  		t.Fatalf("Did not parse %q correctly, res=%d", n, pn)
    34  	}
    35  
    36  	n = []byte("12345invalid678")
    37  	if pn := parseSize(n); pn != -1 {
    38  		t.Fatalf("Should error on %q, res=%d", n, pn)
    39  	}
    40  }
    41  
    42  func TestParseSInt64(t *testing.T) {
    43  	if parseInt64(nil) != -1 {
    44  		t.Fatal("Should error on nil byte slice")
    45  	}
    46  	n := []byte("12345678")
    47  	if pn := parseInt64(n); pn != 12345678 {
    48  		t.Fatalf("Did not parse %q correctly, res=%d", n, pn)
    49  	}
    50  
    51  	n = []byte("12345invalid678")
    52  	if pn := parseInt64(n); pn != -1 {
    53  		t.Fatalf("Should error on %q, res=%d", n, pn)
    54  	}
    55  }
    56  
    57  func TestParseHostPort(t *testing.T) {
    58  	check := func(hostPort string, defaultPort int, expectedHost string, expectedPort int, expectedErr bool) {
    59  		h, p, err := parseHostPort(hostPort, defaultPort)
    60  		if expectedErr {
    61  			if err == nil {
    62  				stackFatalf(t, "Expected an error, did not get one")
    63  			}
    64  			// expected error, so we are done
    65  			return
    66  		}
    67  		if !expectedErr && err != nil {
    68  			stackFatalf(t, "Unexpected error: %v", err)
    69  		}
    70  		if expectedHost != h {
    71  			stackFatalf(t, "Expected host %q, got %q", expectedHost, h)
    72  		}
    73  		if expectedPort != p {
    74  			stackFatalf(t, "Expected port %d, got %d", expectedPort, p)
    75  		}
    76  	}
    77  	check("addr:1234", 5678, "addr", 1234, false)
    78  	check(" addr:1234 ", 5678, "addr", 1234, false)
    79  	check(" addr : 1234 ", 5678, "addr", 1234, false)
    80  	check("addr", 5678, "addr", 5678, false)
    81  	check(" addr ", 5678, "addr", 5678, false)
    82  	check("addr:-1", 5678, "addr", 5678, false)
    83  	check(" addr:-1 ", 5678, "addr", 5678, false)
    84  	check(" addr : -1 ", 5678, "addr", 5678, false)
    85  	check("addr:0", 5678, "addr", 5678, false)
    86  	check(" addr:0 ", 5678, "addr", 5678, false)
    87  	check(" addr : 0 ", 5678, "addr", 5678, false)
    88  	check("addr:addr", 0, "", 0, true)
    89  	check("addr:::1234", 0, "", 0, true)
    90  	check("", 0, "", 0, true)
    91  }
    92  
    93  func TestURLsAreEqual(t *testing.T) {
    94  	check := func(t *testing.T, u1Str, u2Str string, expectedSame bool) {
    95  		t.Helper()
    96  		u1, err := url.Parse(u1Str)
    97  		if err != nil {
    98  			t.Fatalf("Error parsing url %q: %v", u1Str, err)
    99  		}
   100  		u2, err := url.Parse(u2Str)
   101  		if err != nil {
   102  			t.Fatalf("Error parsing url %q: %v", u2Str, err)
   103  		}
   104  		same := urlsAreEqual(u1, u2)
   105  		if expectedSame && !same {
   106  			t.Fatalf("Expected %v and %v to be the same, they were not", u1, u2)
   107  		} else if !expectedSame && same {
   108  			t.Fatalf("Expected %v and %v to be different, they were not", u1, u2)
   109  		}
   110  	}
   111  	check(t, "nats://localhost:4222", "nats://localhost:4222", true)
   112  	check(t, "nats://ivan:pwd@localhost:4222", "nats://ivan:pwd@localhost:4222", true)
   113  	check(t, "nats://ivan@localhost:4222", "nats://ivan@localhost:4222", true)
   114  	check(t, "nats://ivan:@localhost:4222", "nats://ivan:@localhost:4222", true)
   115  	check(t, "nats://host1:4222", "nats://host2:4222", false)
   116  }
   117  
   118  func TestComma(t *testing.T) {
   119  	type testList []struct {
   120  		name, got, exp string
   121  	}
   122  
   123  	l := testList{
   124  		{"0", comma(0), "0"},
   125  		{"10", comma(10), "10"},
   126  		{"100", comma(100), "100"},
   127  		{"1,000", comma(1000), "1,000"},
   128  		{"10,000", comma(10000), "10,000"},
   129  		{"100,000", comma(100000), "100,000"},
   130  		{"10,000,000", comma(10000000), "10,000,000"},
   131  		{"10,100,000", comma(10100000), "10,100,000"},
   132  		{"10,010,000", comma(10010000), "10,010,000"},
   133  		{"10,001,000", comma(10001000), "10,001,000"},
   134  		{"123,456,789", comma(123456789), "123,456,789"},
   135  		{"maxint", comma(9.223372e+18), "9,223,372,000,000,000,000"},
   136  		{"math.maxint", comma(math.MaxInt64), "9,223,372,036,854,775,807"},
   137  		{"math.minint", comma(math.MinInt64), "-9,223,372,036,854,775,808"},
   138  		{"minint", comma(-9.223372e+18), "-9,223,372,000,000,000,000"},
   139  		{"-123,456,789", comma(-123456789), "-123,456,789"},
   140  		{"-10,100,000", comma(-10100000), "-10,100,000"},
   141  		{"-10,010,000", comma(-10010000), "-10,010,000"},
   142  		{"-10,001,000", comma(-10001000), "-10,001,000"},
   143  		{"-10,000,000", comma(-10000000), "-10,000,000"},
   144  		{"-100,000", comma(-100000), "-100,000"},
   145  		{"-10,000", comma(-10000), "-10,000"},
   146  		{"-1,000", comma(-1000), "-1,000"},
   147  		{"-100", comma(-100), "-100"},
   148  		{"-10", comma(-10), "-10"},
   149  	}
   150  
   151  	failed := false
   152  	for _, test := range l {
   153  		if test.got != test.exp {
   154  			t.Errorf("On %v, expected '%v', but got '%v'",
   155  				test.name, test.exp, test.got)
   156  			failed = true
   157  		}
   158  	}
   159  	if failed {
   160  		t.FailNow()
   161  	}
   162  }
   163  
   164  func TestURLRedaction(t *testing.T) {
   165  	redactionFromTo := []struct {
   166  		Full string
   167  		Safe string
   168  	}{
   169  		{"nats://foo:bar@example.org", "nats://foo:xxxxx@example.org"},
   170  		{"nats://foo@example.org", "nats://foo@example.org"},
   171  		{"nats://example.org", "nats://example.org"},
   172  		{"nats://example.org/foo?bar=1", "nats://example.org/foo?bar=1"},
   173  	}
   174  	var err error
   175  	listFull := make([]*url.URL, len(redactionFromTo))
   176  	listSafe := make([]*url.URL, len(redactionFromTo))
   177  	for i := range redactionFromTo {
   178  		r := redactURLString(redactionFromTo[i].Full)
   179  		if r != redactionFromTo[i].Safe {
   180  			t.Fatalf("Redacting URL [index %d] %q, expected %q got %q", i, redactionFromTo[i].Full, redactionFromTo[i].Safe, r)
   181  		}
   182  		if listFull[i], err = url.Parse(redactionFromTo[i].Full); err != nil {
   183  			t.Fatalf("Redacting URL index %d parse Full failed: %v", i, err)
   184  		}
   185  		if listSafe[i], err = url.Parse(redactionFromTo[i].Safe); err != nil {
   186  			t.Fatalf("Redacting URL index %d parse Safe failed: %v", i, err)
   187  		}
   188  	}
   189  	results := redactURLList(listFull)
   190  	if !reflect.DeepEqual(results, listSafe) {
   191  		t.Fatalf("Redacting URL list did not compare equal, even after each URL did")
   192  	}
   193  }
   194  
   195  func TestVersionAtLeast(t *testing.T) {
   196  	for _, test := range []struct {
   197  		version string
   198  		major   int
   199  		minor   int
   200  		update  int
   201  		result  bool
   202  	}{
   203  		{"2.0.0-beta", 1, 9, 9, true},
   204  		{"2.0.0", 1, 99, 9, true},
   205  		{"2.2.0", 2, 1, 9, true},
   206  		{"2.2.2", 2, 2, 2, true},
   207  		{"2.2.2", 2, 2, 3, false},
   208  		{"2.2.2", 2, 3, 2, false},
   209  		{"2.2.2", 3, 2, 2, false},
   210  		{"2.22.2", 3, 0, 0, false},
   211  		{"2.2.22", 2, 3, 0, false},
   212  		{"bad.version", 1, 2, 3, false},
   213  	} {
   214  		t.Run(_EMPTY_, func(t *testing.T) {
   215  			if res := versionAtLeast(test.version, test.major, test.minor, test.update); res != test.result {
   216  				t.Fatalf("For check version %q at least %d.%d.%d result should have been %v, got %v",
   217  					test.version, test.major, test.minor, test.update, test.result, res)
   218  			}
   219  		})
   220  	}
   221  }
   222  
   223  func BenchmarkParseInt(b *testing.B) {
   224  	b.SetBytes(1)
   225  	n := "12345678"
   226  	for i := 0; i < b.N; i++ {
   227  		strconv.ParseInt(n, 10, 0)
   228  	}
   229  }
   230  
   231  func BenchmarkParseSize(b *testing.B) {
   232  	b.SetBytes(1)
   233  	n := []byte("12345678")
   234  	for i := 0; i < b.N; i++ {
   235  		parseSize(n)
   236  	}
   237  }
   238  
   239  func deferUnlock(mu *sync.Mutex) {
   240  	mu.Lock()
   241  	defer mu.Unlock()
   242  	// see noDeferUnlock
   243  	if false {
   244  		return
   245  	}
   246  }
   247  
   248  func BenchmarkDeferMutex(b *testing.B) {
   249  	var mu sync.Mutex
   250  	b.SetBytes(1)
   251  	for i := 0; i < b.N; i++ {
   252  		deferUnlock(&mu)
   253  	}
   254  }
   255  
   256  func noDeferUnlock(mu *sync.Mutex) {
   257  	mu.Lock()
   258  	// prevent staticcheck warning about empty critical section
   259  	if false {
   260  		return
   261  	}
   262  	mu.Unlock()
   263  }
   264  
   265  func BenchmarkNoDeferMutex(b *testing.B) {
   266  	var mu sync.Mutex
   267  	b.SetBytes(1)
   268  	for i := 0; i < b.N; i++ {
   269  		noDeferUnlock(&mu)
   270  	}
   271  }
   272  
   273  func createTestSub() *subscription {
   274  	return &subscription{
   275  		subject: []byte("foo"),
   276  		queue:   []byte("bar"),
   277  		sid:     []byte("22"),
   278  	}
   279  }
   280  
   281  func BenchmarkArrayRand(b *testing.B) {
   282  	b.StopTimer()
   283  	r := rand.New(rand.NewSource(time.Now().UnixNano()))
   284  	// Create an array of 10 items
   285  	subs := []*subscription{}
   286  	for i := 0; i < 10; i++ {
   287  		subs = append(subs, createTestSub())
   288  	}
   289  	b.StartTimer()
   290  
   291  	for i := 0; i < b.N; i++ {
   292  		index := r.Intn(len(subs))
   293  		_ = subs[index]
   294  	}
   295  }
   296  
   297  func BenchmarkMapRange(b *testing.B) {
   298  	b.StopTimer()
   299  	// Create an map of 10 items
   300  	subs := map[int]*subscription{}
   301  	for i := 0; i < 10; i++ {
   302  		subs[i] = createTestSub()
   303  	}
   304  	b.StartTimer()
   305  
   306  	for i := 0; i < b.N; i++ {
   307  		for range subs {
   308  			break
   309  		}
   310  	}
   311  }