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