| Index: impl/memory/race_test.go
|
| diff --git a/impl/memory/race_test.go b/impl/memory/race_test.go
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a8a7a4531effa2a6c710be66370598840f37ef2e
|
| --- /dev/null
|
| +++ b/impl/memory/race_test.go
|
| @@ -0,0 +1,101 @@
|
| +// Copyright 2015 The Chromium 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 memory
|
| +
|
| +import (
|
| + "sync"
|
| + "sync/atomic"
|
| + "testing"
|
| +
|
| + "github.com/luci/gae/service/datastore"
|
| + "golang.org/x/net/context"
|
| +)
|
| +
|
| +func TestRaceGetPut(t *testing.T) {
|
| + t.Parallel()
|
| +
|
| + value := int32(0)
|
| + num := int32(0)
|
| +
|
| + ds := datastore.Get(Use(context.Background()))
|
| +
|
| + wg := sync.WaitGroup{}
|
| +
|
| + for i := 0; i < 100; i++ {
|
| + wg.Add(1)
|
| + go func() {
|
| + defer wg.Done()
|
| +
|
| + err := ds.RunInTransaction(func(c context.Context) error {
|
| + atomic.AddInt32(&num, 1)
|
| +
|
| + ds := datastore.Get(c)
|
| +
|
| + obj := pmap("$key", ds.MakeKey("Obj", 1))
|
| + if err := ds.Get(obj); err != nil && err != datastore.ErrNoSuchEntity {
|
| + t.Fatal("error get", err)
|
| + }
|
| + cur := int64(0)
|
| + if ps, ok := obj["Value"]; ok {
|
| + cur = ps[0].Value().(int64)
|
| + }
|
| +
|
| + cur++
|
| + obj["Value"] = []datastore.Property{prop(cur)}
|
| +
|
| + return ds.Put(obj)
|
| + }, &datastore.TransactionOptions{Attempts: 200})
|
| +
|
| + if err != nil {
|
| + t.Fatal("error during transaction", err)
|
| + }
|
| +
|
| + atomic.AddInt32(&value, 1)
|
| + }()
|
| + }
|
| + wg.Wait()
|
| +
|
| + obj := pmap("$key", ds.MakeKey("Obj", 1))
|
| + if ds.Get(obj) != nil {
|
| + t.FailNow()
|
| + }
|
| + t.Logf("Ran %d inner functions", num)
|
| + if int64(value) != obj["Value"][0].Value().(int64) {
|
| + t.Fatalf("value wrong value %d v %d", value, obj["Value"][0].Value().(int64))
|
| + }
|
| +}
|
| +
|
| +func TestRaceNonConflictingPuts(t *testing.T) {
|
| + t.Parallel()
|
| +
|
| + ds := datastore.Get(Use(context.Background()))
|
| +
|
| + num := int32(0)
|
| +
|
| + wg := sync.WaitGroup{}
|
| +
|
| + for i := 0; i < 100; i++ {
|
| + wg.Add(1)
|
| + go func() {
|
| + defer wg.Done()
|
| +
|
| + err := ds.RunInTransaction(func(c context.Context) error {
|
| + ds := datastore.Get(c)
|
| + return ds.Put(pmap(
|
| + "$kind", "Thing", Next,
|
| + "Value", 100))
|
| + }, nil)
|
| + if err != nil {
|
| + t.Fatal("error during transaction", err)
|
| + }
|
| + atomic.AddInt32(&num, 1)
|
| + }()
|
| + }
|
| + wg.Wait()
|
| +
|
| + if num != 100 {
|
| + t.Fatal("expected 100 runs, got", num)
|
| + }
|
| +}
|
|
|