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  }