| // +build ignore |
| |
| /* |
| Copyright 2012 Google Inc. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| 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", err, someErr) |
| } |
| if v != nil { |
| t.Errorf("unexpected non-nil value %#v", v) |
| } |
| } |
| |
| func TestDoDupSuppress(t *testing.T) { |
| var g Group |
| c := make(chan string) |
| var calls int32 |
| fn := func() (interface{}, error) { |
| atomic.AddInt32(&calls, 1) |
| return <-c, nil |
| } |
| |
| const n = 10 |
| var wg sync.WaitGroup |
| for i := 0; i < n; i++ { |
| wg.Add(1) |
| go func() { |
| v, err := g.Do("key", fn) |
| if err != nil { |
| t.Errorf("Do error: %v", err) |
| } |
| if v.(string) != "bar" { |
| t.Errorf("got %q; want %q", v, "bar") |
| } |
| wg.Done() |
| }() |
| } |
| time.Sleep(100 * time.Millisecond) // let goroutines above block |
| c <- "bar" |
| wg.Wait() |
| if got := atomic.LoadInt32(&calls); got != 1 { |
| t.Errorf("number of calls = %d; want 1", got) |
| } |
| } |