github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/registry/storage/driver/azure/randomwriter_test.go (about) 1 package azure 2 3 import ( 4 "bytes" 5 "io" 6 "io/ioutil" 7 "math/rand" 8 "reflect" 9 "strings" 10 "testing" 11 12 azure "github.com/Azure/azure-sdk-for-go/storage" 13 ) 14 15 func TestRandomWriter_writeChunkToBlocks(t *testing.T) { 16 s := NewStorageSimulator() 17 rw := newRandomBlobWriter(&s, 3) 18 rand := newBlockIDGenerator() 19 c := []byte("AAABBBCCCD") 20 21 if err := rw.bs.CreateBlockBlob("a", "b"); err != nil { 22 t.Fatal(err) 23 } 24 bw, nn, err := rw.writeChunkToBlocks("a", "b", bytes.NewReader(c), rand) 25 if err != nil { 26 t.Fatal(err) 27 } 28 if expected := int64(len(c)); nn != expected { 29 t.Fatalf("wrong nn:%v, expected:%v", nn, expected) 30 } 31 if expected := 4; len(bw) != expected { 32 t.Fatal("unexpected written block count") 33 } 34 35 bx, err := s.GetBlockList("a", "b", azure.BlockListTypeAll) 36 if err != nil { 37 t.Fatal(err) 38 } 39 if expected := 0; len(bx.CommittedBlocks) != expected { 40 t.Fatal("unexpected committed block count") 41 } 42 if expected := 4; len(bx.UncommittedBlocks) != expected { 43 t.Fatalf("unexpected uncommitted block count: %d -- %#v", len(bx.UncommittedBlocks), bx) 44 } 45 46 if err := rw.bs.PutBlockList("a", "b", bw); err != nil { 47 t.Fatal(err) 48 } 49 50 r, err := rw.bs.GetBlob("a", "b") 51 if err != nil { 52 t.Fatal(err) 53 } 54 assertBlobContents(t, r, c) 55 } 56 57 func TestRandomWriter_blocksLeftSide(t *testing.T) { 58 blob := "AAAAABBBBBCCC" 59 cases := []struct { 60 offset int64 61 expectedBlob string 62 expectedPattern []azure.BlockStatus 63 }{ 64 {0, "", []azure.BlockStatus{}}, // write to beginning, discard all 65 {13, blob, []azure.BlockStatus{azure.BlockStatusCommitted, azure.BlockStatusCommitted, azure.BlockStatusCommitted}}, // write to end, no change 66 {1, "A", []azure.BlockStatus{azure.BlockStatusUncommitted}}, // write at 1 67 {5, "AAAAA", []azure.BlockStatus{azure.BlockStatusCommitted}}, // write just after first block 68 {6, "AAAAAB", []azure.BlockStatus{azure.BlockStatusCommitted, azure.BlockStatusUncommitted}}, // split the second block 69 {9, "AAAAABBBB", []azure.BlockStatus{azure.BlockStatusCommitted, azure.BlockStatusUncommitted}}, // write just after first block 70 } 71 72 for _, c := range cases { 73 s := NewStorageSimulator() 74 rw := newRandomBlobWriter(&s, 5) 75 rand := newBlockIDGenerator() 76 77 if err := rw.bs.CreateBlockBlob("a", "b"); err != nil { 78 t.Fatal(err) 79 } 80 bw, _, err := rw.writeChunkToBlocks("a", "b", strings.NewReader(blob), rand) 81 if err != nil { 82 t.Fatal(err) 83 } 84 if err := rw.bs.PutBlockList("a", "b", bw); err != nil { 85 t.Fatal(err) 86 } 87 bx, err := rw.blocksLeftSide("a", "b", c.offset, rand) 88 if err != nil { 89 t.Fatal(err) 90 } 91 92 bs := []azure.BlockStatus{} 93 for _, v := range bx { 94 bs = append(bs, v.Status) 95 } 96 97 if !reflect.DeepEqual(bs, c.expectedPattern) { 98 t.Logf("Committed blocks %v", bw) 99 t.Fatalf("For offset %v: Expected pattern: %v, Got: %v\n(Returned: %v)", c.offset, c.expectedPattern, bs, bx) 100 } 101 if rw.bs.PutBlockList("a", "b", bx); err != nil { 102 t.Fatal(err) 103 } 104 r, err := rw.bs.GetBlob("a", "b") 105 if err != nil { 106 t.Fatal(err) 107 } 108 cout, err := ioutil.ReadAll(r) 109 if err != nil { 110 t.Fatal(err) 111 } 112 outBlob := string(cout) 113 if outBlob != c.expectedBlob { 114 t.Fatalf("wrong blob contents: %v, expected: %v", outBlob, c.expectedBlob) 115 } 116 } 117 } 118 119 func TestRandomWriter_blocksRightSide(t *testing.T) { 120 blob := "AAAAABBBBBCCC" 121 cases := []struct { 122 offset int64 123 size int64 124 expectedBlob string 125 expectedPattern []azure.BlockStatus 126 }{ 127 {0, 100, "", []azure.BlockStatus{}}, // overwrite the entire blob 128 {0, 3, "AABBBBBCCC", []azure.BlockStatus{azure.BlockStatusUncommitted, azure.BlockStatusCommitted, azure.BlockStatusCommitted}}, // split first block 129 {4, 1, "BBBBBCCC", []azure.BlockStatus{azure.BlockStatusCommitted, azure.BlockStatusCommitted}}, // write to last char of first block 130 {1, 6, "BBBCCC", []azure.BlockStatus{azure.BlockStatusUncommitted, azure.BlockStatusCommitted}}, // overwrite splits first and second block, last block remains 131 {3, 8, "CC", []azure.BlockStatus{azure.BlockStatusUncommitted}}, // overwrite a block in middle block, split end block 132 {10, 1, "CC", []azure.BlockStatus{azure.BlockStatusUncommitted}}, // overwrite first byte of rightmost block 133 {11, 2, "", []azure.BlockStatus{}}, // overwrite the rightmost index 134 {13, 20, "", []azure.BlockStatus{}}, // append to the end 135 } 136 137 for _, c := range cases { 138 s := NewStorageSimulator() 139 rw := newRandomBlobWriter(&s, 5) 140 rand := newBlockIDGenerator() 141 142 if err := rw.bs.CreateBlockBlob("a", "b"); err != nil { 143 t.Fatal(err) 144 } 145 bw, _, err := rw.writeChunkToBlocks("a", "b", strings.NewReader(blob), rand) 146 if err != nil { 147 t.Fatal(err) 148 } 149 if err := rw.bs.PutBlockList("a", "b", bw); err != nil { 150 t.Fatal(err) 151 } 152 bx, err := rw.blocksRightSide("a", "b", c.offset, c.size, rand) 153 if err != nil { 154 t.Fatal(err) 155 } 156 157 bs := []azure.BlockStatus{} 158 for _, v := range bx { 159 bs = append(bs, v.Status) 160 } 161 162 if !reflect.DeepEqual(bs, c.expectedPattern) { 163 t.Logf("Committed blocks %v", bw) 164 t.Fatalf("For offset %v-size:%v: Expected pattern: %v, Got: %v\n(Returned: %v)", c.offset, c.size, c.expectedPattern, bs, bx) 165 } 166 if rw.bs.PutBlockList("a", "b", bx); err != nil { 167 t.Fatal(err) 168 } 169 r, err := rw.bs.GetBlob("a", "b") 170 if err != nil { 171 t.Fatal(err) 172 } 173 cout, err := ioutil.ReadAll(r) 174 if err != nil { 175 t.Fatal(err) 176 } 177 outBlob := string(cout) 178 if outBlob != c.expectedBlob { 179 t.Fatalf("For offset %v-size:%v: wrong blob contents: %v, expected: %v", c.offset, c.size, outBlob, c.expectedBlob) 180 } 181 } 182 } 183 184 func TestRandomWriter_Write_NewBlob(t *testing.T) { 185 var ( 186 s = NewStorageSimulator() 187 rw = newRandomBlobWriter(&s, 1024*3) // 3 KB blocks 188 blob = randomContents(1024 * 7) // 7 KB blob 189 ) 190 if err := rw.bs.CreateBlockBlob("a", "b"); err != nil { 191 t.Fatal(err) 192 } 193 194 if _, err := rw.WriteBlobAt("a", "b", 10, bytes.NewReader(blob)); err == nil { 195 t.Fatal("expected error, got nil") 196 } 197 if _, err := rw.WriteBlobAt("a", "b", 100000, bytes.NewReader(blob)); err == nil { 198 t.Fatal("expected error, got nil") 199 } 200 if nn, err := rw.WriteBlobAt("a", "b", 0, bytes.NewReader(blob)); err != nil { 201 t.Fatal(err) 202 } else if expected := int64(len(blob)); expected != nn { 203 t.Fatalf("wrong written bytes count: %v, expected: %v", nn, expected) 204 } 205 if out, err := rw.bs.GetBlob("a", "b"); err != nil { 206 t.Fatal(err) 207 } else { 208 assertBlobContents(t, out, blob) 209 } 210 if bx, err := rw.bs.GetBlockList("a", "b", azure.BlockListTypeCommitted); err != nil { 211 t.Fatal(err) 212 } else if len(bx.CommittedBlocks) != 3 { 213 t.Fatalf("got wrong number of committed blocks: %v", len(bx.CommittedBlocks)) 214 } 215 216 // Replace first 512 bytes 217 leftChunk := randomContents(512) 218 blob = append(leftChunk, blob[512:]...) 219 if nn, err := rw.WriteBlobAt("a", "b", 0, bytes.NewReader(leftChunk)); err != nil { 220 t.Fatal(err) 221 } else if expected := int64(len(leftChunk)); expected != nn { 222 t.Fatalf("wrong written bytes count: %v, expected: %v", nn, expected) 223 } 224 if out, err := rw.bs.GetBlob("a", "b"); err != nil { 225 t.Fatal(err) 226 } else { 227 assertBlobContents(t, out, blob) 228 } 229 if bx, err := rw.bs.GetBlockList("a", "b", azure.BlockListTypeCommitted); err != nil { 230 t.Fatal(err) 231 } else if expected := 4; len(bx.CommittedBlocks) != expected { 232 t.Fatalf("got wrong number of committed blocks: %v, expected: %v", len(bx.CommittedBlocks), expected) 233 } 234 235 // Replace last 512 bytes with 1024 bytes 236 rightChunk := randomContents(1024) 237 offset := int64(len(blob) - 512) 238 blob = append(blob[:offset], rightChunk...) 239 if nn, err := rw.WriteBlobAt("a", "b", offset, bytes.NewReader(rightChunk)); err != nil { 240 t.Fatal(err) 241 } else if expected := int64(len(rightChunk)); expected != nn { 242 t.Fatalf("wrong written bytes count: %v, expected: %v", nn, expected) 243 } 244 if out, err := rw.bs.GetBlob("a", "b"); err != nil { 245 t.Fatal(err) 246 } else { 247 assertBlobContents(t, out, blob) 248 } 249 if bx, err := rw.bs.GetBlockList("a", "b", azure.BlockListTypeCommitted); err != nil { 250 t.Fatal(err) 251 } else if expected := 5; len(bx.CommittedBlocks) != expected { 252 t.Fatalf("got wrong number of committed blocks: %v, expected: %v", len(bx.CommittedBlocks), expected) 253 } 254 255 // Replace 2K-4K (overlaps 2 blocks from L/R) 256 newChunk := randomContents(1024 * 2) 257 offset = 1024 * 2 258 blob = append(append(blob[:offset], newChunk...), blob[offset+int64(len(newChunk)):]...) 259 if nn, err := rw.WriteBlobAt("a", "b", offset, bytes.NewReader(newChunk)); err != nil { 260 t.Fatal(err) 261 } else if expected := int64(len(newChunk)); expected != nn { 262 t.Fatalf("wrong written bytes count: %v, expected: %v", nn, expected) 263 } 264 if out, err := rw.bs.GetBlob("a", "b"); err != nil { 265 t.Fatal(err) 266 } else { 267 assertBlobContents(t, out, blob) 268 } 269 if bx, err := rw.bs.GetBlockList("a", "b", azure.BlockListTypeCommitted); err != nil { 270 t.Fatal(err) 271 } else if expected := 6; len(bx.CommittedBlocks) != expected { 272 t.Fatalf("got wrong number of committed blocks: %v, expected: %v\n%v", len(bx.CommittedBlocks), expected, bx.CommittedBlocks) 273 } 274 275 // Replace the entire blob 276 newBlob := randomContents(1024 * 30) 277 if nn, err := rw.WriteBlobAt("a", "b", 0, bytes.NewReader(newBlob)); err != nil { 278 t.Fatal(err) 279 } else if expected := int64(len(newBlob)); expected != nn { 280 t.Fatalf("wrong written bytes count: %v, expected: %v", nn, expected) 281 } 282 if out, err := rw.bs.GetBlob("a", "b"); err != nil { 283 t.Fatal(err) 284 } else { 285 assertBlobContents(t, out, newBlob) 286 } 287 if bx, err := rw.bs.GetBlockList("a", "b", azure.BlockListTypeCommitted); err != nil { 288 t.Fatal(err) 289 } else if expected := 10; len(bx.CommittedBlocks) != expected { 290 t.Fatalf("got wrong number of committed blocks: %v, expected: %v\n%v", len(bx.CommittedBlocks), expected, bx.CommittedBlocks) 291 } else if expected, size := int64(1024*30), getBlobSize(bx); size != expected { 292 t.Fatalf("committed block size does not indicate blob size") 293 } 294 } 295 296 func Test_getBlobSize(t *testing.T) { 297 // with some committed blocks 298 if expected, size := int64(151), getBlobSize(azure.BlockListResponse{ 299 CommittedBlocks: []azure.BlockResponse{ 300 {"A", 100}, 301 {"B", 50}, 302 {"C", 1}, 303 }, 304 UncommittedBlocks: []azure.BlockResponse{ 305 {"D", 200}, 306 }}); expected != size { 307 t.Fatalf("wrong blob size: %v, expected: %v", size, expected) 308 } 309 310 // with no committed blocks 311 if expected, size := int64(0), getBlobSize(azure.BlockListResponse{ 312 UncommittedBlocks: []azure.BlockResponse{ 313 {"A", 100}, 314 {"B", 50}, 315 {"C", 1}, 316 {"D", 200}, 317 }}); expected != size { 318 t.Fatalf("wrong blob size: %v, expected: %v", size, expected) 319 } 320 } 321 322 func assertBlobContents(t *testing.T, r io.Reader, expected []byte) { 323 out, err := ioutil.ReadAll(r) 324 if err != nil { 325 t.Fatal(err) 326 } 327 328 if !reflect.DeepEqual(out, expected) { 329 t.Fatalf("wrong blob contents. size: %v, expected: %v", len(out), len(expected)) 330 } 331 } 332 333 func randomContents(length int64) []byte { 334 b := make([]byte, length) 335 for i := range b { 336 b[i] = byte(rand.Intn(2 << 8)) 337 } 338 return b 339 }