...
Run Format

Source file src/internal/singleflight/singleflight_test.go

Documentation: internal/singleflight

  // Copyright 2013 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package singleflight
  
  import (
  	"errors"
  	"fmt"
  	"sync"
  	"sync/atomic"
  	"testing"
  	"time"
  )
  
  func TestDo(t *testing.T) {
  	var g Group
  	v, err, _ := g.Do("key", func() (interface{}, error) {
  		return "bar", nil
  	})
  	if got, want := fmt.Sprintf("%v (%T)", v, v), "bar (string)"; got != want {
  		t.Errorf("Do = %v; want %v", got, want)
  	}
  	if err != nil {
  		t.Errorf("Do error = %v", err)
  	}
  }
  
  func TestDoErr(t *testing.T) {
  	var g Group
  	someErr := errors.New("Some error")
  	v, err, _ := g.Do("key", func() (interface{}, error) {
  		return nil, someErr
  	})
  	if err != someErr {
  		t.Errorf("Do error = %v; want someErr %v", err, someErr)
  	}
  	if v != nil {
  		t.Errorf("unexpected non-nil value %#v", v)
  	}
  }
  
  func TestDoDupSuppress(t *testing.T) {
  	var g Group
  	var wg1, wg2 sync.WaitGroup
  	c := make(chan string, 1)
  	var calls int32
  	fn := func() (interface{}, error) {
  		if atomic.AddInt32(&calls, 1) == 1 {
  			// First invocation.
  			wg1.Done()
  		}
  		v := <-c
  		c <- v // pump; make available for any future calls
  
  		time.Sleep(10 * time.Millisecond) // let more goroutines enter Do
  
  		return v, nil
  	}
  
  	const n = 10
  	wg1.Add(1)
  	for i := 0; i < n; i++ {
  		wg1.Add(1)
  		wg2.Add(1)
  		go func() {
  			defer wg2.Done()
  			wg1.Done()
  			v, err, _ := g.Do("key", fn)
  			if err != nil {
  				t.Errorf("Do error: %v", err)
  				return
  			}
  			if s, _ := v.(string); s != "bar" {
  				t.Errorf("Do = %T %v; want %q", v, v, "bar")
  			}
  		}()
  	}
  	wg1.Wait()
  	// At least one goroutine is in fn now and all of them have at
  	// least reached the line before the Do.
  	c <- "bar"
  	wg2.Wait()
  	if got := atomic.LoadInt32(&calls); got <= 0 || got >= n {
  		t.Errorf("number of calls = %d; want over 0 and less than %d", got, n)
  	}
  }
  

View as plain text