Mirror of BoringSSL (grpc依赖)
https://boringssl.googlesource.com/boringssl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
4.9 KiB
198 lines
4.9 KiB
// Copyright (c) 2021, Google Inc. |
|
// |
|
// Permission to use, copy, modify, and/or distribute this software for any |
|
// purpose with or without fee is hereby granted, provided that the above |
|
// copyright notice and this permission notice appear in all copies. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
|
|
package main |
|
|
|
import ( |
|
"bytes" |
|
"compress/bzip2" |
|
"encoding/json" |
|
"flag" |
|
"fmt" |
|
"io" |
|
"io/ioutil" |
|
"log" |
|
"os" |
|
"os/exec" |
|
"runtime" |
|
"strings" |
|
"sync" |
|
"sync/atomic" |
|
) |
|
|
|
var ( |
|
toolPath *string = flag.String("tool", "", "Path to acvptool binary") |
|
moduleWrappers *string = flag.String("module-wrappers", "", "Comma-separated list of name:path pairs for known module wrappers") |
|
testsPath *string = flag.String("tests", "", "Path to JSON file listing tests") |
|
update *bool = flag.Bool("update", false, "If true then write updated outputs") |
|
) |
|
|
|
type invocation struct { |
|
toolPath string |
|
wrapperPath string |
|
inPath string |
|
expectedPath string |
|
} |
|
|
|
func main() { |
|
flag.Parse() |
|
|
|
if len(*toolPath) == 0 { |
|
log.Fatal("-tool must be given") |
|
} |
|
|
|
if len(*moduleWrappers) == 0 { |
|
log.Fatal("-module-wrappers must be given") |
|
} |
|
|
|
wrappers := make(map[string]string) |
|
pairs := strings.Split(*moduleWrappers, ",") |
|
for _, pair := range pairs { |
|
parts := strings.SplitN(pair, ":", 2) |
|
if _, ok := wrappers[parts[0]]; ok { |
|
log.Fatalf("wrapper %q defined twice", parts[0]) |
|
} |
|
wrappers[parts[0]] = parts[1] |
|
} |
|
|
|
if len(*testsPath) == 0 { |
|
log.Fatal("-tests must be given") |
|
} |
|
|
|
testsFile, err := os.Open(*testsPath) |
|
if err != nil { |
|
log.Fatal(err) |
|
} |
|
defer testsFile.Close() |
|
|
|
decoder := json.NewDecoder(testsFile) |
|
var tests []struct { |
|
Wrapper string |
|
In string |
|
Out string // Optional, may be empty. |
|
} |
|
if err := decoder.Decode(&tests); err != nil { |
|
log.Fatal(err) |
|
} |
|
|
|
work := make(chan invocation, runtime.NumCPU()) |
|
var numFailed uint32 |
|
|
|
var wg sync.WaitGroup |
|
for i := 0; i < runtime.NumCPU(); i++ { |
|
wg.Add(1) |
|
go worker(&wg, work, &numFailed) |
|
} |
|
|
|
for _, test := range tests { |
|
wrapper, ok := wrappers[test.Wrapper] |
|
if !ok { |
|
log.Fatalf("wrapper %q not specified on command line", test.Wrapper) |
|
} |
|
work <- invocation{ |
|
toolPath: *toolPath, |
|
wrapperPath: wrapper, |
|
inPath: test.In, |
|
expectedPath: test.Out, |
|
} |
|
} |
|
|
|
close(work) |
|
wg.Wait() |
|
|
|
n := atomic.LoadUint32(&numFailed) |
|
if n > 0 { |
|
log.Printf("Failed %d tests", n) |
|
os.Exit(1) |
|
} else { |
|
log.Printf("%d ACVP tests matched expectations", len(tests)) |
|
} |
|
} |
|
|
|
func worker(wg *sync.WaitGroup, work <-chan invocation, numFailed *uint32) { |
|
defer wg.Done() |
|
|
|
for test := range work { |
|
if err := doTest(test); err != nil { |
|
log.Printf("Test failed for %q: %s", test.inPath, err) |
|
atomic.AddUint32(numFailed, 1) |
|
} |
|
} |
|
} |
|
|
|
func doTest(test invocation) error { |
|
input, err := os.Open(test.inPath) |
|
if err != nil { |
|
return fmt.Errorf("Failed to open %q: %s", test.inPath, err) |
|
} |
|
defer input.Close() |
|
|
|
tempFile, err := ioutil.TempFile("", "boringssl-check_expected-") |
|
if err != nil { |
|
return fmt.Errorf("Failed to create temp file: %s", err) |
|
} |
|
defer os.Remove(tempFile.Name()) |
|
defer tempFile.Close() |
|
|
|
decompressor := bzip2.NewReader(input) |
|
if _, err := io.Copy(tempFile, decompressor); err != nil { |
|
return fmt.Errorf("Failed to decompress %q: %s", test.inPath, err) |
|
} |
|
|
|
cmd := exec.Command(test.toolPath, "-wrapper", test.wrapperPath, "-json", tempFile.Name()) |
|
result, err := cmd.CombinedOutput() |
|
if err != nil { |
|
os.Stderr.Write(result) |
|
return fmt.Errorf("Failed to process %q", test.inPath) |
|
} |
|
|
|
if len(test.expectedPath) == 0 { |
|
// This test has variable output and thus cannot be compared against a fixed |
|
// result. |
|
return nil |
|
} |
|
|
|
expected, err := os.Open(test.expectedPath) |
|
if err != nil { |
|
if *update { |
|
writeUpdate(test.expectedPath, result) |
|
} |
|
return fmt.Errorf("Failed to open %q: %s", test.expectedPath, err) |
|
} |
|
defer expected.Close() |
|
|
|
decompressor = bzip2.NewReader(expected) |
|
|
|
var expectedBuf bytes.Buffer |
|
if _, err := io.Copy(&expectedBuf, decompressor); err != nil { |
|
return fmt.Errorf("Failed to decompress %q: %s", test.expectedPath, err) |
|
} |
|
|
|
if !bytes.Equal(expectedBuf.Bytes(), result) { |
|
if *update { |
|
writeUpdate(test.expectedPath, result) |
|
} |
|
return fmt.Errorf("Mismatch for %q", test.expectedPath) |
|
} |
|
|
|
return nil |
|
} |
|
|
|
func writeUpdate(path string, contents []byte) { |
|
if err := ioutil.WriteFile(path, contents, 0644); err != nil { |
|
log.Printf("Failed to create missing file %q: %s", path, err) |
|
} else { |
|
log.Printf("Wrote %q", path) |
|
} |
|
}
|
|
|