Source file src/crypto/tls/cache_test.go

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package tls
     6  
     7  import (
     8  	"encoding/pem"
     9  	"fmt"
    10  	"runtime"
    11  	"testing"
    12  	"time"
    13  )
    14  
    15  func TestCertCache(t *testing.T) {
    16  	cc := certCache{}
    17  	p, _ := pem.Decode([]byte(rsaCertPEM))
    18  	if p == nil {
    19  		t.Fatal("Failed to decode certificate")
    20  	}
    21  
    22  	certA, err := cc.newCert(p.Bytes)
    23  	if err != nil {
    24  		t.Fatalf("newCert failed: %s", err)
    25  	}
    26  	certB, err := cc.newCert(p.Bytes)
    27  	if err != nil {
    28  		t.Fatalf("newCert failed: %s", err)
    29  	}
    30  	if certA.cert != certB.cert {
    31  		t.Fatal("newCert returned a unique reference for a duplicate certificate")
    32  	}
    33  
    34  	if entry, ok := cc.Load(string(p.Bytes)); !ok {
    35  		t.Fatal("cache does not contain expected entry")
    36  	} else {
    37  		if refs := entry.(*cacheEntry).refs.Load(); refs != 2 {
    38  			t.Fatalf("unexpected number of references: got %d, want 2", refs)
    39  		}
    40  	}
    41  
    42  	timeoutRefCheck := func(t *testing.T, key string, count int64) {
    43  		t.Helper()
    44  		timeout := time.After(4 * time.Second)
    45  		for {
    46  			select {
    47  			case <-timeout:
    48  				t.Fatal("timed out waiting for expected ref count")
    49  			default:
    50  				e, ok := cc.Load(key)
    51  				if !ok && count != 0 {
    52  					t.Fatal("cache does not contain expected key")
    53  				} else if count == 0 && !ok {
    54  					return
    55  				}
    56  
    57  				if e.(*cacheEntry).refs.Load() == count {
    58  					return
    59  				}
    60  			}
    61  			// Explicitly yield to the scheduler.
    62  			//
    63  			// On single-threaded platforms like js/wasm a busy-loop might
    64  			// never call into the scheduler for the full timeout, meaning
    65  			// that if we arrive here and the cleanup hasn't already run,
    66  			// we'll simply loop until the timeout. Busy-loops put us at the
    67  			// mercy of the Go scheduler, making this test fragile on some
    68  			// platforms.
    69  			runtime.Gosched()
    70  		}
    71  	}
    72  
    73  	// Keep certA alive until at least now, so that we can
    74  	// purposefully nil it and force the finalizer to be
    75  	// called.
    76  	runtime.KeepAlive(certA)
    77  	certA = nil
    78  	runtime.GC()
    79  
    80  	timeoutRefCheck(t, string(p.Bytes), 1)
    81  
    82  	// Keep certB alive until at least now, so that we can
    83  	// purposefully nil it and force the finalizer to be
    84  	// called.
    85  	runtime.KeepAlive(certB)
    86  	certB = nil
    87  	runtime.GC()
    88  
    89  	timeoutRefCheck(t, string(p.Bytes), 0)
    90  }
    91  
    92  func BenchmarkCertCache(b *testing.B) {
    93  	p, _ := pem.Decode([]byte(rsaCertPEM))
    94  	if p == nil {
    95  		b.Fatal("Failed to decode certificate")
    96  	}
    97  
    98  	cc := certCache{}
    99  	b.ReportAllocs()
   100  	b.ResetTimer()
   101  	// We expect that calling newCert additional times after
   102  	// the initial call should not cause additional allocations.
   103  	for extra := 0; extra < 4; extra++ {
   104  		b.Run(fmt.Sprint(extra), func(b *testing.B) {
   105  			actives := make([]*activeCert, extra+1)
   106  			b.ResetTimer()
   107  			for i := 0; i < b.N; i++ {
   108  				var err error
   109  				actives[0], err = cc.newCert(p.Bytes)
   110  				if err != nil {
   111  					b.Fatal(err)
   112  				}
   113  				for j := 0; j < extra; j++ {
   114  					actives[j+1], err = cc.newCert(p.Bytes)
   115  					if err != nil {
   116  						b.Fatal(err)
   117  					}
   118  				}
   119  				for j := 0; j < extra+1; j++ {
   120  					actives[j] = nil
   121  				}
   122  				runtime.GC()
   123  			}
   124  		})
   125  	}
   126  }
   127  

View as plain text