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