github.com/letsencrypt/trillian@v1.1.2-0.20180615153820-ae375a99d36a/storage/suffix_test.go (about)

     1  // Copyright 2017 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package storage
    16  
    17  import (
    18  	"bytes"
    19  	"encoding/base64"
    20  	"fmt"
    21  	"math/big"
    22  	"testing"
    23  )
    24  
    25  const (
    26  	logStrataDepth = 8
    27  	maxLogDepth    = 64
    28  	// TODO(gdbelvin): remove these constants in favor of the real ones in
    29  	// storage/cache when merkle no longer depends on storage.NodeID
    30  )
    31  
    32  //h2b6 takes a hex string and emits a base64 string
    33  func h2b6(h string) string {
    34  	return base64.StdEncoding.EncodeToString(h2b(h))
    35  }
    36  
    37  func TestParseSuffix(t *testing.T) {
    38  	for _, tc := range []struct {
    39  		suffix   string
    40  		wantBits byte
    41  		wantPath []byte
    42  		wantErr  bool
    43  	}{
    44  		{h2b6("0100"), 1, h2b("00"), false},
    45  		{h2b6("0801"), 8, h2b("01"), false},
    46  		{"----", 1, h2b("00"), true},
    47  	} {
    48  		sfx, err := ParseSuffix(tc.suffix)
    49  		if got, want := err != nil, tc.wantErr; got != want {
    50  			t.Errorf("ParseSuffix(%s): %v, wantErr: %v", tc.suffix, err, want)
    51  			continue
    52  		}
    53  		if err != nil {
    54  			continue
    55  		}
    56  		if got, want := sfx.Bits, tc.wantBits; got != want {
    57  			t.Errorf("ParseSuffix(%s).Bits: %v, want %v", tc.suffix, got, want)
    58  		}
    59  		if got, want := sfx.Path, tc.wantPath; !bytes.Equal(got, want) {
    60  			t.Errorf("ParseSuffix(%s).Path: %x, want %x", tc.suffix, got, want)
    61  		}
    62  	}
    63  }
    64  
    65  func TestSplitParseSuffixRoundtrip(t *testing.T) {
    66  	for _, tc := range []struct {
    67  		prefix    []byte
    68  		leafIndex int64
    69  		want      []byte
    70  	}{
    71  		{h2b(""), 1, h2b("0801")},
    72  		{h2b("00"), 1, h2b("0801")},
    73  	} {
    74  		nodeID := NewNodeIDFromPrefix(tc.prefix, logStrataDepth, tc.leafIndex, logStrataDepth, maxLogDepth)
    75  		_, sfx := nodeID.Split(len(tc.prefix), logStrataDepth)
    76  		sfxKey := sfx.String()
    77  
    78  		sfxP, err := ParseSuffix(sfxKey)
    79  		if err != nil {
    80  			t.Errorf("ParseSuffix(%s): %v", sfxKey, err)
    81  			continue
    82  		}
    83  		if got, want := sfx.Bits, sfxP.Bits; got != want {
    84  			t.Errorf("ParseSuffix(%s).Bits: %v, want %v", sfxKey, got, want)
    85  		}
    86  		if got, want := sfx.Path, sfxP.Path; !bytes.Equal(got, want) {
    87  			t.Errorf("ParseSuffix(%s).Path: %x, want %x", sfxKey, got, want)
    88  		}
    89  	}
    90  }
    91  
    92  // TestSuffixKeyEquals ensures that NodeID.Split produces the same output as makeSuffixKey for the Log's use cases.
    93  func TestSuffixKeyEquals(t *testing.T) {
    94  	for _, tc := range []struct {
    95  		prefix    []byte
    96  		leafIndex int64
    97  		want      []byte
    98  	}{
    99  		{h2b(""), 1, h2b("0801")},
   100  		{h2b("00"), 1, h2b("0801")},
   101  	} {
   102  		sfxA, err := makeSuffixKey(logStrataDepth, tc.leafIndex)
   103  		if err != nil {
   104  			t.Errorf("makeSuffixKey(%v, %v): %v", logStrataDepth, tc.leafIndex, err)
   105  			continue
   106  		}
   107  
   108  		sfxABytes, err := base64.StdEncoding.DecodeString(sfxA)
   109  		if err != nil {
   110  			t.Errorf("makeSuffixKey(%v, %v): %v", logStrataDepth, tc.leafIndex, err)
   111  			continue
   112  		}
   113  
   114  		if got, want := sfxABytes, tc.want; !bytes.Equal(got, want) {
   115  			t.Errorf("makeSuffixKey(%v, %v): %x, want %x", logStrataDepth, tc.leafIndex, got, want)
   116  			continue
   117  		}
   118  
   119  		nodeID := NewNodeIDFromPrefix(tc.prefix, logStrataDepth, tc.leafIndex, logStrataDepth, maxLogDepth)
   120  		_, sfxB := nodeID.Split(len(tc.prefix), logStrataDepth)
   121  		sfxBKey := sfxB.String()
   122  		sfxBBytes, err := base64.StdEncoding.DecodeString(sfxBKey)
   123  		if err != nil {
   124  			t.Errorf("splitNodeID(%v): _, %v", nodeID, err)
   125  			continue
   126  		}
   127  
   128  		if got, want := sfxBBytes, tc.want; !bytes.Equal(got, want) {
   129  			t.Errorf("[%x, %v].splitNodeID(%v, %v): %v.Serialize(): %x, want %x", nodeID.Path, nodeID.PrefixLenBits, len(tc.prefix), logStrataDepth, sfxB, got, want)
   130  			continue
   131  		}
   132  	}
   133  }
   134  
   135  // TestSuffixKey documents the behavior of makeSuffixKey
   136  func TestSuffixKey(t *testing.T) {
   137  	for _, tc := range []struct {
   138  		depth   int
   139  		index   int64
   140  		want    []byte
   141  		wantErr bool
   142  	}{
   143  		{depth: 0, index: 0x00, want: h2b("0000"), wantErr: false},
   144  		{depth: 8, index: 0x00, want: h2b("0800"), wantErr: false},
   145  		{depth: 15, index: 0xab, want: h2b("0fab"), wantErr: false},
   146  
   147  		// Map cases which produce incorrect output from makeSuffixKey.
   148  		{depth: 16, index: 0x00, want: h2b("1000"), wantErr: false},
   149  		{depth: 8, index: 0xabcd, want: h2b("08cd"), wantErr: false},
   150  		{
   151  			depth:   2,
   152  			index:   new(big.Int).SetBytes(h2b("4000000000000000000000000000000000000000000000000000000000000000")).Int64(),
   153  			want:    h2b("0200"),
   154  			wantErr: false,
   155  		},
   156  	} {
   157  		suffixKey, err := makeSuffixKey(tc.depth, tc.index)
   158  		if got, want := err != nil, tc.wantErr; got != want {
   159  			t.Errorf("makeSuffixKey(%v, %v): %v, want err: %v",
   160  				tc.depth, tc.index, err, want)
   161  			continue
   162  		}
   163  		if err != nil {
   164  			continue
   165  		}
   166  		b, err := base64.StdEncoding.DecodeString(suffixKey)
   167  		if err != nil {
   168  			t.Errorf("DecodeString(%v): %v", suffixKey, err)
   169  			continue
   170  		}
   171  		if got, want := b, tc.want; !bytes.Equal(got, want) {
   172  			t.Errorf("makeSuffixKey(%v, %x): %x, want %x",
   173  				tc.depth, tc.index, got, want)
   174  		}
   175  	}
   176  }
   177  
   178  // makeSuffixKey creates a suffix key for indexing into the subtree's Leaves and InternalNodes maps.
   179  // This function documents existing log storage behavior. Any new code that emits Sufix objects must
   180  // produce the exact same outputs as this function would for Logs.
   181  func makeSuffixKey(depth int, index int64) (string, error) {
   182  	if depth < 0 {
   183  		return "", fmt.Errorf("invalid negative depth of %d", depth)
   184  	}
   185  	if index < 0 {
   186  		return "", fmt.Errorf("invalid negative index %d", index)
   187  	}
   188  	sfx := Suffix{byte(depth), []byte{byte(index)}}
   189  	return sfx.String(), nil
   190  }
   191  
   192  func TestSuffixSerialize(t *testing.T) {
   193  	for _, tc := range []struct {
   194  		s    Suffix
   195  		want string
   196  	}{
   197  		// Prexisting format. This test vector must NOT change or existing data will be inaccessible.
   198  		{s: Suffix{5, []byte{0xae}}, want: "Ba4="},
   199  	} {
   200  		if got, want := tc.s.String(), tc.want; got != want {
   201  			t.Errorf("%v.serialize(): %v, want %v", tc.s, got, want)
   202  		}
   203  	}
   204  }