kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/util/riegeli/block_test.go (about)

     1  /*
     2   * Copyright 2018 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package riegeli
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/hex"
    22  	"io"
    23  	"io/ioutil"
    24  	"testing"
    25  )
    26  
    27  func TestBlockWriter_fullBlock(t *testing.T) {
    28  	var buf bytes.Buffer
    29  	w := &blockWriter{w: &buf}
    30  
    31  	// Write a full block
    32  	chunk := bytes.Repeat([]byte{0}, usableBlockSize)
    33  	n, err := w.WriteChunk(chunk)
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	} else if expected := blockSize; n != expected {
    37  		t.Fatalf("Unexpected write size: found: %d; expected: %d", n, expected)
    38  	} else if buf.Len() != expected {
    39  		t.Fatalf("Unexpected output size: found: %d; expected: %d", buf.Len(), expected)
    40  	}
    41  
    42  	r := bytes.NewReader(buf.Bytes())
    43  	h, err := decodeBlockHeader(r)
    44  	if err != nil {
    45  		t.Fatalf("Error decoding block header: %v", err)
    46  	} else if expected := 0; h.PreviousChunk != uint64(expected) {
    47  		t.Fatalf("Unexpected PreviousChunk offset: found: %d; expected: %d", h.PreviousChunk, expected)
    48  	} else if expected := blockSize; h.NextChunk != uint64(expected) {
    49  		t.Fatalf("Unexpected NextChunk offset: found: %d; expected: %d", h.NextChunk, expected)
    50  	}
    51  
    52  	rest, err := ioutil.ReadAll(r)
    53  	if err != nil {
    54  		t.Fatalf("Error reading chunk: %v", err)
    55  	} else if !bytes.Equal(rest, chunk) {
    56  		t.Fatalf("Unexpected chunk bytes: found: %d; expected: %d", rest, chunk)
    57  	}
    58  }
    59  
    60  func TestBlockWriter_crossBlock(t *testing.T) {
    61  	var buf bytes.Buffer
    62  	w := &blockWriter{w: &buf}
    63  
    64  	// Write almost a full block
    65  	chunk := bytes.Repeat([]byte{0}, usableBlockSize-10)
    66  	n, err := w.WriteChunk(chunk)
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	} else if expected := blockHeaderSize + len(chunk); n != expected {
    70  		t.Fatalf("Unexpected write size: found: %d; expected: %d", n, expected)
    71  	} else if buf.Len() != expected {
    72  		t.Fatalf("Unexpected output size: found: %d; expected: %d", buf.Len(), expected)
    73  	}
    74  
    75  	// Write another chunk that crosses a block header boundary
    76  	n, err = w.WriteChunk(chunk)
    77  	if err != nil {
    78  		t.Fatal(err)
    79  	} else if expected := blockHeaderSize + len(chunk); n != expected {
    80  		t.Fatalf("Unexpected write size: found: %d; expected: %d", n, expected)
    81  	} else if buf.Len() != expected*2 {
    82  		t.Fatalf("Unexpected output size: found: %d; expected: %d", buf.Len(), expected*2)
    83  	}
    84  
    85  	r := bytes.NewReader(buf.Bytes())
    86  	// Decode first block header
    87  	h, err := decodeBlockHeader(r)
    88  	if err != nil {
    89  		t.Fatalf("Error decoding block header: %v", err)
    90  	} else if expected := 0; h.PreviousChunk != uint64(expected) {
    91  		t.Fatalf("Unexpected PreviousChunk offset: found: %d; expected: %d", h.PreviousChunk, expected)
    92  	} else if expected := blockHeaderSize + len(chunk); h.NextChunk != uint64(expected) {
    93  		t.Fatalf("Unexpected NextChunk offset: found: %d; expected: %d", h.NextChunk, expected)
    94  	}
    95  
    96  	// Read first chunk
    97  	chunkRead := make([]byte, len(chunk))
    98  	if _, err := io.ReadFull(r, chunkRead); err != nil {
    99  		t.Fatalf("Error reading chunk: %v", err)
   100  	} else if !bytes.Equal(chunkRead, chunk) {
   101  		t.Fatalf("Unexpected chunk bytes: found: %d; expected: %d", chunkRead, chunk)
   102  	}
   103  
   104  	// Read part of second chunk
   105  	if _, err := io.ReadFull(r, chunkRead[:10]); err != nil {
   106  		t.Fatalf("Error reading chunk: %v", err)
   107  	}
   108  
   109  	// Decode second block header
   110  	h, err = decodeBlockHeader(r)
   111  	if err != nil {
   112  		t.Fatalf("Error decoding block header: %v", err)
   113  	} else if expected := 10; h.PreviousChunk != uint64(expected) {
   114  		t.Fatalf("Unexpected PreviousChunk offset: found: %d; expected: %d", h.PreviousChunk, expected)
   115  	} else if expected := blockHeaderSize + len(chunk) - 10; h.NextChunk != uint64(expected) {
   116  		t.Fatalf("Unexpected NextChunk offset: found: %d; expected: %d", h.NextChunk, expected)
   117  	}
   118  
   119  	// Read rest of second chunk
   120  	if _, err := io.ReadFull(r, chunkRead[10:]); err != nil {
   121  		t.Fatalf("Error reading chunk: %v", err)
   122  	} else if !bytes.Equal(chunkRead, chunk) {
   123  		t.Fatalf("Unexpected chunk bytes: found: %d; expected: %d", chunkRead, chunk)
   124  	}
   125  }
   126  
   127  func TestBlockWriter_singleChunk(t *testing.T) {
   128  	var buf bytes.Buffer
   129  	w := &blockWriter{w: &buf}
   130  
   131  	// Write a small chunk
   132  	chunk := bytes.Repeat([]byte{0}, 1024)
   133  	n, err := w.WriteChunk(chunk)
   134  	if err != nil {
   135  		t.Fatal(err)
   136  	} else if expected := blockHeaderSize + len(chunk); n != expected {
   137  		t.Fatalf("Unexpected write size: found: %d; expected: %d", n, expected)
   138  	} else if buf.Len() != expected {
   139  		t.Fatalf("Unexpected output size: found: %d; expected: %d", buf.Len(), expected)
   140  	}
   141  
   142  	r := bytes.NewReader(buf.Bytes())
   143  	h, err := decodeBlockHeader(r)
   144  	if err != nil {
   145  		t.Fatalf("Error decoding block header: %v", err)
   146  	} else if expected := 0; h.PreviousChunk != uint64(expected) {
   147  		t.Fatalf("Unexpected PreviousChunk offset: found: %d; expected: %d", h.PreviousChunk, expected)
   148  	} else if expected := blockHeaderSize + len(chunk); h.NextChunk != uint64(expected) {
   149  		t.Fatalf("Unexpected NextChunk offset: found: %d; expected: %d", h.NextChunk, expected)
   150  	}
   151  
   152  	rest, err := ioutil.ReadAll(r)
   153  	if err != nil {
   154  		t.Fatalf("Error reading chunk: %v", err)
   155  	} else if !bytes.Equal(rest, chunk) {
   156  		t.Fatalf("Unexpected chunk bytes: found: %d; expected: %d", rest, chunk)
   157  	}
   158  }
   159  
   160  func TestBlockWriter_multipleChunks(t *testing.T) {
   161  	var buf bytes.Buffer
   162  	w := &blockWriter{w: &buf}
   163  
   164  	// Write multiple chunks
   165  	chunk := bytes.Repeat([]byte{0}, 1024)
   166  	numChunks := usableBlockSize / len(chunk)
   167  	n, err := w.WriteChunk(chunk)
   168  	if err != nil {
   169  		t.Fatal(err)
   170  	} else if expected := blockHeaderSize + len(chunk); n != expected {
   171  		t.Fatalf("Unexpected write size: found: %d; expected: %d", n, expected)
   172  	} else if buf.Len() != expected {
   173  		t.Fatalf("Unexpected output size: found: %d; expected: %d", buf.Len(), expected)
   174  	}
   175  	for i := 1; i < numChunks; i++ {
   176  		n, err := w.WriteChunk(chunk)
   177  		if err != nil {
   178  			t.Fatal(err)
   179  		} else if expected := len(chunk); n != expected { // doesn't include blockHeaderSize overhead
   180  			t.Fatalf("Unexpected write size: found: %d; expected: %d", n, expected)
   181  		}
   182  	}
   183  
   184  	r := bytes.NewReader(buf.Bytes())
   185  	h, err := decodeBlockHeader(r)
   186  	if err != nil {
   187  		t.Fatalf("Error decoding block header: %v", err)
   188  	} else if expected := 0; h.PreviousChunk != uint64(expected) {
   189  		t.Fatalf("Unexpected PreviousChunk offset: found: %d; expected: %d", h.PreviousChunk, expected)
   190  	} else if expected := blockHeaderSize + len(chunk); h.NextChunk != uint64(expected) {
   191  		t.Fatalf("Unexpected NextChunk offset: found: %d; expected: %d", h.NextChunk, expected)
   192  	}
   193  }
   194  
   195  func TestBlockReader_sequential(t *testing.T) {
   196  	var buf bytes.Buffer
   197  	w := &blockWriter{w: &buf}
   198  
   199  	// Write multiple chunks across multiple blocks
   200  	const numChunks = 255
   201  	const chunkSize = usableBlockSize / 10
   202  	for i := 0; i < numChunks; i++ {
   203  		chunk := bytes.Repeat([]byte{byte(i)}, chunkSize)
   204  		if _, err := w.WriteChunk(chunk); err != nil {
   205  			t.Fatal(err)
   206  		}
   207  	}
   208  
   209  	r := &blockReader{r: bytes.NewReader(buf.Bytes())}
   210  	for i := 0; i < numChunks; i++ {
   211  		expected := bytes.Repeat([]byte{byte(i)}, chunkSize)
   212  		found := make([]byte, chunkSize)
   213  		if _, err := io.ReadFull(r, found); err != nil {
   214  			t.Fatal(err)
   215  		} else if !bytes.Equal(expected, found) {
   216  			t.Fatalf("Unexpected chunk bytes: found: %d; expected: %d", found, expected)
   217  		}
   218  	}
   219  
   220  	found := make([]byte, chunkSize)
   221  	if n, err := r.Read(found); err != io.EOF {
   222  		t.Fatalf("Unexpected read of %d bytes past end (err=%v): %s", n, err, hex.EncodeToString(found))
   223  	}
   224  }