func TestTupleSpaceProcessNewEntriesAlwaysRespondsToReaders(t *testing.T) {
	rts := tuplespace.NewRawTupleSpace(store.NewMemoryStore())
	take := rts.ReadOperation(tuplespace.MustMatch("cmd"), 0, tuplespace.ActionOne|tuplespace.ActionTake)
	read := rts.ReadOperation(tuplespace.MustMatch("cmd"), 0, tuplespace.ActionOne)
	go func() {
		time.Sleep(time.Second * 1)
		take.Cancel()
		read.Cancel()
	}()
	tuples := []tuplespace.Tuple{tuplespace.Tuple{"cmd": "uname -a"}}
	expected := []tuplespace.Tuple{tuplespace.Tuple{"cmd": "uname -a"}}
	assert.NoError(t, rts.ProcessNewEntries(tuples, time.Now()))
	assert.Equal(t, <-take.Get(), expected)
	assert.Equal(t, <-read.Get(), expected)
}
func TestTupleSpaceTake(t *testing.T) {
	ts := tuplespace.NewTupleSpace(store.NewMemoryStore())
	defer ts.Shutdown()
	ts.Send(tuplespace.Tuple{"cmd": "uname -a"}, 0)
	ts.Send(tuplespace.Tuple{"cmd": "uptime"}, 0)
	_, err := ts.Take(tuplespace.MustMatch(`cmd != nil`), time.Second)
	assert.NoError(t, err)
	assert.Equal(t, ts.Stats().Tuples, 1)
}
func benchmarkTupleSpaceReadAll1000(b *testing.B, builder TupleStoreBuilder) {
	ts := tuplespace.NewTupleSpace(NewTemporaryDiskStore(builder))
	defer ts.Shutdown()
	sendN(ts, 1000, 0)
	b.ResetTimer()
	match := tuplespace.MustMatch(`cmd != nil`)
	for i := 0; i < b.N; i++ {
		ts.ReadAll(match, 0)
	}
}
func benchmarkTupleSpaceTake(b *testing.B, builder TupleStoreBuilder) {
	ts := tuplespace.NewTupleSpace(NewTemporaryDiskStore(builder))
	defer ts.Shutdown()
	sendN(ts, b.N, 0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		match := tuplespace.MustMatch(`cmd == %d`, i)
		ts.Take(match, 0)
	}
}
func TestTupleSpaceReadAll(t *testing.T) {
	ts := tuplespace.NewTupleSpace(store.NewMemoryStore())
	defer ts.Shutdown()
	ts.Send(tuplespace.Tuple{"cmd": "uname -a"}, 0)
	ts.Send(tuplespace.Tuple{"cmd": "uptime"}, 0)
	time.Sleep(time.Millisecond * 100)
	tuples, err := ts.ReadAll(tuplespace.MustMatch(`cmd != nil`), time.Second)
	assert.NoError(t, err)
	assert.Equal(t, tuples, []tuplespace.Tuple{tuplespace.Tuple{"cmd": "uname -a"}, tuplespace.Tuple{"cmd": "uptime"}})
	assert.Equal(t, ts.Stats().Tuples, 2)
}
func benchmarkTupleSpaceRead(b *testing.B, builder TupleStoreBuilder) {
	ts := tuplespace.NewTupleSpace(NewTemporaryDiskStore(builder))
	defer ts.Shutdown()
	sendN(ts, b.N, 0)
	sendN(ts, b.N, 0)
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		match := tuplespace.MustMatch(`cmd == %d`, int64(i))
		_, err := ts.Read(match, 0)
		if err != nil {
			panic(err.Error())
		}
	}
}
func benchmarkTupleSpaceStressTestConcurrency32(b *testing.B, builder TupleStoreBuilder) {
	ts := tuplespace.NewTupleSpace(NewTemporaryDiskStore(builder))
	defer ts.Shutdown()

	threads := 32
	messages := b.N

	var sent int32
	var read int32

	readWait := sync.WaitGroup{}
	for i := 0; i < threads; i++ {
		readWait.Add(1)
		go func(i int) {
			for n := 0; n < messages; n++ {
				match := tuplespace.MustMatch(`"a" == "reader" && "b" == %d && "c" == %d`, i, n)
				_, err := ts.Take(match, time.Minute)
				if err != nil {
					fmt.Errorf("failed to take: %s", err)
				} else {
					atomic.AddInt32(&read, 1)
				}
			}
			readWait.Done()
		}(i)
	}

	writeWait := sync.WaitGroup{}
	for i := 0; i < threads; i++ {
		writeWait.Add(1)
		go func(i int) {
			for n := 0; n < messages; n++ {
				tuple := tuplespace.Tuple{"a": "reader", "b": int64(i), "c": int64(n)}
				err := ts.Send(tuple, 0)
				if err != nil {
					fmt.Errorf("failed to take: %s", err)
				} else {
					atomic.AddInt32(&sent, 1)
				}
			}
			writeWait.Done()
		}(i)
	}

	writeWait.Wait()
	if int(sent) != threads*messages {
		panic("consistency check failed")
	}

	readWait.Wait()
	if sent != read {
		panic("consistency check failed")
	}

	// assert.Equal(t, ts.Stats(), tuplespace.TupleSpaceStats{
	// 	TuplesSeen:  int64(threads * messages),
	// 	WaitersSeen: int64(threads * messages),
	// 	TuplesTaken: int64(threads * messages),
	// 	TuplesRead:  0,
	// })
}