github.com/coreos/mantle@v0.13.0/update/generator/full_test.go (about) 1 // Copyright 2016 CoreOS, Inc. 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 generator 16 17 import ( 18 "bytes" 19 "io" 20 "io/ioutil" 21 "os" 22 "testing" 23 24 "github.com/coreos/mantle/system" 25 "github.com/coreos/mantle/system/exec" 26 "github.com/coreos/mantle/update/metadata" 27 ) 28 29 func TestFullUpdateScanEmpty(t *testing.T) { 30 scanner := fullScanner{ 31 payload: &bytes.Buffer{}, 32 source: bytes.NewReader([]byte{}), 33 } 34 35 if err := scanner.Scan(); err != io.EOF { 36 t.Errorf("expected io.EOF, got %v", err) 37 } 38 39 if scanner.offset != 0 { 40 t.Errorf("read %d bytes from nowhere", scanner.offset) 41 } 42 43 if len(scanner.operations) != 0 { 44 t.Errorf("operations not empty: %v", scanner.operations) 45 } 46 } 47 48 func checkReplace(t *testing.T, ops []*metadata.InstallOperation, source, sourceHash, payload []byte) { 49 if len(ops) != 1 { 50 t.Fatalf("unexpected operations: %v", ops) 51 } 52 53 op := ops[0] 54 if op.GetType() != metadata.InstallOperation_REPLACE { 55 t.Errorf("unexpected operation type: %s", op.GetType()) 56 } 57 58 if len(op.DstExtents) != 1 { 59 t.Fatalf("unexpected extents: %v", op.GetDstExtents()) 60 } 61 62 ext := op.DstExtents[0] 63 if ext.GetStartBlock() != 0 || ext.GetNumBlocks() != 1 { 64 t.Fatalf("unexpected extent: %v", ext) 65 } 66 67 if op.GetDataLength() != BlockSize { 68 t.Errorf("unexpected payload size %d", op.GetDataLength()) 69 } 70 71 if !bytes.Equal(op.DataSha256Hash, sourceHash) { 72 t.Error("unexpected payload hash") 73 } 74 75 if !bytes.Equal(payload, source) { 76 t.Errorf("source not coppied to payload") 77 } 78 } 79 80 func checkReplaceBZ(t *testing.T, ops []*metadata.InstallOperation, source, sourceHash, payload []byte) { 81 if len(ops) != 1 { 82 t.Fatalf("unexpected operations: %v", ops) 83 } 84 85 op := ops[0] 86 if op.GetType() != metadata.InstallOperation_REPLACE_BZ { 87 t.Errorf("unexpected operation type: %s", op.GetType()) 88 } 89 90 if len(op.DstExtents) != 1 { 91 t.Fatalf("unexpected extents: %v", op.GetDstExtents()) 92 } 93 94 ext := op.DstExtents[0] 95 if ext.GetStartBlock() != 0 || ext.GetNumBlocks() != 1 { 96 t.Fatalf("unexpected extent: %v", ext) 97 } 98 99 if op.GetDataLength() == 0 && op.GetDataLength() >= BlockSize { 100 t.Errorf("unexpected payload size %d", op.GetDataLength()) 101 } 102 103 if !bytes.Equal(bunzip2(t, payload), source) { 104 t.Errorf("source not properly compressed in payload") 105 } 106 } 107 108 func checkFullScan(t *testing.T, source []byte) ([]*metadata.InstallOperation, []byte) { 109 var payload bytes.Buffer 110 scanner := fullScanner{ 111 payload: &payload, 112 source: bytes.NewReader(source), 113 } 114 115 if err := scanner.Scan(); err != nil { 116 if exec.IsCmdNotFound(err) { 117 t.Skip(err) 118 } 119 120 t.Fatalf("unexpected error %v", err) 121 } 122 123 if err := scanner.Scan(); err != io.EOF { 124 t.Errorf("expected io.EOF, got %v", err) 125 } 126 127 if scanner.offset != BlockSize { 128 t.Errorf("expected %d bytes, got %d", BlockSize, scanner.offset) 129 } 130 131 return scanner.operations, payload.Bytes() 132 } 133 134 func TestFullUpdateScanOnes(t *testing.T) { 135 ops, payload := checkFullScan(t, testOnes) 136 137 checkReplaceBZ(t, ops, testOnes, testOnesHash, payload) 138 } 139 140 func TestFullUpdateScanRand(t *testing.T) { 141 ops, payload := checkFullScan(t, testRand) 142 143 checkReplace(t, ops, testRand, testRandHash, payload) 144 } 145 146 func TestFullUpdateScanUnaligned(t *testing.T) { 147 scanner := fullScanner{ 148 payload: &bytes.Buffer{}, 149 source: bytes.NewReader(testUnaligned), 150 } 151 152 if err := scanner.Scan(); err != errShortRead { 153 t.Fatalf("expected errShortRead, got %v", err) 154 } 155 } 156 157 func checkFullProc(t *testing.T, source, sourceHash []byte) *Procedure { 158 f, err := ioutil.TempFile("", "") 159 if err != nil { 160 t.Fatal(err) 161 } 162 defer f.Close() 163 defer os.Remove(f.Name()) 164 165 if _, err := f.Write(source); err != nil { 166 t.Fatal(err) 167 } 168 169 proc, err := FullUpdate(f.Name()) 170 if system.IsOpNotSupported(err) { 171 t.Skip("O_TMPFILE not supported") 172 } else if exec.IsCmdNotFound(err) { 173 t.Skip(err) 174 } else if err != nil { 175 t.Fatal(err) 176 } 177 178 if proc.NewInfo.GetSize() != BlockSize { 179 t.Errorf("expected %d bytes, got %d", BlockSize, proc.NewInfo.GetSize()) 180 } 181 182 if !bytes.Equal(proc.NewInfo.Hash, sourceHash) { 183 t.Error("unexpected source hash") 184 } 185 186 return proc 187 } 188 189 func TestFullUpdateOnes(t *testing.T) { 190 proc := checkFullProc(t, testOnes, testOnesHash) 191 defer proc.Close() 192 193 payload, err := ioutil.ReadAll(proc) 194 if err != nil { 195 t.Fatal(err) 196 } 197 198 checkReplaceBZ(t, proc.Operations, testOnes, testOnesHash, payload) 199 } 200 201 func TestFullUpdateRand(t *testing.T) { 202 proc := checkFullProc(t, testRand, testRandHash) 203 defer proc.Close() 204 205 payload, err := ioutil.ReadAll(proc) 206 if err != nil { 207 t.Fatal(err) 208 } 209 210 checkReplace(t, proc.Operations, testRand, testRandHash, payload) 211 }