go.mercari.io/datastore@v1.8.2/dsmiddleware/splitop/splitcall_test.go (about) 1 package splitop 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/internal/testutils" 13 ) 14 15 func TestSplitOp_Basic(t *testing.T) { 16 ctx, client, cleanUp := testutils.SetupCloudDatastore(t) 17 defer cleanUp() 18 19 var logs []string 20 logf := func(ctx context.Context, format string, args ...interface{}) { 21 t.Logf(format, args...) 22 logs = append(logs, fmt.Sprintf(format, args...)) 23 } 24 25 // setup. strategies are first in - first apply. 26 27 bLog := dslog.NewLogger("before: ", logf) 28 client.AppendMiddleware(bLog) 29 defer func() { 30 // stop logging before cleanUp func called. 31 client.RemoveMiddleware(bLog) 32 }() 33 34 ch := New( 35 WithLogger(logf), 36 WithGetSplitThreshold(3), 37 WithPutSplitThreshold(2), 38 ) 39 client.AppendMiddleware(ch) 40 defer func() { 41 // stop logging before cleanUp func called. 42 client.RemoveMiddleware(ch) 43 }() 44 45 aLog := dslog.NewLogger("after: ", logf) 46 client.AppendMiddleware(aLog) 47 defer func() { 48 // stop logging before cleanUp func called. 49 client.RemoveMiddleware(aLog) 50 }() 51 52 // exec. 53 54 type Data struct { 55 Name string 56 } 57 58 // Put 59 var keys []datastore.Key 60 var entities []*Data 61 for i := 1; i <= 5; i++ { 62 keys = append(keys, client.IDKey("Data", int64(i), nil)) 63 entities = append(entities, &Data{Name: fmt.Sprintf("Data%d", i)}) 64 } 65 _, err := client.PutMulti(ctx, keys, entities) 66 if err != nil { 67 t.Fatal(err) 68 } 69 70 // Get 71 result := make([]*Data, len(keys)) 72 err = client.GetMulti(ctx, keys, result) 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 for idx, obj := range result { 78 if v := obj.Name; v != fmt.Sprintf("Data%d", keys[idx].ID()) { 79 t.Errorf("unexpected: %v", v) 80 } 81 } 82 83 expected := heredoc.Doc(` 84 before: PutMultiWithoutTx #1, len(keys)=5, keys=[/Data,1, /Data,2, /Data,3, /Data,4, /Data,5] 85 put 5 keys 86 put [0, 2) range keys 87 after: PutMultiWithoutTx #1, len(keys)=2, keys=[/Data,1, /Data,2] 88 after: PutMultiWithoutTx #1, keys=[/Data,1, /Data,2] 89 put [2, 4) range keys 90 after: PutMultiWithoutTx #2, len(keys)=2, keys=[/Data,3, /Data,4] 91 after: PutMultiWithoutTx #2, keys=[/Data,3, /Data,4] 92 put [4, 5) range keys 93 after: PutMultiWithoutTx #3, len(keys)=1, keys=[/Data,5] 94 after: PutMultiWithoutTx #3, keys=[/Data,5] 95 before: PutMultiWithoutTx #1, keys=[/Data,1, /Data,2, /Data,3, /Data,4, /Data,5] 96 before: GetMultiWithoutTx #2, len(keys)=5, keys=[/Data,1, /Data,2, /Data,3, /Data,4, /Data,5] 97 get 5 keys 98 get [0, 3) range keys 99 after: GetMultiWithoutTx #4, len(keys)=3, keys=[/Data,1, /Data,2, /Data,3] 100 get [3, 5) range keys 101 after: GetMultiWithoutTx #5, len(keys)=2, keys=[/Data,4, /Data,5] 102 `) 103 104 if v := strings.Join(logs, "\n") + "\n"; v != expected { 105 t.Errorf("unexpected: %v", v) 106 } 107 } 108 109 func TestSplitOp_HasNoSuchEntity(t *testing.T) { 110 ctx, client, cleanUp := testutils.SetupCloudDatastore(t) 111 defer cleanUp() 112 113 var logs []string 114 logf := func(ctx context.Context, format string, args ...interface{}) { 115 t.Logf(format, args...) 116 logs = append(logs, fmt.Sprintf(format, args...)) 117 } 118 119 // setup. strategies are first in - first apply. 120 121 bLog := dslog.NewLogger("before: ", logf) 122 client.AppendMiddleware(bLog) 123 defer func() { 124 // stop logging before cleanUp func called. 125 client.RemoveMiddleware(bLog) 126 }() 127 128 ch := New( 129 WithLogger(logf), 130 WithGetSplitThreshold(3), 131 WithPutSplitThreshold(2), 132 ) 133 client.AppendMiddleware(ch) 134 defer func() { 135 // stop logging before cleanUp func called. 136 client.RemoveMiddleware(ch) 137 }() 138 139 aLog := dslog.NewLogger("after: ", logf) 140 client.AppendMiddleware(aLog) 141 defer func() { 142 // stop logging before cleanUp func called. 143 client.RemoveMiddleware(aLog) 144 }() 145 146 // exec. 147 148 type Data struct { 149 Name string 150 } 151 152 // Put 153 var keys []datastore.Key 154 { 155 var putKeys []datastore.Key 156 var entities []*Data 157 for i := 1; i <= 5; i++ { 158 key := client.IDKey("Data", int64(i), nil) 159 keys = append(keys, key) 160 161 switch key.ID() { 162 case 1, 3, 5: 163 putKeys = append(putKeys, key) 164 entities = append(entities, &Data{Name: fmt.Sprintf("Data%d", key.ID())}) 165 } 166 } 167 _, err := client.PutMulti(ctx, putKeys, entities) 168 if err != nil { 169 t.Fatal(err) 170 } 171 } 172 173 // Get 174 result := make([]*Data, len(keys)) 175 err := client.GetMulti(ctx, keys, result) 176 if mErr, ok := err.(datastore.MultiError); !ok { 177 t.Fatal(err) 178 } else { 179 for idx, err := range mErr { 180 id := keys[idx].ID() 181 switch id { 182 case 1, 3, 5: 183 if err != nil { 184 t.Errorf("unexpected error content: %d, %v", id, err) 185 } 186 default: 187 if err != datastore.ErrNoSuchEntity { 188 t.Errorf("unexpected error content: %d, %v", id, err) 189 } 190 } 191 } 192 } 193 194 for idx, obj := range result { 195 if obj == nil { 196 continue 197 } 198 if v := obj.Name; v != fmt.Sprintf("Data%d", keys[idx].ID()) { 199 t.Errorf("unexpected: %v", v) 200 } 201 } 202 203 expected := heredoc.Doc(` 204 before: PutMultiWithoutTx #1, len(keys)=3, keys=[/Data,1, /Data,3, /Data,5] 205 put 3 keys 206 put [0, 2) range keys 207 after: PutMultiWithoutTx #1, len(keys)=2, keys=[/Data,1, /Data,3] 208 after: PutMultiWithoutTx #1, keys=[/Data,1, /Data,3] 209 put [2, 3) range keys 210 after: PutMultiWithoutTx #2, len(keys)=1, keys=[/Data,5] 211 after: PutMultiWithoutTx #2, keys=[/Data,5] 212 before: PutMultiWithoutTx #1, keys=[/Data,1, /Data,3, /Data,5] 213 before: GetMultiWithoutTx #2, len(keys)=5, keys=[/Data,1, /Data,2, /Data,3, /Data,4, /Data,5] 214 get 5 keys 215 get [0, 3) range keys 216 after: GetMultiWithoutTx #3, len(keys)=3, keys=[/Data,1, /Data,2, /Data,3] 217 after: GetMultiWithoutTx #3, err=datastore: no such entity 218 get [3, 5) range keys 219 after: GetMultiWithoutTx #4, len(keys)=2, keys=[/Data,4, /Data,5] 220 after: GetMultiWithoutTx #4, err=datastore: no such entity 221 before: GetMultiWithoutTx #2, err=datastore: no such entity (and 1 other error) 222 `) 223 224 if v := strings.Join(logs, "\n") + "\n"; v != expected { 225 t.Errorf("unexpected: %v", v) 226 } 227 }