...

Source file src/golang.org/x/sync/syncmap/map_test.go

Documentation: golang.org/x/sync/syncmap

     1  // Copyright 2016 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 syncmap_test
     6  
     7  import (
     8  	"math/rand"
     9  	"reflect"
    10  	"runtime"
    11  	"sync"
    12  	"testing"
    13  	"testing/quick"
    14  
    15  	"golang.org/x/sync/syncmap"
    16  )
    17  
    18  type mapOp string
    19  
    20  const (
    21  	opLoad        = mapOp("Load")
    22  	opStore       = mapOp("Store")
    23  	opLoadOrStore = mapOp("LoadOrStore")
    24  	opDelete      = mapOp("Delete")
    25  )
    26  
    27  var mapOps = [...]mapOp{opLoad, opStore, opLoadOrStore, opDelete}
    28  
    29  // mapCall is a quick.Generator for calls on mapInterface.
    30  type mapCall struct {
    31  	op   mapOp
    32  	k, v interface{}
    33  }
    34  
    35  func (c mapCall) apply(m mapInterface) (interface{}, bool) {
    36  	switch c.op {
    37  	case opLoad:
    38  		return m.Load(c.k)
    39  	case opStore:
    40  		m.Store(c.k, c.v)
    41  		return nil, false
    42  	case opLoadOrStore:
    43  		return m.LoadOrStore(c.k, c.v)
    44  	case opDelete:
    45  		m.Delete(c.k)
    46  		return nil, false
    47  	default:
    48  		panic("invalid mapOp")
    49  	}
    50  }
    51  
    52  type mapResult struct {
    53  	value interface{}
    54  	ok    bool
    55  }
    56  
    57  func randValue(r *rand.Rand) interface{} {
    58  	b := make([]byte, r.Intn(4))
    59  	for i := range b {
    60  		b[i] = 'a' + byte(rand.Intn(26))
    61  	}
    62  	return string(b)
    63  }
    64  
    65  func (mapCall) Generate(r *rand.Rand, size int) reflect.Value {
    66  	c := mapCall{op: mapOps[rand.Intn(len(mapOps))], k: randValue(r)}
    67  	switch c.op {
    68  	case opStore, opLoadOrStore:
    69  		c.v = randValue(r)
    70  	}
    71  	return reflect.ValueOf(c)
    72  }
    73  
    74  func applyCalls(m mapInterface, calls []mapCall) (results []mapResult, final map[interface{}]interface{}) {
    75  	for _, c := range calls {
    76  		v, ok := c.apply(m)
    77  		results = append(results, mapResult{v, ok})
    78  	}
    79  
    80  	final = make(map[interface{}]interface{})
    81  	m.Range(func(k, v interface{}) bool {
    82  		final[k] = v
    83  		return true
    84  	})
    85  
    86  	return results, final
    87  }
    88  
    89  func applyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
    90  	return applyCalls(new(syncmap.Map), calls)
    91  }
    92  
    93  func applyRWMutexMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
    94  	return applyCalls(new(RWMutexMap), calls)
    95  }
    96  
    97  func applyDeepCopyMap(calls []mapCall) ([]mapResult, map[interface{}]interface{}) {
    98  	return applyCalls(new(DeepCopyMap), calls)
    99  }
   100  
   101  func TestMapMatchesRWMutex(t *testing.T) {
   102  	if err := quick.CheckEqual(applyMap, applyRWMutexMap, nil); err != nil {
   103  		t.Error(err)
   104  	}
   105  }
   106  
   107  func TestMapMatchesDeepCopy(t *testing.T) {
   108  	if err := quick.CheckEqual(applyMap, applyDeepCopyMap, nil); err != nil {
   109  		t.Error(err)
   110  	}
   111  }
   112  
   113  func TestConcurrentRange(t *testing.T) {
   114  	const mapSize = 1 << 10
   115  
   116  	m := new(syncmap.Map)
   117  	for n := int64(1); n <= mapSize; n++ {
   118  		m.Store(n, n)
   119  	}
   120  
   121  	done := make(chan struct{})
   122  	var wg sync.WaitGroup
   123  	defer func() {
   124  		close(done)
   125  		wg.Wait()
   126  	}()
   127  	for g := int64(runtime.GOMAXPROCS(0)); g > 0; g-- {
   128  		r := rand.New(rand.NewSource(g))
   129  		wg.Add(1)
   130  		go func(g int64) {
   131  			defer wg.Done()
   132  			for i := int64(0); ; i++ {
   133  				select {
   134  				case <-done:
   135  					return
   136  				default:
   137  				}
   138  				for n := int64(1); n < mapSize; n++ {
   139  					if r.Int63n(mapSize) == 0 {
   140  						m.Store(n, n*i*g)
   141  					} else {
   142  						m.Load(n)
   143  					}
   144  				}
   145  			}
   146  		}(g)
   147  	}
   148  
   149  	iters := 1 << 10
   150  	if testing.Short() {
   151  		iters = 16
   152  	}
   153  	for n := iters; n > 0; n-- {
   154  		seen := make(map[int64]bool, mapSize)
   155  
   156  		m.Range(func(ki, vi interface{}) bool {
   157  			k, v := ki.(int64), vi.(int64)
   158  			if v%k != 0 {
   159  				t.Fatalf("while Storing multiples of %v, Range saw value %v", k, v)
   160  			}
   161  			if seen[k] {
   162  				t.Fatalf("Range visited key %v twice", k)
   163  			}
   164  			seen[k] = true
   165  			return true
   166  		})
   167  
   168  		if len(seen) != mapSize {
   169  			t.Fatalf("Range visited %v elements of %v-element Map", len(seen), mapSize)
   170  		}
   171  	}
   172  }
   173  

View as plain text