go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/service/datastore/serialize_test.go (about)

     1  // Copyright 2015 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package datastore
    16  
    17  import (
    18  	"bytes"
    19  	"io"
    20  	"testing"
    21  	"time"
    22  
    23  	"go.chromium.org/luci/common/data/cmpbin"
    24  
    25  	"go.chromium.org/luci/gae/service/blobstore"
    26  
    27  	. "github.com/smartystreets/goconvey/convey"
    28  	. "go.chromium.org/luci/common/testing/assertions"
    29  )
    30  
    31  func init() {
    32  	WritePropertyMapDeterministic = true
    33  }
    34  
    35  type dspmapTC struct {
    36  	name  string
    37  	props PropertyMap
    38  }
    39  
    40  func mkKeyCtx(appID, namespace string, elems ...any) *Key {
    41  	return MkKeyContext(appID, namespace).MakeKey(elems...)
    42  }
    43  
    44  func mkBuf(data []byte) cmpbin.WriteableBytesBuffer {
    45  	return cmpbin.Invertible(bytes.NewBuffer(data))
    46  }
    47  
    48  func TestPropertyMapSerialization(t *testing.T) {
    49  	t.Parallel()
    50  
    51  	now := time.Now().UTC()
    52  	tests := []dspmapTC{
    53  		{
    54  			"basic",
    55  			PropertyMap{
    56  				"R": PropertySlice{mp(false), mp(2.1), mpNI(3)},
    57  				"S": PropertySlice{mp("hello"), mp("world")},
    58  			},
    59  		},
    60  		{
    61  			"keys",
    62  			PropertyMap{
    63  				"DS": PropertySlice{
    64  					mp(mkKeyCtx("appy", "ns", "Foo", 7)),
    65  					mp(mkKeyCtx("other", "", "Yot", "wheeep")),
    66  					mp((*Key)(nil)),
    67  				},
    68  				"blobstore": PropertySlice{mp(blobstore.Key("sup")), mp(blobstore.Key("nerds"))},
    69  			},
    70  		},
    71  		{
    72  			"property map",
    73  			PropertyMap{
    74  				"pm": PropertySlice{
    75  					mp(PropertyMap{
    76  						"$key":    mpNI(mkKeyCtx("app", "ns", "entity", "id")),
    77  						"$kind":   mpNI("entity"),
    78  						"$id":     mpNI("id"),
    79  						"$parent": mpNI(nil),
    80  						"indexed": mp("indexed"),
    81  						"map": mpNI(PropertyMap{
    82  							"b": mpNI([]byte("byte")),
    83  						}),
    84  						"str": mpNI("string")},
    85  					),
    86  				},
    87  			},
    88  		},
    89  		{
    90  			"geo",
    91  			PropertyMap{
    92  				"G": mp(GeoPoint{Lat: 1, Lng: 2}),
    93  			},
    94  		},
    95  		{
    96  			"data",
    97  			PropertyMap{
    98  				"S":                    PropertySlice{mp("sup"), mp("fool"), mp("nerd")},
    99  				"Deserialize.Foo.Nerd": PropertySlice{mp([]byte("sup")), mp([]byte("fool"))},
   100  			},
   101  		},
   102  		{
   103  			"time",
   104  			PropertyMap{
   105  				"T": PropertySlice{
   106  					mp(now),
   107  					mp(now.Add(time.Second)),
   108  				},
   109  			},
   110  		},
   111  		{
   112  			"empty vals",
   113  			PropertyMap{
   114  				"T": PropertySlice{mp(true), mp(true)},
   115  				"F": PropertySlice{mp(false), mp(false)},
   116  				"N": PropertySlice{mp(nil), mp(nil)},
   117  				"E": PropertySlice{},
   118  			},
   119  		},
   120  	}
   121  
   122  	Convey("PropertyMap serialization", t, func() {
   123  		Convey("round trip", func() {
   124  			for _, tc := range tests {
   125  				tc := tc
   126  				Convey(tc.name, func() {
   127  					data := SerializeKC.ToBytes(tc.props)
   128  					dec, err := Deserialize.PropertyMap(mkBuf(data))
   129  					So(err, ShouldBeNil)
   130  					So(dec, ShouldResemble, tc.props)
   131  				})
   132  			}
   133  		})
   134  	})
   135  }
   136  
   137  func die(err error) {
   138  	if err != nil {
   139  		panic(err)
   140  	}
   141  }
   142  
   143  func wf(w io.Writer, v float64) int {
   144  	ret, err := cmpbin.WriteFloat64(w, v)
   145  	die(err)
   146  	return ret
   147  }
   148  
   149  func ws(w io.ByteWriter, s string) int {
   150  	ret, err := cmpbin.WriteString(w, s)
   151  	die(err)
   152  	return ret
   153  }
   154  
   155  func wi(w io.ByteWriter, i int64) int {
   156  	ret, err := cmpbin.WriteInt(w, i)
   157  	die(err)
   158  	return ret
   159  }
   160  
   161  func wui(w io.ByteWriter, i uint64) int {
   162  	ret, err := cmpbin.WriteUint(w, i)
   163  	die(err)
   164  	return ret
   165  }
   166  
   167  func TestSerializationReadMisc(t *testing.T) {
   168  	t.Parallel()
   169  
   170  	Convey("Misc Serialization tests", t, func() {
   171  		Convey("GeoPoint", func() {
   172  			buf := mkBuf(nil)
   173  			wf(buf, 10)
   174  			wf(buf, 20)
   175  			So(string(Serialize.ToBytes(GeoPoint{Lat: 10, Lng: 20})), ShouldEqual, buf.String())
   176  		})
   177  
   178  		Convey("IndexColumn", func() {
   179  			buf := mkBuf(nil)
   180  			die(buf.WriteByte(1))
   181  			ws(buf, "hi")
   182  			So(string(Serialize.ToBytes(IndexColumn{Property: "hi", Descending: true})),
   183  				ShouldEqual, buf.String())
   184  		})
   185  
   186  		Convey("KeyTok", func() {
   187  			buf := mkBuf(nil)
   188  			ws(buf, "foo")
   189  			die(buf.WriteByte(byte(PTInt)))
   190  			wi(buf, 20)
   191  			So(string(Serialize.ToBytes(KeyTok{Kind: "foo", IntID: 20})),
   192  				ShouldEqual, buf.String())
   193  		})
   194  
   195  		Convey("Property", func() {
   196  			buf := mkBuf(nil)
   197  			die(buf.WriteByte(0x80 | byte(PTString)))
   198  			ws(buf, "nerp")
   199  			So(string(Serialize.ToBytes(mp("nerp"))),
   200  				ShouldEqual, buf.String())
   201  		})
   202  
   203  		Convey("Time", func() {
   204  			tp := mp(time.Now().UTC())
   205  			So(string(Serialize.ToBytes(tp.Value())), ShouldEqual, string(Serialize.ToBytes(tp)[1:]))
   206  		})
   207  
   208  		Convey("Zero time", func() {
   209  			buf := mkBuf(nil)
   210  			So(Serialize.Time(buf, time.Time{}), ShouldBeNil)
   211  			t, err := Deserialize.Time(mkBuf(buf.Bytes()))
   212  			So(err, ShouldBeNil)
   213  			So(t.Equal(time.Time{}), ShouldBeTrue)
   214  		})
   215  
   216  		Convey("ReadKey", func() {
   217  			Convey("good cases", func() {
   218  				dwc := Deserializer{MkKeyContext("spam", "nerd")}
   219  
   220  				Convey("w/ ctx decodes normally w/ ctx", func() {
   221  					k := mkKeyCtx("aid", "ns", "knd", "yo", "other", 10)
   222  					data := SerializeKC.ToBytes(k)
   223  					dk, err := Deserialize.Key(mkBuf(data))
   224  					So(err, ShouldBeNil)
   225  					So(dk, ShouldEqualKey, k)
   226  				})
   227  				Convey("w/ ctx decodes normally w/o ctx", func() {
   228  					k := mkKeyCtx("aid", "ns", "knd", "yo", "other", 10)
   229  					data := SerializeKC.ToBytes(k)
   230  					dk, err := dwc.Key(mkBuf(data))
   231  					So(err, ShouldBeNil)
   232  					So(dk, ShouldEqualKey, mkKeyCtx("spam", "nerd", "knd", "yo", "other", 10))
   233  				})
   234  				Convey("w/o ctx decodes normally w/ ctx", func() {
   235  					k := mkKeyCtx("aid", "ns", "knd", "yo", "other", 10)
   236  					data := Serialize.ToBytes(k)
   237  					dk, err := Deserialize.Key(mkBuf(data))
   238  					So(err, ShouldBeNil)
   239  					So(dk, ShouldEqualKey, mkKeyCtx("", "", "knd", "yo", "other", 10))
   240  				})
   241  				Convey("w/o ctx decodes normally w/o ctx", func() {
   242  					k := mkKeyCtx("aid", "ns", "knd", "yo", "other", 10)
   243  					data := Serialize.ToBytes(k)
   244  					dk, err := dwc.Key(mkBuf(data))
   245  					So(err, ShouldBeNil)
   246  					So(dk, ShouldEqualKey, mkKeyCtx("spam", "nerd", "knd", "yo", "other", 10))
   247  				})
   248  				Convey("IntIDs always sort before StringIDs", func() {
   249  					// -1 writes as almost all 1's in the first byte under cmpbin, even
   250  					// though it's technically not a valid key.
   251  					k := mkKeyCtx("aid", "ns", "knd", -1)
   252  					data := Serialize.ToBytes(k)
   253  
   254  					k = mkKeyCtx("aid", "ns", "knd", "hat")
   255  					data2 := Serialize.ToBytes(k)
   256  
   257  					So(string(data), ShouldBeLessThan, string(data2))
   258  				})
   259  			})
   260  
   261  			Convey("err cases", func() {
   262  				buf := mkBuf(nil)
   263  
   264  				Convey("nil", func() {
   265  					_, err := Deserialize.Key(buf)
   266  					So(err, ShouldEqual, io.EOF)
   267  				})
   268  				Convey("str", func() {
   269  					_, err := buf.WriteString("sup")
   270  					die(err)
   271  					_, err = Deserialize.Key(buf)
   272  					So(err, ShouldErrLike, "expected actualCtx")
   273  				})
   274  				Convey("truncated 1", func() {
   275  					die(buf.WriteByte(1)) // actualCtx == 1
   276  					_, err := Deserialize.Key(buf)
   277  					So(err, ShouldEqual, io.EOF)
   278  				})
   279  				Convey("truncated 2", func() {
   280  					die(buf.WriteByte(1)) // actualCtx == 1
   281  					ws(buf, "aid")
   282  					_, err := Deserialize.Key(buf)
   283  					So(err, ShouldEqual, io.EOF)
   284  				})
   285  				Convey("truncated 3", func() {
   286  					die(buf.WriteByte(1)) // actualCtx == 1
   287  					ws(buf, "aid")
   288  					ws(buf, "ns")
   289  					_, err := Deserialize.Key(buf)
   290  					So(err, ShouldEqual, io.EOF)
   291  				})
   292  				Convey("huge key", func() {
   293  					die(buf.WriteByte(1)) // actualCtx == 1
   294  					ws(buf, "aid")
   295  					ws(buf, "ns")
   296  					for i := 1; i < 60; i++ {
   297  						die(buf.WriteByte(1))
   298  						die(Serialize.KeyTok(buf, KeyTok{Kind: "sup", IntID: int64(i)}))
   299  					}
   300  					die(buf.WriteByte(0))
   301  					_, err := Deserialize.Key(buf)
   302  					So(err, ShouldErrLike, "huge key")
   303  				})
   304  				Convey("insufficient tokens", func() {
   305  					die(buf.WriteByte(1)) // actualCtx == 1
   306  					ws(buf, "aid")
   307  					ws(buf, "ns")
   308  					wui(buf, 2)
   309  					_, err := Deserialize.Key(buf)
   310  					So(err, ShouldEqual, io.EOF)
   311  				})
   312  				Convey("partial token 1", func() {
   313  					die(buf.WriteByte(1)) // actualCtx == 1
   314  					ws(buf, "aid")
   315  					ws(buf, "ns")
   316  					die(buf.WriteByte(1))
   317  					ws(buf, "hi")
   318  					_, err := Deserialize.Key(buf)
   319  					So(err, ShouldEqual, io.EOF)
   320  				})
   321  				Convey("partial token 2", func() {
   322  					die(buf.WriteByte(1)) // actualCtx == 1
   323  					ws(buf, "aid")
   324  					ws(buf, "ns")
   325  					die(buf.WriteByte(1))
   326  					ws(buf, "hi")
   327  					die(buf.WriteByte(byte(PTString)))
   328  					_, err := Deserialize.Key(buf)
   329  					So(err, ShouldEqual, io.EOF)
   330  				})
   331  				Convey("bad token (invalid type)", func() {
   332  					die(buf.WriteByte(1)) // actualCtx == 1
   333  					ws(buf, "aid")
   334  					ws(buf, "ns")
   335  					die(buf.WriteByte(1))
   336  					ws(buf, "hi")
   337  					die(buf.WriteByte(byte(PTBlobKey)))
   338  					_, err := Deserialize.Key(buf)
   339  					So(err, ShouldErrLike, "invalid type PTBlobKey")
   340  				})
   341  				Convey("bad token (invalid IntID)", func() {
   342  					die(buf.WriteByte(1)) // actualCtx == 1
   343  					ws(buf, "aid")
   344  					ws(buf, "ns")
   345  					die(buf.WriteByte(1))
   346  					ws(buf, "hi")
   347  					die(buf.WriteByte(byte(PTInt)))
   348  					wi(buf, -2)
   349  					_, err := Deserialize.Key(buf)
   350  					So(err, ShouldErrLike, "zero/negative")
   351  				})
   352  			})
   353  		})
   354  
   355  		Convey("ReadGeoPoint", func() {
   356  			buf := mkBuf(nil)
   357  			Convey("trunc 1", func() {
   358  				_, err := Deserialize.GeoPoint(buf)
   359  				So(err, ShouldEqual, io.EOF)
   360  			})
   361  			Convey("trunc 2", func() {
   362  				wf(buf, 100)
   363  				_, err := Deserialize.GeoPoint(buf)
   364  				So(err, ShouldEqual, io.EOF)
   365  			})
   366  			Convey("invalid", func() {
   367  				wf(buf, 100)
   368  				wf(buf, 1000)
   369  				_, err := Deserialize.GeoPoint(buf)
   370  				So(err, ShouldErrLike, "invalid GeoPoint")
   371  			})
   372  		})
   373  
   374  		Convey("WriteTime", func() {
   375  			Convey("in non-UTC!", func() {
   376  				pst, err := time.LoadLocation("America/Los_Angeles")
   377  				So(err, ShouldBeNil)
   378  				So(func() {
   379  					die(Serialize.Time(mkBuf(nil), time.Now().In(pst)))
   380  				}, ShouldPanic)
   381  			})
   382  		})
   383  
   384  		Convey("ReadTime", func() {
   385  			Convey("trunc 1", func() {
   386  				_, err := Deserialize.Time(mkBuf(nil))
   387  				So(err, ShouldEqual, io.EOF)
   388  			})
   389  		})
   390  
   391  		Convey("ReadProperty", func() {
   392  			buf := mkBuf(nil)
   393  			Convey("trunc 1", func() {
   394  				p, err := Deserialize.Property(buf)
   395  				So(err, ShouldEqual, io.EOF)
   396  				So(p.Type(), ShouldEqual, PTNull)
   397  				So(p.Value(), ShouldBeNil)
   398  			})
   399  			Convey("trunc (PTBytes)", func() {
   400  				die(buf.WriteByte(byte(PTBytes)))
   401  				_, err := Deserialize.Property(buf)
   402  				So(err, ShouldEqual, io.EOF)
   403  			})
   404  			Convey("trunc (PTBlobKey)", func() {
   405  				die(buf.WriteByte(byte(PTBlobKey)))
   406  				_, err := Deserialize.Property(buf)
   407  				So(err, ShouldEqual, io.EOF)
   408  			})
   409  			Convey("invalid type", func() {
   410  				die(buf.WriteByte(byte(PTUnknown + 1)))
   411  				_, err := Deserialize.Property(buf)
   412  				So(err, ShouldErrLike, "unknown type!")
   413  			})
   414  		})
   415  
   416  		Convey("ReadPropertyMap", func() {
   417  			buf := mkBuf(nil)
   418  			Convey("trunc 1", func() {
   419  				_, err := Deserialize.PropertyMap(buf)
   420  				So(err, ShouldEqual, io.EOF)
   421  			})
   422  			Convey("too many rows", func() {
   423  				wui(buf, 1000000)
   424  				_, err := Deserialize.PropertyMap(buf)
   425  				So(err, ShouldErrLike, "huge number of rows")
   426  			})
   427  			Convey("trunc 2", func() {
   428  				wui(buf, 10)
   429  				_, err := Deserialize.PropertyMap(buf)
   430  				So(err, ShouldEqual, io.EOF)
   431  			})
   432  			Convey("trunc 3", func() {
   433  				wui(buf, 10)
   434  				ws(buf, "ohai")
   435  				_, err := Deserialize.PropertyMap(buf)
   436  				So(err, ShouldEqual, io.EOF)
   437  			})
   438  			Convey("too many values", func() {
   439  				wui(buf, 10)
   440  				ws(buf, "ohai")
   441  				wui(buf, 100000)
   442  				_, err := Deserialize.PropertyMap(buf)
   443  				So(err, ShouldErrLike, "huge number of properties")
   444  			})
   445  			Convey("trunc 4", func() {
   446  				wui(buf, 10)
   447  				ws(buf, "ohai")
   448  				wui(buf, 10)
   449  				_, err := Deserialize.PropertyMap(buf)
   450  				So(err, ShouldEqual, io.EOF)
   451  			})
   452  		})
   453  
   454  		Convey("IndexDefinition", func() {
   455  			id := IndexDefinition{Kind: "kind"}
   456  			data := Serialize.ToBytes(*id.PrepForIdxTable())
   457  			newID, err := Deserialize.IndexDefinition(mkBuf(data))
   458  			So(err, ShouldBeNil)
   459  			So(newID.Flip(), ShouldResemble, id.Normalize())
   460  
   461  			id.SortBy = append(id.SortBy, IndexColumn{Property: "prop"})
   462  			data = Serialize.ToBytes(*id.PrepForIdxTable())
   463  			newID, err = Deserialize.IndexDefinition(mkBuf(data))
   464  			So(err, ShouldBeNil)
   465  			So(newID.Flip(), ShouldResemble, id.Normalize())
   466  
   467  			id.SortBy = append(id.SortBy, IndexColumn{Property: "other", Descending: true})
   468  			id.Ancestor = true
   469  			data = Serialize.ToBytes(*id.PrepForIdxTable())
   470  			newID, err = Deserialize.IndexDefinition(mkBuf(data))
   471  			So(err, ShouldBeNil)
   472  			So(newID.Flip(), ShouldResemble, id.Normalize())
   473  
   474  			// invalid
   475  			id.SortBy = append(id.SortBy, IndexColumn{Property: "", Descending: true})
   476  			data = Serialize.ToBytes(*id.PrepForIdxTable())
   477  			newID, err = Deserialize.IndexDefinition(mkBuf(data))
   478  			So(err, ShouldBeNil)
   479  			So(newID.Flip(), ShouldResemble, id.Normalize())
   480  
   481  			Convey("too many", func() {
   482  				id := IndexDefinition{Kind: "wat"}
   483  				for i := 0; i < maxIndexColumns+1; i++ {
   484  					id.SortBy = append(id.SortBy, IndexColumn{Property: "Hi", Descending: true})
   485  				}
   486  				data := Serialize.ToBytes(*id.PrepForIdxTable())
   487  				newID, err = Deserialize.IndexDefinition(mkBuf(data))
   488  				So(err, ShouldErrLike, "over 64 sort orders")
   489  			})
   490  		})
   491  	})
   492  }
   493  
   494  func TestIndexedProperties(t *testing.T) {
   495  	t.Parallel()
   496  
   497  	fakeKey := mkKeyCtx("dev~app", "ns", "parentKind", "sid", "knd", 10)
   498  
   499  	innerKey1 := mkKeyCtx("dev~app", "ns", "parentKind", "sid", "innerKey", 1)
   500  	innerKey2 := mkKeyCtx("dev~app", "ns", "parentKind", "sid", "innerKey", 2)
   501  	innerKey3 := mkKeyCtx("dev~app", "ns", "parentKind", "sid", "innerKey", 3)
   502  
   503  	Convey("TestIndexedProperties", t, func() {
   504  		pm := PropertyMap{
   505  			"wat":  PropertySlice{mpNI("thing"), mp("hat"), mp(100)},
   506  			"nerd": mp(103.7),
   507  			"spaz": mpNI(false),
   508  			"nested": PropertySlice{
   509  				mp(PropertyMap{
   510  					"$key":  mpNI(innerKey1),
   511  					"prop":  mp(123),
   512  					"slice": PropertySlice{mp(123), mp(456)},
   513  					"ni":    mpNI(666),
   514  				}),
   515  				mpNI(PropertyMap{ // will be skipped, not indexed
   516  					"$key":  mpNI(innerKey2),
   517  					"prop":  mp(123),
   518  					"slice": PropertySlice{mp(123), mp(456)},
   519  				}),
   520  				mp(PropertyMap{
   521  					"$kind":   mpNI("innerKey"),
   522  					"$id":     mpNI(3),
   523  					"$parent": mpNI(innerKey3.Parent()),
   524  					"prop":    mp(456),
   525  					"slice":   PropertySlice{mp(456), mp(789)},
   526  					"ni":      mpNI(666),
   527  				}),
   528  				mp(PropertyMap{ // key is optional
   529  					"prop": mp(777),
   530  					"deeper": mp(PropertyMap{
   531  						"deep": mp(888),
   532  					}),
   533  				}),
   534  			},
   535  		}
   536  
   537  		Convey("IndexedProperties", func() {
   538  			sip := Serialize.IndexedProperties(fakeKey, pm)
   539  			So(len(sip), ShouldEqual, 8)
   540  			sip.Sort()
   541  
   542  			So(sip, ShouldResemble, IndexedProperties{
   543  				"wat": {
   544  					Serialize.ToBytes(mp(100)),
   545  					Serialize.ToBytes(mp("hat")),
   546  					// 'thing' is skipped, because it's not NoIndex
   547  				},
   548  				"nerd": {
   549  					Serialize.ToBytes(mp(103.7)),
   550  				},
   551  				"nested.__key__": {
   552  					Serialize.ToBytes(mp(innerKey1)),
   553  					Serialize.ToBytes(mp(innerKey3)),
   554  				},
   555  				"nested.deeper.deep": {
   556  					Serialize.ToBytes(mp(888)),
   557  				},
   558  				"nested.prop": {
   559  					Serialize.ToBytes(mp(123)),
   560  					Serialize.ToBytes(mp(456)),
   561  					Serialize.ToBytes(mp(777)),
   562  				},
   563  				"nested.slice": {
   564  					Serialize.ToBytes(mp(123)),
   565  					Serialize.ToBytes(mp(456)),
   566  					Serialize.ToBytes(mp(789)),
   567  				},
   568  				"__key__": {
   569  					Serialize.ToBytes(mp(fakeKey)),
   570  				},
   571  				"__ancestor__": {
   572  					Serialize.ToBytes(mp(fakeKey.Parent())),
   573  					Serialize.ToBytes(mp(fakeKey)),
   574  				},
   575  			})
   576  		})
   577  
   578  		Convey("IndexedPropertiesForIndicies", func() {
   579  			sip := Serialize.IndexedPropertiesForIndicies(fakeKey, pm, []IndexColumn{
   580  				{Property: "wat"},
   581  				{Property: "wat", Descending: true},
   582  				{Property: "unknown"},
   583  				{Property: "nested.__key__"},
   584  			})
   585  			So(len(sip), ShouldEqual, 4)
   586  			sip.Sort()
   587  
   588  			So(sip, ShouldResemble, IndexedProperties{
   589  				"wat": {
   590  					Serialize.ToBytes(mp(100)),
   591  					Serialize.ToBytes(mp("hat")),
   592  				},
   593  				"nested.__key__": {
   594  					Serialize.ToBytes(mp(innerKey1)),
   595  					Serialize.ToBytes(mp(innerKey3)),
   596  				},
   597  				"__key__": {
   598  					Serialize.ToBytes(mp(fakeKey)),
   599  				},
   600  				"__ancestor__": {
   601  					Serialize.ToBytes(mp(fakeKey.Parent())),
   602  					Serialize.ToBytes(mp(fakeKey)),
   603  				},
   604  			})
   605  		})
   606  	})
   607  }