Merge "js/core: Fix a race in test_serviced where we weren't locking operations on the cache."
diff --git a/go/src/v.io/x/js.core/test_service/test_serviced/cache_impl.go b/go/src/v.io/x/js.core/test_service/test_serviced/cache_impl.go
index 6b88db8..a716b3b 100644
--- a/go/src/v.io/x/js.core/test_service/test_serviced/cache_impl.go
+++ b/go/src/v.io/x/js.core/test_service/test_serviced/cache_impl.go
@@ -5,6 +5,7 @@
 package main
 
 import (
+	"sync"
 	"fmt"
 	"reflect"
 	"sort"
@@ -23,6 +24,7 @@
 
 // A simple in-memory implementation of a Cache service.
 type cacheImpl struct {
+	mu             sync.Mutex
 	cache          map[string]*vdl.Value
 	mostRecent     test_service.KeyValuePair
 	lastUpdateTime time.Time
@@ -34,16 +36,21 @@
 }
 
 // Set sets a value for a key.  This should never return an error.
-func (c *cacheImpl) Set(_ *context.T, _ rpc.ServerCall, key string, value *vdl.Value) error {
+func (c *cacheImpl) Set(ctx *context.T, _ rpc.ServerCall, key string, value *vdl.Value) error {
+	c.mu.Lock()
+	ctx.VI(0).Info("Set called with %v", key)
 	c.cache[key] = value
 	c.mostRecent = test_service.KeyValuePair{Key: key, Value: value}
 	c.lastUpdateTime = time.Now()
+	c.mu.Unlock()
 	return nil
 }
 
 // Get returns the value for a key.  If the key is not in the map, it returns
 // an error.
 func (c *cacheImpl) Get(ctx *context.T, _ rpc.ServerCall, key string) (*vdl.Value, error) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
 	if value, ok := c.cache[key]; ok {
 		return value, nil
 	}
@@ -132,10 +139,12 @@
 
 // KeyValuePairs returns the full contents of the cache as a slice of pairs.
 func (c *cacheImpl) KeyValuePairs(*context.T, rpc.ServerCall) ([]test_service.KeyValuePair, error) {
+	c.mu.Lock()
 	kvp := make([]test_service.KeyValuePair, 0, len(c.cache))
 	for key, val := range c.cache {
 		kvp = append(kvp, test_service.KeyValuePair{key, val})
 	}
+	c.mu.Unlock()
 	return kvp, nil
 }
 
@@ -144,6 +153,8 @@
 // TODO(bprosnitz) support type types and change time to native time type
 func (c *cacheImpl) MostRecentSet(ctx *context.T, _ rpc.ServerCall) (test_service.KeyValuePair, int64, error) {
 	var err error
+	c.mu.Lock()
+	defer c.mu.Unlock()
 	if c.lastUpdateTime.IsZero() {
 		err = verror.New(verror.ErrNoExist, ctx)
 	}
@@ -155,10 +166,12 @@
 func (c *cacheImpl) KeyPage(ctx *context.T, _ rpc.ServerCall, index int64) (test_service.KeyPageResult, error) {
 	results := test_service.KeyPageResult{}
 
+	c.mu.Lock()
 	keys := sort.StringSlice{}
 	for key, _ := range c.cache {
 		keys = append(keys, key)
 	}
+	c.mu.Unlock()
 	keys.Sort()
 
 	lowIndex := int(index) * 10
@@ -188,7 +201,9 @@
 func (c *cacheImpl) MultiGet(ctx *context.T, call test_service.CacheMultiGetServerCall) error {
 	for call.RecvStream().Advance() {
 		key := call.RecvStream().Value()
+		c.mu.Lock()
 		value, ok := c.cache[key]
+		c.mu.Unlock()
 		if !ok {
 			return verror.New(verror.ErrNoExist, ctx, key)
 		}