OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. |
| 4 |
| 5 package ar |
| 6 |
| 7 import ( |
| 8 "bytes" |
| 9 "io/ioutil" |
| 10 "os" |
| 11 "os/exec" |
| 12 "path" |
| 13 "strings" |
| 14 "testing" |
| 15 "time" |
| 16 |
| 17 "github.com/maruel/ut" |
| 18 ) |
| 19 |
| 20 var ( |
| 21 TestFile1 = ("" + |
| 22 // ar file header |
| 23 "!<arch>\n" + |
| 24 // filename len - 16 bytes |
| 25 "#1/9 " + |
| 26 // modtime - 12 bytes |
| 27 "1447140471 " + |
| 28 // owner id - 6 bytes |
| 29 "1000 " + |
| 30 // group id - 6 bytes |
| 31 "1000 " + |
| 32 // file mode - 8 bytes |
| 33 "100640 " + |
| 34 // Data size - 10 bytes |
| 35 "15 " + |
| 36 // File magic - 2 bytes |
| 37 "\x60\n" + |
| 38 // File name - 9 bytes |
| 39 "filename1" + |
| 40 // File data - 6 bytes |
| 41 "abc123" + |
| 42 // Padding - 1 byte |
| 43 "\n" + |
| 44 "") |
| 45 |
| 46 TestFile2 = ("" + |
| 47 // ar file header |
| 48 "!<arch>\n" + |
| 49 |
| 50 // File 1 |
| 51 // ---------------------- |
| 52 // filename len - 16 bytes |
| 53 "#1/5 " + |
| 54 // modtime - 12 bytes |
| 55 "1447140471 " + |
| 56 // owner id - 6 bytes |
| 57 "1000 " + |
| 58 // group id - 6 bytes |
| 59 "1000 " + |
| 60 // file mode - 8 bytes |
| 61 "100640 " + |
| 62 // Data size - 10 bytes |
| 63 "13 " + |
| 64 // File magic - 2 bytes |
| 65 "\x60\n" + |
| 66 // File name - 9 bytes |
| 67 "file1" + |
| 68 // File data - 6 bytes |
| 69 "contents" + |
| 70 // Padding - 1 byte |
| 71 "\n" + |
| 72 |
| 73 // File 2 |
| 74 // ---------------------- |
| 75 // filename len - 16 bytes |
| 76 "#1/7 " + |
| 77 // modtime - 12 bytes |
| 78 "1447140471 " + |
| 79 // owner id - 6 bytes |
| 80 "1000 " + |
| 81 // group id - 6 bytes |
| 82 "1000 " + |
| 83 // file mode - 8 bytes |
| 84 "100640 " + |
| 85 // Data size - 10 bytes |
| 86 "10 " + |
| 87 // File magic - 2 bytes |
| 88 "\x60\n" + |
| 89 // File name - 9 bytes |
| 90 "fileabc" + |
| 91 // File data - 6 bytes |
| 92 "123" + |
| 93 // No padding - 0 byte |
| 94 |
| 95 // File 3 |
| 96 // ---------------------- |
| 97 // filename len - 16 bytes |
| 98 "#1/10 " + |
| 99 // modtime - 12 bytes |
| 100 "1447140471 " + |
| 101 // owner id - 6 bytes |
| 102 "1000 " + |
| 103 // group id - 6 bytes |
| 104 "1000 " + |
| 105 // file mode - 8 bytes |
| 106 "100640 " + |
| 107 // Data size - 10 bytes |
| 108 "16 " + |
| 109 // File magic - 2 bytes |
| 110 "\x60\n" + |
| 111 // File name - 9 bytes |
| 112 "dir1/file1" + |
| 113 // File data - 6 bytes |
| 114 "123abc" + |
| 115 // No padding - 0 byte |
| 116 "") |
| 117 ) |
| 118 |
| 119 func TestWriterCreatesTestFile1(t *testing.T) { |
| 120 b := &bytes.Buffer{} |
| 121 data := []byte("abc123") |
| 122 |
| 123 ar, err := NewWriter(b) |
| 124 if err != nil { |
| 125 t.Fatalf("NewWriter: %v", err) |
| 126 } |
| 127 if err := ar.AddWithContent("filename1", data); err != nil { |
| 128 t.Fatalf("AddWithContent: %v", err) |
| 129 } |
| 130 if err := ar.Close(); err != nil { |
| 131 t.Fatalf("Close: %v", err) |
| 132 } |
| 133 |
| 134 ut.AssertEqual(t, []byte(TestFile1), b.Bytes()) |
| 135 } |
| 136 |
| 137 func TestReaderOnTestFile1(t *testing.T) { |
| 138 r := strings.NewReader(TestFile1) |
| 139 |
| 140 ar, err := NewReader(r) |
| 141 if err != nil { |
| 142 t.Fatalf("NewReader: %v", err) |
| 143 } |
| 144 |
| 145 h, herr := ar.Next() |
| 146 if herr != nil { |
| 147 t.Fatalf("Header: %v", herr) |
| 148 } |
| 149 |
| 150 ut.AssertEqual(t, time.Unix(1447140471, 0), h.ModTime()) |
| 151 ut.AssertEqual(t, 1000, h.UserID()) |
| 152 ut.AssertEqual(t, 1000, h.GroupID()) |
| 153 ut.AssertEqual(t, "filename1", h.Name()) |
| 154 ut.AssertEqual(t, int64(6), h.Size()) |
| 155 |
| 156 data1 := make([]byte, 3) |
| 157 data2 := make([]byte, 4) |
| 158 n1, berr := ar.Body().Read(data1) |
| 159 if berr != nil { |
| 160 t.Fatalf("Data: %v", berr) |
| 161 } |
| 162 ut.AssertEqual(t, 3, n1) |
| 163 n2, berr := ar.Body().Read(data2) |
| 164 if berr != nil { |
| 165 t.Fatalf("Data: %v", berr) |
| 166 } |
| 167 ut.AssertEqual(t, 3, n2) |
| 168 |
| 169 ut.AssertEqual(t, []byte("abc"), data1) |
| 170 ut.AssertEqual(t, []byte{'1', '2', '3', 0}, data2) |
| 171 |
| 172 if err := ar.Close(); err != nil { |
| 173 t.Fatalf("Close: %v", err) |
| 174 } |
| 175 } |
| 176 |
| 177 func TestReaderOnTestFile2(t *testing.T) { |
| 178 r := strings.NewReader(TestFile2) |
| 179 |
| 180 ar, err := NewReader(r) |
| 181 if err != nil { |
| 182 t.Fatalf("NewReader: %v", err) |
| 183 } |
| 184 |
| 185 h1, herr := ar.Next() |
| 186 if herr != nil { |
| 187 t.Fatalf("Header: %v", herr) |
| 188 } |
| 189 ut.AssertEqual(t, time.Unix(1447140471, 0), h1.ModTime()) |
| 190 ut.AssertEqual(t, 1000, h1.UserID()) |
| 191 ut.AssertEqual(t, 1000, h1.GroupID()) |
| 192 ut.AssertEqual(t, "file1", h1.Name()) |
| 193 ut.AssertEqual(t, int64(8), h1.Size()) |
| 194 |
| 195 // Skipping the body of file 1 |
| 196 |
| 197 h2, herr := ar.Next() |
| 198 if herr != nil { |
| 199 t.Fatalf("Header: %v", herr) |
| 200 } |
| 201 ut.AssertEqual(t, time.Unix(1447140471, 0), h2.ModTime()) |
| 202 ut.AssertEqual(t, 1000, h2.UserID()) |
| 203 ut.AssertEqual(t, 1000, h2.GroupID()) |
| 204 ut.AssertEqual(t, "fileabc", h2.Name()) |
| 205 ut.AssertEqual(t, int64(3), h2.Size()) |
| 206 |
| 207 // Read only some of the body |
| 208 data := make([]byte, 2) |
| 209 n, berr := ar.Body().Read(data) |
| 210 if berr != nil { |
| 211 t.Fatalf("Data: %v", berr) |
| 212 } |
| 213 ut.AssertEqual(t, 2, n) |
| 214 ut.AssertEqual(t, []byte("12"), data) |
| 215 |
| 216 h3, herr := ar.Next() |
| 217 if herr != nil { |
| 218 t.Fatalf("Header: %v", herr) |
| 219 } |
| 220 ut.AssertEqual(t, time.Unix(1447140471, 0), h3.ModTime()) |
| 221 ut.AssertEqual(t, 1000, h3.UserID()) |
| 222 ut.AssertEqual(t, 1000, h3.GroupID()) |
| 223 ut.AssertEqual(t, "dir1/file1", h3.Name()) |
| 224 ut.AssertEqual(t, int64(6), h3.Size()) |
| 225 |
| 226 // Read the full file |
| 227 data = make([]byte, 6) |
| 228 n, berr = ar.Body().Read(data) |
| 229 if berr != nil { |
| 230 t.Fatalf("Data: %v", berr) |
| 231 } |
| 232 ut.AssertEqual(t, 6, n) |
| 233 ut.AssertEqual(t, []byte("123abc"), data) |
| 234 |
| 235 if err := ar.Close(); err != nil { |
| 236 t.Fatalf("Close: %v", err) |
| 237 } |
| 238 } |
| 239 |
| 240 func TestWithSystemArCommandList(t *testing.T) { |
| 241 if _, err := exec.LookPath("ar"); err != nil { |
| 242 t.Skipf("ar command not found: %v", err) |
| 243 } |
| 244 |
| 245 // Write out to an archive file |
| 246 tmpfile, err := ioutil.TempFile("", "go-ar-test.") |
| 247 if err != nil { |
| 248 t.Fatalf("unable to create temp file: %v", err) |
| 249 } |
| 250 defer os.Remove(tmpfile.Name()) // clean up |
| 251 ar, err := NewWriter(tmpfile) |
| 252 if err != nil { |
| 253 t.Fatalf("NewWriter: %v", err) |
| 254 } |
| 255 ar.AddWithContent("file1.txt", []byte("file1 contents")) |
| 256 ar.AddWithContent("file2.txt", []byte("file2 contents")) |
| 257 ar.AddWithContent("dir1/file3.txt", []byte("file3 contents")) |
| 258 ar.Close() |
| 259 |
| 260 // Use the ar command to list the file |
| 261 cmdList := exec.Command("ar", "t", tmpfile.Name()) |
| 262 var cmdListOutBuf bytes.Buffer |
| 263 cmdList.Stdout = &cmdListOutBuf |
| 264 if err := cmdList.Run(); err != nil { |
| 265 t.Fatalf("ar command failed: %v\n%s", err, cmdListOutBuf.String(
)) |
| 266 } |
| 267 |
| 268 cmdListActualOut := cmdListOutBuf.String() |
| 269 cmdListExpectOut := `file1.txt |
| 270 file2.txt |
| 271 dir1/file3.txt |
| 272 ` |
| 273 ut.AssertEqual(t, cmdListExpectOut, cmdListActualOut) |
| 274 } |
| 275 |
| 276 func TestWithSystemArCommandExtract(t *testing.T) { |
| 277 arpath, err := exec.LookPath("ar") |
| 278 if err != nil { |
| 279 t.Skipf("ar command not found: %v", err) |
| 280 } |
| 281 |
| 282 // Write out to an archive file |
| 283 tmpfile, err := ioutil.TempFile("", "go-ar-test.") |
| 284 if err != nil { |
| 285 t.Fatalf("unable to create temp file: %v", err) |
| 286 } |
| 287 defer os.Remove(tmpfile.Name()) // clean up |
| 288 ar, err := NewWriter(tmpfile) |
| 289 if err != nil { |
| 290 t.Fatalf("NewWriter: %v", err) |
| 291 } |
| 292 ar.AddWithContent("file1.txt", []byte("file1 contents")) |
| 293 ar.AddWithContent("file2.txt", []byte("file2 contents")) |
| 294 ar.Close() |
| 295 |
| 296 // Extract the ar |
| 297 tmpdir, err := ioutil.TempDir("", "go-ar-test.") |
| 298 defer os.RemoveAll(tmpdir) |
| 299 cmdExtract := exec.Cmd{ |
| 300 Path: arpath, |
| 301 Args: []string{"ar", "x", tmpfile.Name()}, |
| 302 Dir: tmpdir, |
| 303 } |
| 304 var cmdExtractOutBuf bytes.Buffer |
| 305 cmdExtract.Stdout = &cmdExtractOutBuf |
| 306 if err := cmdExtract.Run(); err != nil { |
| 307 t.Fatalf("ar command failed: %v\n%s", err, cmdExtractOutBuf.Stri
ng()) |
| 308 } |
| 309 |
| 310 // Compare the directory output |
| 311 dirContents, err := ioutil.ReadDir(tmpdir) |
| 312 if err != nil { |
| 313 t.Fatalf("Unable to read the output directory: %v", err) |
| 314 } |
| 315 for _, fi := range dirContents { |
| 316 if fi.Name() != "file1.txt" && fi.Name() != "file2.txt" { |
| 317 t.Errorf("Found unexpected file '%s'", fi.Name()) |
| 318 } |
| 319 } |
| 320 |
| 321 file1Contents, err := ioutil.ReadFile(path.Join(tmpdir, "file1.txt")) |
| 322 file1Expected := []byte("file1 contents") |
| 323 if err != nil { |
| 324 t.Errorf("%v", err) |
| 325 } else { |
| 326 if bytes.Compare(file1Contents, file1Expected) != 0 { |
| 327 t.Errorf("file1.txt content incorrect. Got:\n%v\n%v\n",
file1Contents, file1Expected) |
| 328 } |
| 329 } |
| 330 |
| 331 file2Contents, err := ioutil.ReadFile(path.Join(tmpdir, "file2.txt")) |
| 332 file2Expected := []byte("file2 contents") |
| 333 if err != nil { |
| 334 t.Errorf("%v", err) |
| 335 } else { |
| 336 if bytes.Compare(file2Contents, file2Expected) != 0 { |
| 337 t.Errorf("file2.txt content incorrect. Got:\n%v\n%v\n",
file2Contents, file2Expected) |
| 338 } |
| 339 } |
| 340 } |
OLD | NEW |