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 }