go.mercari.io/datastore@v1.8.2/testsuite/realworld/tbf/main.go (about) 1 package tbf 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/json" 7 "fmt" 8 "io/ioutil" 9 "strings" 10 "testing" 11 "time" 12 13 "github.com/golang/protobuf/proto" 14 "go.mercari.io/datastore" 15 "go.mercari.io/datastore/testsuite" 16 netcontext "golang.org/x/net/context" 17 "google.golang.org/appengine" 18 ) 19 20 // TestSuite contains all the test cases that this package provides. 21 var TestSuite = map[string]testsuite.Test{ 22 "RealWorld_TBF": tbf, 23 } 24 25 func init() { 26 testsuite.MergeTestSuite(TestSuite) 27 } 28 29 type contextClient struct{} 30 type contextBatch struct{} 31 32 func timeNow() time.Time { 33 l, err := time.LoadLocation("Asia/Tokyo") 34 if err != nil { 35 panic(err) 36 } 37 return time.Date(2017, 11, 8, 10, 11, 12, 13, l) 38 } 39 40 func tbf(ctx context.Context, t *testing.T, client datastore.Client) { 41 defer func() { 42 err := client.Close() 43 if err != nil { 44 t.Fatal(err) 45 } 46 }() 47 48 // それぞれのCircleに4枚の画像を持たせて、Circleを10件Getしたい。RPCは Query 1回 + BatchGet 1回 の合計2回がいい 49 50 // clientは複数作ってぶん回すとどっかでブロックされて処理が返ってこなくなるので使いまわす 51 ctx = context.WithValue(ctx, contextClient{}, client) 52 // batchは再利用可能 53 batch := client.Batch() 54 ctx = context.WithValue(ctx, contextBatch{}, batch) 55 56 rpcCount := 0 57 inMemcacheTestSuite := false 58 if testsuite.IsAEDatastoreClient(ctx) { 59 // checking rpc count when testing in ae. 60 ctx = appengine.WithAPICallFunc(ctx, func(ctx netcontext.Context, service, method string, in, out proto.Message) error { 61 t.Log(service, method) 62 if service == "datastore_v3" { 63 rpcCount++ 64 } 65 if service == "memcache" { 66 // if memcache service called, this test in the TestAEDatastoreWithAEMemcacheTestSuite. 67 inMemcacheTestSuite = true 68 } 69 70 return appengine.APICall(ctx, service, method, in, out) 71 }) 72 } 73 74 const circleLimit = 10 75 const imageLimit = 4 76 77 // Prepare entities 78 for i := 0; i < circleLimit; i++ { 79 // NOTE Don't use client.AllocateIDs for JSON format consistency 80 circleID := CircleID(1000000 + 10000*i) 81 circleKey := circleID.ToKey(client) 82 83 circle := &Circle{ 84 ID: circleID, 85 Name: fmt.Sprintf("サークル #%d", i+1), 86 } 87 for j := 0; j < imageLimit; j++ { 88 // NOTE Don't use client.AllocateIDs for JSON format consistency 89 imageID := imageID(circleKey.ID() + 1000 + int64(10*j)) 90 imageKey := imageID.ToKey(client) 91 92 image := &Image{ 93 ID: imageID, 94 OwnerCircleID: circleID, 95 GCSPath: fmt.Sprintf("%d/%d.jpg", circleKey.ID(), imageKey.ID()), 96 } 97 batch.Put(imageKey, image, nil) 98 99 circle.ImageIDs = append(circle.ImageIDs, image.ID) 100 circle.Images = append(circle.Images, image) 101 } 102 103 batch.Put(circleKey, circle, nil) 104 } 105 err := batch.Exec(ctx) 106 if err != nil { 107 t.Fatal(err) 108 } 109 if testsuite.IsAEDatastoreClient(ctx) && !inMemcacheTestSuite { 110 if rpcCount != 1 { 111 t.Errorf("unexpected: %v", rpcCount) 112 } 113 } 114 115 // fetch entities 116 rpcCount = 0 117 q := client.NewQuery(kindCircle) 118 var circleList []*Circle 119 _, err = client.GetAll(ctx, q, &circleList) 120 if err != nil { 121 t.Fatal(err) 122 } 123 err = batch.Exec(ctx) 124 if err != nil { 125 t.Fatal(err) 126 } 127 if testsuite.IsAEDatastoreClient(ctx) && !inMemcacheTestSuite { 128 if rpcCount != 2 { 129 t.Errorf("unexpected: %v", rpcCount) 130 } 131 } 132 133 if v := len(circleList); v != circleLimit { 134 t.Errorf("unexpected: %v", v) 135 } 136 for _, circle := range circleList { 137 if v := len(circle.Images); v != imageLimit { 138 t.Errorf("unexpected: %v", v) 139 } 140 for _, image := range circle.Images { 141 if v := image.GCSPath; !strings.HasPrefix(v, fmt.Sprintf("%d/", circle.ID)) { 142 t.Errorf("unexpected: %v", v) 143 } 144 } 145 } 146 147 { // obj <-> JSON 148 b, err := json.MarshalIndent(circleList, "", " ") 149 if err != nil { 150 t.Fatal(err) 151 } 152 153 const filePath = "../testsuite/realworld/tbf/realworld-tbf.json" 154 expected, err := ioutil.ReadFile(filePath) 155 if err != nil { 156 err = ioutil.WriteFile(filePath, b, 0644) 157 if err != nil { 158 t.Fatal(err) 159 } 160 expected = b 161 } 162 163 if !bytes.Equal(b, expected) { 164 t.Fatalf("unexpected json format. hint: rm %s", filePath) 165 } 166 167 var newCircleList []*Circle 168 err = json.Unmarshal(b, &newCircleList) 169 if err != nil { 170 t.Fatal(err) 171 } 172 173 if v := len(newCircleList); v != circleLimit { 174 t.Errorf("unexpected: %v", v) 175 } 176 for _, circle := range newCircleList { 177 if v := len(circle.Images); v != imageLimit { 178 t.Errorf("unexpected: %v", v) 179 } 180 for _, image := range circle.Images { 181 if v := image.GCSPath; !strings.HasPrefix(v, fmt.Sprintf("%d/", circle.ID)) { 182 t.Errorf("unexpected: %v", v) 183 } 184 } 185 } 186 } 187 188 { // Naked Get 189 q := client.NewQuery(kindImage) 190 var pss []datastore.PropertyList 191 _, err = client.GetAll(ctx, q, &pss) 192 if err != nil { 193 t.Fatal(err) 194 } 195 196 if v := len(pss); v != circleLimit*imageLimit { 197 t.Errorf("unexpected: %v", v) 198 } 199 for _, ps := range pss { 200 for _, p := range ps { 201 if !strings.HasSuffix(p.Name, "ID") { 202 continue 203 } 204 205 _, ok := p.Value.(datastore.Key) 206 if !ok { 207 t.Errorf("unexpected: %T", p.Value) 208 } 209 } 210 } 211 } 212 }