From e43272c0544b60d8915f7bf9853b897e2695663d Mon Sep 17 00:00:00 2001 From: Evgeniy Scherbina Date: Fri, 22 Dec 2023 16:44:03 -0500 Subject: [PATCH] Added Hive Integration Tests (#2) --- .github/workflows/ci.yml | 46 +++++++++++++- cmd/result_parser/main.go | 129 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 cmd/result_parser/main.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be52bf9a49..54cf193a8a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,11 +2,13 @@ name: Continuous Integration (Default Checks) on: push: + branches: [ master ] pull_request: workflow_dispatch: env: TEST_PACKAGES: ./... + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} jobs: lint: @@ -40,4 +42,46 @@ jobs: with: go-version: '1.21.4' - name: run tests - run: go run build/ci.go test $TEST_PACKAGES \ No newline at end of file + run: go run build/ci.go test $TEST_PACKAGES + + hive: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.21.4' + - name: clone hive repository + run: git clone https://github.com/ethereum/hive + - name: install hive + working-directory: ./hive + run: go install . + + - name: create hive-clients.yml configuration file based on $BRANCH_NAME + working-directory: .github/workflows + run: | + echo " + - client: go-ethereum + dockerfile: git + build_args: + github: Kava-Labs/go-ethereum + tag: $BRANCH_NAME" > hive-clients.yml + + - name: print hive-clients.yml configuration file for debug purposes + working-directory: .github/workflows + run: cat hive-clients.yml + + - name: run devp2p/discv4 simulation + working-directory: ./hive + run: hive --sim devp2p --sim.limit discv4 --client go-ethereum --client-file $GITHUB_WORKSPACE/.github/workflows/hive-clients.yml + + - name: run ethereum/sync simulation + working-directory: ./hive + run: hive --sim ethereum/sync --client go-ethereum --client-file $GITHUB_WORKSPACE/.github/workflows/hive-clients.yml + + - name: install simulation result parser + run: go install ./cmd/result_parser + - name: run simulation result parser + working-directory: ./hive + run: result_parser -path_to_results ./workspace/logs diff --git a/cmd/result_parser/main.go b/cmd/result_parser/main.go new file mode 100644 index 0000000000..968db79218 --- /dev/null +++ b/cmd/result_parser/main.go @@ -0,0 +1,129 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "log" + "os" + "path/filepath" + "time" + + "github.com/graph-gophers/graphql-go/errors" +) + +var filesToSkip = []string{ + "hive.json", +} + +type simulationResult struct { + Id int `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + ClientVersions struct { + GoEthereum string `json:"go-ethereum"` + } `json:"clientVersions"` + TestCases map[string]*testCase `json:"testCases"` +} + +func (sim *simulationResult) check() error { + for _, testCase := range sim.TestCases { + if err := testCase.check(); err != nil { + return errors.Errorf("simulation %v - %v (%v) failed with an error: %v", sim.Id, sim.Name, sim.Description, err) + } + } + + return nil +} + +type testCase struct { + Name string `json:"name"` + Description string `json:"description"` + Start time.Time `json:"start"` + End time.Time `json:"end"` + SummaryResult struct { + Pass bool `json:"pass"` + } `json:"summaryResult"` +} + +func (t *testCase) check() error { + if !t.SummaryResult.Pass { + return errors.Errorf("test case %v (%v) failed", t.Name, t.Description) + } + + return nil +} + +func parseSimulationResults(pathToResults string) ([]*simulationResult, error) { + dirEntries, err := os.ReadDir(pathToResults) + if err != nil { + return nil, fmt.Errorf("can't read directory: %v", err) + } + + simResults := make([]*simulationResult, 0) + for _, dirEntry := range dirEntries { + if skipFile(dirEntry) { + continue + } + + pathToFile := filepath.Join(pathToResults, dirEntry.Name()) + simResultsInJson, err := os.ReadFile(pathToFile) + if err != nil { + return nil, fmt.Errorf("can't read file: %v", err) + } + + var simResult simulationResult + if err := json.Unmarshal(simResultsInJson, &simResult); err != nil { + return nil, fmt.Errorf("can't unmarshal simulation results: %v", err) + } + + simResults = append(simResults, &simResult) + } + + return simResults, nil +} + +// skipFile returns true if file should be skipped (excluded from parsing and processing) +// skipFile returns true in such cases: +// - entry is a directory (not a file) +// - file doesn't have json extension +// - filename is explicitly marked to be skipped +func skipFile(dirEntry os.DirEntry) bool { + if dirEntry.IsDir() { + return true + } + + ext := filepath.Ext(dirEntry.Name()) + if ext != ".json" { + return true + } + + for _, fileToSkip := range filesToSkip { + if dirEntry.Name() == fileToSkip { + return true + } + } + + return false +} + +func main() { + pathToResultsHelpString := `path to simulation results files of hive framework, by default should be in /path/to/hive/repo/workspace/logs` + pathToResults := flag.String("path_to_results", "", pathToResultsHelpString) + flag.Parse() + + simResults, err := parseSimulationResults(*pathToResults) + if err != nil { + log.Fatalf("can't parse simulation results: %v", err) + } + + for _, simResult := range simResults { + if err := simResult.check(); err != nil { + log.Fatal(err) + } + + fmt.Printf("simulation %v - %v (%v) passed successfully\n", simResult.Id, simResult.Name, simResult.Description) + } + + fmt.Printf("All %v simulations passed successfully\n", len(simResults)) +}