| Index: service/datastore/serialize/serialize_test.go | 
| diff --git a/service/datastore/serialize/serialize_test.go b/service/datastore/serialize/serialize_test.go | 
| index 63f44d01b6b3b0b094cae2d2d1dce6ccfee405ae..d7e3f3f42158db126addab19c8107d80fa852395 100644 | 
| --- a/service/datastore/serialize/serialize_test.go | 
| +++ b/service/datastore/serialize/serialize_test.go | 
| @@ -13,7 +13,6 @@ import ( | 
|  | 
| "github.com/luci/gae/service/blobstore" | 
| ds "github.com/luci/gae/service/datastore" | 
| -	"github.com/luci/gae/service/datastore/dskey" | 
| "github.com/luci/luci-go/common/cmpbin" | 
| . "github.com/luci/luci-go/common/testing/assertions" | 
| . "github.com/smartystreets/goconvey/convey" | 
| @@ -33,25 +32,7 @@ type dspmapTC struct { | 
| props ds.PropertyMap | 
| } | 
|  | 
| -// TODO(riannucci): dedup with datastore/key testing file. | 
| -func mkKey(aid, ns string, elems ...interface{}) ds.Key { | 
| -	if len(elems)%2 != 0 { | 
| -		panic("odd number of tokens") | 
| -	} | 
| -	toks := make([]ds.KeyTok, len(elems)/2) | 
| -	for i := 0; i < len(elems); i += 2 { | 
| -		toks[i/2].Kind = elems[i].(string) | 
| -		switch x := elems[i+1].(type) { | 
| -		case string: | 
| -			toks[i/2].StringID = x | 
| -		case int: | 
| -			toks[i/2].IntID = int64(x) | 
| -		default: | 
| -			panic("bad token id") | 
| -		} | 
| -	} | 
| -	return dskey.NewToks(aid, ns, toks) | 
| -} | 
| +var mkKey = ds.MakeKey | 
|  | 
| func mkBuf(data []byte) Buffer { | 
| return Invertible(bytes.NewBuffer(data)) | 
| @@ -62,7 +43,7 @@ func ShouldEqualKey(actual interface{}, expected ...interface{}) string { | 
| if len(expected) != 1 { | 
| return fmt.Sprintf("Assertion requires 1 expected value, got %d", len(expected)) | 
| } | 
| -	if dskey.Equal(actual.(ds.Key), expected[0].(ds.Key)) { | 
| +	if actual.(*ds.Key).Equal(expected[0].(*ds.Key)) { | 
| return "" | 
| } | 
| return fmt.Sprintf("Expected: %q\nActual: %q", actual, expected[0]) | 
| @@ -133,38 +114,68 @@ func TestPropertyMapSerialization(t *testing.T) { | 
| }) | 
| } | 
|  | 
| +func die(err error) { | 
| +	if err != nil { | 
| +		panic(err) | 
| +	} | 
| +} | 
| + | 
| +func wf(w io.Writer, v float64) int { | 
| +	ret, err := cmpbin.WriteFloat64(w, v) | 
| +	die(err) | 
| +	return ret | 
| +} | 
| + | 
| +func ws(w io.ByteWriter, s string) int { | 
| +	ret, err := cmpbin.WriteString(w, s) | 
| +	die(err) | 
| +	return ret | 
| +} | 
| + | 
| +func wi(w io.ByteWriter, i int64) int { | 
| +	ret, err := cmpbin.WriteInt(w, i) | 
| +	die(err) | 
| +	return ret | 
| +} | 
| + | 
| +func wui(w io.ByteWriter, i uint64) int { | 
| +	ret, err := cmpbin.WriteUint(w, i) | 
| +	die(err) | 
| +	return ret | 
| +} | 
| + | 
| func TestSerializationReadMisc(t *testing.T) { | 
| t.Parallel() | 
|  | 
| Convey("Misc Serialization tests", t, func() { | 
| Convey("GeoPoint", func() { | 
| buf := mkBuf(nil) | 
| -			cmpbin.WriteFloat64(buf, 10) | 
| -			cmpbin.WriteFloat64(buf, 20) | 
| +			wf(buf, 10) | 
| +			wf(buf, 20) | 
| So(string(ToBytes(ds.GeoPoint{Lat: 10, Lng: 20})), ShouldEqual, buf.String()) | 
| }) | 
|  | 
| Convey("IndexColumn", func() { | 
| buf := mkBuf(nil) | 
| -			buf.WriteByte(1) | 
| -			cmpbin.WriteString(buf, "hi") | 
| -			So(string(ToBytes(ds.IndexColumn{Property: "hi", Direction: ds.DESCENDING})), | 
| +			die(buf.WriteByte(1)) | 
| +			ws(buf, "hi") | 
| +			So(string(ToBytes(ds.IndexColumn{Property: "hi", Descending: true})), | 
| ShouldEqual, buf.String()) | 
| }) | 
|  | 
| Convey("KeyTok", func() { | 
| buf := mkBuf(nil) | 
| -			cmpbin.WriteString(buf, "foo") | 
| -			buf.WriteByte(byte(ds.PTInt)) | 
| -			cmpbin.WriteInt(buf, 20) | 
| +			ws(buf, "foo") | 
| +			die(buf.WriteByte(byte(ds.PTInt))) | 
| +			wi(buf, 20) | 
| So(string(ToBytes(ds.KeyTok{Kind: "foo", IntID: 20})), | 
| ShouldEqual, buf.String()) | 
| }) | 
|  | 
| Convey("Property", func() { | 
| buf := mkBuf(nil) | 
| -			buf.WriteByte(0x80 | byte(ds.PTString)) | 
| -			cmpbin.WriteString(buf, "nerp") | 
| +			die(buf.WriteByte(0x80 | byte(ds.PTString))) | 
| +			ws(buf, "nerp") | 
| So(string(ToBytes(mp("nerp"))), | 
| ShouldEqual, buf.String()) | 
| }) | 
| @@ -237,85 +248,86 @@ func TestSerializationReadMisc(t *testing.T) { | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("str", func() { | 
| -					buf.WriteString("sup") | 
| -					_, err := ReadKey(buf, WithContext, "", "") | 
| +					_, err := buf.WriteString("sup") | 
| +					die(err) | 
| +					_, err = ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldErrLike, "expected actualCtx") | 
| }) | 
| Convey("truncated 1", func() { | 
| -					buf.WriteByte(1) // actualCtx == 1 | 
| +					die(buf.WriteByte(1)) // actualCtx == 1 | 
| _, err := ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("truncated 2", func() { | 
| -					buf.WriteByte(1) // actualCtx == 1 | 
| -					cmpbin.WriteString(buf, "aid") | 
| +					die(buf.WriteByte(1)) // actualCtx == 1 | 
| +					ws(buf, "aid") | 
| _, err := ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("truncated 3", func() { | 
| -					buf.WriteByte(1) // actualCtx == 1 | 
| -					cmpbin.WriteString(buf, "aid") | 
| -					cmpbin.WriteString(buf, "ns") | 
| +					die(buf.WriteByte(1)) // actualCtx == 1 | 
| +					ws(buf, "aid") | 
| +					ws(buf, "ns") | 
| _, err := ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("huge key", func() { | 
| -					buf.WriteByte(1) // actualCtx == 1 | 
| -					cmpbin.WriteString(buf, "aid") | 
| -					cmpbin.WriteString(buf, "ns") | 
| +					die(buf.WriteByte(1)) // actualCtx == 1 | 
| +					ws(buf, "aid") | 
| +					ws(buf, "ns") | 
| for i := 1; i < 60; i++ { | 
| -						buf.WriteByte(1) | 
| -						WriteKeyTok(buf, ds.KeyTok{Kind: "sup", IntID: int64(i)}) | 
| +						die(buf.WriteByte(1)) | 
| +						die(WriteKeyTok(buf, ds.KeyTok{Kind: "sup", IntID: int64(i)})) | 
| } | 
| -					buf.WriteByte(0) | 
| +					die(buf.WriteByte(0)) | 
| _, err := ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldErrLike, "huge key") | 
| }) | 
| Convey("insufficient tokens", func() { | 
| -					buf.WriteByte(1) // actualCtx == 1 | 
| -					cmpbin.WriteString(buf, "aid") | 
| -					cmpbin.WriteString(buf, "ns") | 
| -					cmpbin.WriteUint(buf, 2) | 
| +					die(buf.WriteByte(1)) // actualCtx == 1 | 
| +					ws(buf, "aid") | 
| +					ws(buf, "ns") | 
| +					wui(buf, 2) | 
| _, err := ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("partial token 1", func() { | 
| -					buf.WriteByte(1) // actualCtx == 1 | 
| -					cmpbin.WriteString(buf, "aid") | 
| -					cmpbin.WriteString(buf, "ns") | 
| -					buf.WriteByte(1) | 
| -					cmpbin.WriteString(buf, "hi") | 
| +					die(buf.WriteByte(1)) // actualCtx == 1 | 
| +					ws(buf, "aid") | 
| +					ws(buf, "ns") | 
| +					die(buf.WriteByte(1)) | 
| +					ws(buf, "hi") | 
| _, err := ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("partial token 2", func() { | 
| -					buf.WriteByte(1) // actualCtx == 1 | 
| -					cmpbin.WriteString(buf, "aid") | 
| -					cmpbin.WriteString(buf, "ns") | 
| -					buf.WriteByte(1) | 
| -					cmpbin.WriteString(buf, "hi") | 
| -					buf.WriteByte(byte(ds.PTString)) | 
| +					die(buf.WriteByte(1)) // actualCtx == 1 | 
| +					ws(buf, "aid") | 
| +					ws(buf, "ns") | 
| +					die(buf.WriteByte(1)) | 
| +					ws(buf, "hi") | 
| +					die(buf.WriteByte(byte(ds.PTString))) | 
| _, err := ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("bad token (invalid type)", func() { | 
| -					buf.WriteByte(1) // actualCtx == 1 | 
| -					cmpbin.WriteString(buf, "aid") | 
| -					cmpbin.WriteString(buf, "ns") | 
| -					buf.WriteByte(1) | 
| -					cmpbin.WriteString(buf, "hi") | 
| -					buf.WriteByte(byte(ds.PTBlobKey)) | 
| +					die(buf.WriteByte(1)) // actualCtx == 1 | 
| +					ws(buf, "aid") | 
| +					ws(buf, "ns") | 
| +					die(buf.WriteByte(1)) | 
| +					ws(buf, "hi") | 
| +					die(buf.WriteByte(byte(ds.PTBlobKey))) | 
| _, err := ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldErrLike, "invalid type PTBlobKey") | 
| }) | 
| Convey("bad token (invalid IntID)", func() { | 
| -					buf.WriteByte(1) // actualCtx == 1 | 
| -					cmpbin.WriteString(buf, "aid") | 
| -					cmpbin.WriteString(buf, "ns") | 
| -					buf.WriteByte(1) | 
| -					cmpbin.WriteString(buf, "hi") | 
| -					buf.WriteByte(byte(ds.PTInt)) | 
| -					cmpbin.WriteInt(buf, -2) | 
| +					die(buf.WriteByte(1)) // actualCtx == 1 | 
| +					ws(buf, "aid") | 
| +					ws(buf, "ns") | 
| +					die(buf.WriteByte(1)) | 
| +					ws(buf, "hi") | 
| +					die(buf.WriteByte(byte(ds.PTInt))) | 
| +					wi(buf, -2) | 
| _, err := ReadKey(buf, WithContext, "", "") | 
| So(err, ShouldErrLike, "zero/negative") | 
| }) | 
| @@ -329,13 +341,13 @@ func TestSerializationReadMisc(t *testing.T) { | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("trunc 2", func() { | 
| -				cmpbin.WriteFloat64(buf, 100) | 
| +				wf(buf, 100) | 
| _, err := ReadGeoPoint(buf) | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("invalid", func() { | 
| -				cmpbin.WriteFloat64(buf, 100) | 
| -				cmpbin.WriteFloat64(buf, 1000) | 
| +				wf(buf, 100) | 
| +				wf(buf, 1000) | 
| _, err := ReadGeoPoint(buf) | 
| So(err, ShouldErrLike, "invalid GeoPoint") | 
| }) | 
| @@ -346,7 +358,7 @@ func TestSerializationReadMisc(t *testing.T) { | 
| pst, err := time.LoadLocation("America/Los_Angeles") | 
| So(err, ShouldBeNil) | 
| So(func() { | 
| -					WriteTime(mkBuf(nil), time.Now().In(pst)) | 
| +					die(WriteTime(mkBuf(nil), time.Now().In(pst))) | 
| }, ShouldPanic) | 
| }) | 
| }) | 
| @@ -367,17 +379,17 @@ func TestSerializationReadMisc(t *testing.T) { | 
| So(p.Value(), ShouldBeNil) | 
| }) | 
| Convey("trunc (PTBytes)", func() { | 
| -				buf.WriteByte(byte(ds.PTBytes)) | 
| +				die(buf.WriteByte(byte(ds.PTBytes))) | 
| _, err := ReadProperty(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("trunc (PTBlobKey)", func() { | 
| -				buf.WriteByte(byte(ds.PTBlobKey)) | 
| +				die(buf.WriteByte(byte(ds.PTBlobKey))) | 
| _, err := ReadProperty(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("invalid type", func() { | 
| -				buf.WriteByte(byte(ds.PTUnknown + 1)) | 
| +				die(buf.WriteByte(byte(ds.PTUnknown + 1))) | 
| _, err := ReadProperty(buf, WithContext, "", "") | 
| So(err, ShouldErrLike, "unknown type!") | 
| }) | 
| @@ -390,32 +402,32 @@ func TestSerializationReadMisc(t *testing.T) { | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("too many rows", func() { | 
| -				cmpbin.WriteUint(buf, 1000000) | 
| +				wui(buf, 1000000) | 
| _, err := ReadPropertyMap(buf, WithContext, "", "") | 
| So(err, ShouldErrLike, "huge number of rows") | 
| }) | 
| Convey("trunc 2", func() { | 
| -				cmpbin.WriteUint(buf, 10) | 
| +				wui(buf, 10) | 
| _, err := ReadPropertyMap(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("trunc 3", func() { | 
| -				cmpbin.WriteUint(buf, 10) | 
| -				cmpbin.WriteString(buf, "ohai") | 
| +				wui(buf, 10) | 
| +				ws(buf, "ohai") | 
| _, err := ReadPropertyMap(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| Convey("too many values", func() { | 
| -				cmpbin.WriteUint(buf, 10) | 
| -				cmpbin.WriteString(buf, "ohai") | 
| -				cmpbin.WriteUint(buf, 100000) | 
| +				wui(buf, 10) | 
| +				ws(buf, "ohai") | 
| +				wui(buf, 100000) | 
| _, err := ReadPropertyMap(buf, WithContext, "", "") | 
| So(err, ShouldErrLike, "huge number of properties") | 
| }) | 
| Convey("trunc 4", func() { | 
| -				cmpbin.WriteUint(buf, 10) | 
| -				cmpbin.WriteString(buf, "ohai") | 
| -				cmpbin.WriteUint(buf, 10) | 
| +				wui(buf, 10) | 
| +				ws(buf, "ohai") | 
| +				wui(buf, 10) | 
| _, err := ReadPropertyMap(buf, WithContext, "", "") | 
| So(err, ShouldEqual, io.EOF) | 
| }) | 
| @@ -434,7 +446,7 @@ func TestSerializationReadMisc(t *testing.T) { | 
| So(err, ShouldBeNil) | 
| So(newID.Flip(), ShouldResemble, id.Normalize()) | 
|  | 
| -			id.SortBy = append(id.SortBy, ds.IndexColumn{Property: "other", Direction: ds.DESCENDING}) | 
| +			id.SortBy = append(id.SortBy, ds.IndexColumn{Property: "other", Descending: true}) | 
| id.Ancestor = true | 
| data = ToBytes(*id.PrepForIdxTable()) | 
| newID, err = ReadIndexDefinition(mkBuf(data)) | 
| @@ -442,7 +454,7 @@ func TestSerializationReadMisc(t *testing.T) { | 
| So(newID.Flip(), ShouldResemble, id.Normalize()) | 
|  | 
| // invalid | 
| -			id.SortBy = append(id.SortBy, ds.IndexColumn{Property: "", Direction: ds.DESCENDING}) | 
| +			id.SortBy = append(id.SortBy, ds.IndexColumn{Property: "", Descending: true}) | 
| data = ToBytes(*id.PrepForIdxTable()) | 
| newID, err = ReadIndexDefinition(mkBuf(data)) | 
| So(err, ShouldBeNil) | 
| @@ -451,7 +463,7 @@ func TestSerializationReadMisc(t *testing.T) { | 
| Convey("too many", func() { | 
| id := ds.IndexDefinition{Kind: "wat"} | 
| for i := 0; i < MaxIndexColumns+1; i++ { | 
| -					id.SortBy = append(id.SortBy, ds.IndexColumn{Property: "Hi", Direction: ds.ASCENDING}) | 
| +					id.SortBy = append(id.SortBy, ds.IndexColumn{Property: "Hi", Descending: true}) | 
| } | 
| data := ToBytes(*id.PrepForIdxTable()) | 
| newID, err = ReadIndexDefinition(mkBuf(data)) | 
|  |