go.mercari.io/datastore@v1.8.2/testsuite/dsmiddleware/fishbone/fishbone.go (about) 1 package fishbone 2 3 import ( 4 "context" 5 "fmt" 6 "strings" 7 "testing" 8 9 "github.com/MakeNowJust/heredoc/v2" 10 "go.mercari.io/datastore" 11 "go.mercari.io/datastore/dsmiddleware/dslog" 12 "go.mercari.io/datastore/dsmiddleware/fishbone" 13 "go.mercari.io/datastore/testsuite" 14 "google.golang.org/api/iterator" 15 ) 16 17 // TestSuite contains all the test cases that this package provides. 18 var TestSuite = map[string]testsuite.Test{ 19 "FishBone_QueryWithoutTx": queryWithoutTx, 20 "FishBone_QueryWithTx": queryWithTx, 21 } 22 23 func init() { 24 testsuite.MergeTestSuite(TestSuite) 25 } 26 27 func queryWithoutTx(ctx context.Context, t *testing.T, client datastore.Client) { 28 defer func() { 29 err := client.Close() 30 if err != nil { 31 t.Fatal(err) 32 } 33 }() 34 35 var logs []string 36 logf := func(ctx context.Context, format string, args ...interface{}) { 37 t.Logf(format, args...) 38 logs = append(logs, fmt.Sprintf(format, args...)) 39 } 40 41 // setup. strategies are first in - first apply. 42 43 bLog := dslog.NewLogger("before: ", logf) 44 client.AppendMiddleware(bLog) 45 defer func() { 46 // stop logging before cleanUp func called. 47 client.RemoveMiddleware(bLog) 48 }() 49 50 m := fishbone.New() 51 client.AppendMiddleware(m) 52 defer func() { 53 // stop logging before cleanUp func called. 54 client.RemoveMiddleware(m) 55 }() 56 57 aLog := dslog.NewLogger("after: ", logf) 58 client.AppendMiddleware(aLog) 59 defer func() { 60 // stop logging before cleanUp func called. 61 client.RemoveMiddleware(aLog) 62 }() 63 64 // exec. 65 66 type Data struct { 67 Name string 68 } 69 70 const size = 3 71 72 keys := make([]datastore.Key, size) 73 list := make([]*Data, size) 74 for i := 0; i < size; i++ { 75 keys[i] = client.NameKey("Data", fmt.Sprintf("#%d", i+1), nil) 76 list[i] = &Data{ 77 Name: fmt.Sprintf("#%d", i+1), 78 } 79 } 80 _, err := client.PutMulti(ctx, keys, list) 81 if err != nil { 82 t.Fatal(err) 83 } 84 85 q := client.NewQuery("Data").Order("-Name") 86 87 // Run 88 iter := client.Run(ctx, q) 89 90 // Next 91 cnt := 0 92 for { 93 obj := &Data{} 94 key, err := iter.Next(obj) 95 if err == iterator.Done { 96 break 97 } else if err != nil { 98 t.Fatal(err) 99 } 100 if v := obj.Name; v == "" || v != key.Name() { 101 t.Errorf("unexpected: %v", cnt) 102 } 103 cnt++ 104 } 105 if cnt != size { 106 t.Errorf("unexpected: %v", cnt) 107 } 108 109 // GetAll 110 q = client.NewQuery("Data").Order("-Name") 111 list = nil 112 keys, err = client.GetAll(ctx, q, &list) 113 if err != nil { 114 t.Fatal(err) 115 } 116 if v := len(list); v != size { 117 t.Errorf("unexpected: %v", v) 118 } 119 for idx, obj := range list { 120 if v := obj.Name; v == "" || v != keys[idx].Name() { 121 t.Errorf("unexpected: %v", v) 122 } 123 } 124 125 expected := heredoc.Doc(` 126 before: PutMultiWithoutTx #1, len(keys)=3, keys=[/Data,#1, /Data,#2, /Data,#3] 127 after: PutMultiWithoutTx #1, len(keys)=3, keys=[/Data,#1, /Data,#2, /Data,#3] 128 after: PutMultiWithoutTx #1, keys=[/Data,#1, /Data,#2, /Data,#3] 129 before: PutMultiWithoutTx #1, keys=[/Data,#1, /Data,#2, /Data,#3] 130 before: Run #2, q=v1:Data&or=-Name 131 after: Run #2, q=v1:Data&or=-Name&k=t 132 before: Next #3, q=v1:Data&or=-Name 133 after: Next #3, q=v1:Data&or=-Name 134 after: Next #3, key=/Data,#3 135 before: GetMultiWithoutTx #4, len(keys)=1, keys=[/Data,#3] 136 after: GetMultiWithoutTx #4, len(keys)=1, keys=[/Data,#3] 137 before: Next #3, key=/Data,#3 138 before: Next #5, q=v1:Data&or=-Name 139 after: Next #5, q=v1:Data&or=-Name 140 after: Next #5, key=/Data,#2 141 before: GetMultiWithoutTx #6, len(keys)=1, keys=[/Data,#2] 142 after: GetMultiWithoutTx #6, len(keys)=1, keys=[/Data,#2] 143 before: Next #5, key=/Data,#2 144 before: Next #7, q=v1:Data&or=-Name 145 after: Next #7, q=v1:Data&or=-Name 146 after: Next #7, key=/Data,#1 147 before: GetMultiWithoutTx #8, len(keys)=1, keys=[/Data,#1] 148 after: GetMultiWithoutTx #8, len(keys)=1, keys=[/Data,#1] 149 before: Next #7, key=/Data,#1 150 before: Next #9, q=v1:Data&or=-Name 151 after: Next #9, q=v1:Data&or=-Name 152 after: Next #9, err=no more items in iterator 153 before: Next #9, err=no more items in iterator 154 before: GetAll #10, q=v1:Data&or=-Name 155 after: GetAll #10, q=v1:Data&or=-Name&k=t 156 after: GetAll #10, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1] 157 before: GetMultiWithoutTx #11, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1] 158 after: GetMultiWithoutTx #11, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1] 159 before: GetAll #10, len(keys)=3, keys=[/Data,#3, /Data,#2, /Data,#1] 160 `) 161 162 if v := strings.Join(logs, "\n") + "\n"; v != expected { 163 t.Errorf("unexpected: %v", v) 164 } 165 } 166 167 func queryWithTx(ctx context.Context, t *testing.T, client datastore.Client) { 168 defer func() { 169 err := client.Close() 170 if err != nil { 171 t.Fatal(err) 172 } 173 }() 174 175 var logs []string 176 logf := func(ctx context.Context, format string, args ...interface{}) { 177 t.Logf(format, args...) 178 logs = append(logs, fmt.Sprintf(format, args...)) 179 } 180 181 // setup. strategies are first in - first apply. 182 183 bLog := dslog.NewLogger("before: ", logf) 184 client.AppendMiddleware(bLog) 185 defer func() { 186 // stop logging before cleanUp func called. 187 client.RemoveMiddleware(bLog) 188 }() 189 190 m := fishbone.New() 191 client.AppendMiddleware(m) 192 defer func() { 193 // stop logging before cleanUp func called. 194 client.RemoveMiddleware(m) 195 }() 196 197 aLog := dslog.NewLogger("after: ", logf) 198 client.AppendMiddleware(aLog) 199 defer func() { 200 // stop logging before cleanUp func called. 201 client.RemoveMiddleware(aLog) 202 }() 203 204 // exec. 205 206 type Data struct { 207 Name string 208 } 209 210 const size = 3 211 212 parentKey := client.NameKey("Parent", "p", nil) 213 keys := make([]datastore.Key, size) 214 list := make([]*Data, size) 215 for i := 0; i < size; i++ { 216 keys[i] = client.NameKey("Data", fmt.Sprintf("#%d", i+1), parentKey) 217 list[i] = &Data{ 218 Name: fmt.Sprintf("#%d", i+1), 219 } 220 } 221 _, err := client.PutMulti(ctx, keys, list) 222 if err != nil { 223 t.Fatal(err) 224 } 225 226 tx, err := client.NewTransaction(ctx) 227 if err != nil { 228 t.Fatal(err) 229 } 230 defer func() { 231 err := tx.Rollback() 232 if err != nil { 233 t.Fatal(err) 234 } 235 }() 236 237 q := client.NewQuery("Data").Order("-Name").Ancestor(parentKey).Transaction(tx) 238 239 // Run 240 iter := client.Run(ctx, q) 241 242 // Next 243 cnt := 0 244 for { 245 obj := &Data{} 246 key, err := iter.Next(obj) 247 if err == iterator.Done { 248 break 249 } else if err != nil { 250 t.Fatal(err) 251 } 252 if v := obj.Name; v == "" || v != key.Name() { 253 t.Errorf("unexpected: %v", cnt) 254 } 255 cnt++ 256 } 257 if cnt != size { 258 t.Errorf("unexpected: %v", cnt) 259 } 260 261 // GetAll 262 q = client.NewQuery("Data").Order("-Name").Ancestor(parentKey).Transaction(tx) 263 list = nil 264 keys, err = client.GetAll(ctx, q, &list) 265 if err != nil { 266 t.Fatal(err) 267 } 268 if v := len(list); v != size { 269 t.Errorf("unexpected: %v", v) 270 } 271 for idx, obj := range list { 272 if v := obj.Name; v == "" || v != keys[idx].Name() { 273 t.Errorf("unexpected: %v", v) 274 } 275 } 276 277 expected := heredoc.Doc(` 278 before: PutMultiWithoutTx #1, len(keys)=3, keys=[/Parent,p/Data,#1, /Parent,p/Data,#2, /Parent,p/Data,#3] 279 after: PutMultiWithoutTx #1, len(keys)=3, keys=[/Parent,p/Data,#1, /Parent,p/Data,#2, /Parent,p/Data,#3] 280 after: PutMultiWithoutTx #1, keys=[/Parent,p/Data,#1, /Parent,p/Data,#2, /Parent,p/Data,#3] 281 before: PutMultiWithoutTx #1, keys=[/Parent,p/Data,#1, /Parent,p/Data,#2, /Parent,p/Data,#3] 282 before: Run #2, q=v1:Data&a=/Parent,p&t=t&or=-Name 283 after: Run #2, q=v1:Data&a=/Parent,p&t=t&or=-Name&k=t 284 before: Next #3, q=v1:Data&a=/Parent,p&t=t&or=-Name 285 after: Next #3, q=v1:Data&a=/Parent,p&t=t&or=-Name 286 after: Next #3, key=/Parent,p/Data,#3 287 before: GetMultiWithTx #4, len(keys)=1, keys=[/Parent,p/Data,#3] 288 after: GetMultiWithTx #4, len(keys)=1, keys=[/Parent,p/Data,#3] 289 before: Next #3, key=/Parent,p/Data,#3 290 before: Next #5, q=v1:Data&a=/Parent,p&t=t&or=-Name 291 after: Next #5, q=v1:Data&a=/Parent,p&t=t&or=-Name 292 after: Next #5, key=/Parent,p/Data,#2 293 before: GetMultiWithTx #6, len(keys)=1, keys=[/Parent,p/Data,#2] 294 after: GetMultiWithTx #6, len(keys)=1, keys=[/Parent,p/Data,#2] 295 before: Next #5, key=/Parent,p/Data,#2 296 before: Next #7, q=v1:Data&a=/Parent,p&t=t&or=-Name 297 after: Next #7, q=v1:Data&a=/Parent,p&t=t&or=-Name 298 after: Next #7, key=/Parent,p/Data,#1 299 before: GetMultiWithTx #8, len(keys)=1, keys=[/Parent,p/Data,#1] 300 after: GetMultiWithTx #8, len(keys)=1, keys=[/Parent,p/Data,#1] 301 before: Next #7, key=/Parent,p/Data,#1 302 before: Next #9, q=v1:Data&a=/Parent,p&t=t&or=-Name 303 after: Next #9, q=v1:Data&a=/Parent,p&t=t&or=-Name 304 after: Next #9, err=no more items in iterator 305 before: Next #9, err=no more items in iterator 306 before: GetAll #10, q=v1:Data&a=/Parent,p&t=t&or=-Name 307 after: GetAll #10, q=v1:Data&a=/Parent,p&t=t&or=-Name&k=t 308 after: GetAll #10, len(keys)=3, keys=[/Parent,p/Data,#3, /Parent,p/Data,#2, /Parent,p/Data,#1] 309 before: GetMultiWithTx #11, len(keys)=3, keys=[/Parent,p/Data,#3, /Parent,p/Data,#2, /Parent,p/Data,#1] 310 after: GetMultiWithTx #11, len(keys)=3, keys=[/Parent,p/Data,#3, /Parent,p/Data,#2, /Parent,p/Data,#1] 311 before: GetAll #10, len(keys)=3, keys=[/Parent,p/Data,#3, /Parent,p/Data,#2, /Parent,p/Data,#1] 312 `) 313 314 if v := strings.Join(logs, "\n") + "\n"; v != expected { 315 t.Errorf("unexpected: %v", v) 316 } 317 }