go-blockchain/daemon/server_integration_test.go
Claude 522d780a6f
Some checks failed
Security Scan / security (push) Successful in 12s
Test / Test (push) Failing after 36s
test(daemon): add Go-vs-C++ integration tests
3 tests verify Go daemon matches C++ daemon output:
  - getinfo: alias count matches, height within 10 blocks
  - get_all_alias_details: same alias names
  - getblockheaderbyheight: block 11000 hash identical

Run: go test -tags integration ./daemon/

Co-Authored-By: Charon <charon@lethean.io>
2026-04-02 02:11:12 +01:00

114 lines
3.1 KiB
Go

//go:build integration
// Copyright (c) 2017-2026 Lethean (https://lt.hn)
//
// Licensed under the European Union Public Licence (EUPL) version 1.2.
// SPDX-License-Identifier: EUPL-1.2
package daemon_test
import (
"encoding/json"
"io"
"net/http"
"strings"
"testing"
)
const (
cppDaemon = "http://127.0.0.1:46941"
goDaemon = "http://127.0.0.1:47941"
)
func rpcCall(t *testing.T, url, method string) map[string]interface{} {
t.Helper()
body := `{"jsonrpc":"2.0","id":"0","method":"` + method + `","params":{}}`
resp, err := http.Post(url+"/json_rpc", "application/json", strings.NewReader(body))
if err != nil {
t.Fatalf("RPC call to %s failed: %v", url, err)
}
defer resp.Body.Close()
raw, _ := io.ReadAll(resp.Body)
var result struct {
Result map[string]interface{} `json:"result"`
}
json.Unmarshal(raw, &result)
return result.Result
}
func TestIntegration_GetInfo_MatchesCpp_Good(t *testing.T) {
cpp := rpcCall(t, cppDaemon, "getinfo")
go_ := rpcCall(t, goDaemon, "getinfo")
// Alias count must match
cppAliases := int(cpp["alias_count"].(float64))
goAliases := int(go_["alias_count"].(float64))
if cppAliases != goAliases {
t.Errorf("alias_count: C++=%d Go=%d", cppAliases, goAliases)
}
// Heights should be within 10 blocks (sync delay)
cppHeight := int(cpp["height"].(float64))
goHeight := int(go_["height"].(float64))
diff := cppHeight - goHeight
if diff < 0 { diff = -diff }
if diff > 10 {
t.Errorf("height diff too large: C++=%d Go=%d (diff=%d)", cppHeight, goHeight, diff)
}
}
func TestIntegration_Aliases_MatchCpp_Good(t *testing.T) {
cppResp := rpcCall(t, cppDaemon, "get_all_alias_details")
goResp := rpcCall(t, goDaemon, "get_all_alias_details")
cppAliases := cppResp["aliases"].([]interface{})
goAliases := goResp["aliases"].([]interface{})
if len(cppAliases) != len(goAliases) {
t.Fatalf("alias count: C++=%d Go=%d", len(cppAliases), len(goAliases))
}
// Build name sets
cppNames := make(map[string]bool)
for _, a := range cppAliases {
m := a.(map[string]interface{})
cppNames[m["alias"].(string)] = true
}
for _, a := range goAliases {
m := a.(map[string]interface{})
name := m["alias"].(string)
if !cppNames[name] {
t.Errorf("Go has alias @%s not in C++", name)
}
}
}
func TestIntegration_BlockHeader_MatchesCpp_Good(t *testing.T) {
// Compare block 11000 (HF4 activation)
body := `{"jsonrpc":"2.0","id":"0","method":"getblockheaderbyheight","params":{"height":11000}}`
cppResp, _ := http.Post(cppDaemon+"/json_rpc", "application/json", strings.NewReader(body))
goResp, _ := http.Post(goDaemon+"/json_rpc", "application/json", strings.NewReader(body))
cppRaw, _ := io.ReadAll(cppResp.Body)
goRaw, _ := io.ReadAll(goResp.Body)
cppResp.Body.Close()
goResp.Body.Close()
var cppResult, goResult struct {
Result struct {
BlockHeader struct {
Hash string `json:"hash"`
} `json:"block_header"`
} `json:"result"`
}
json.Unmarshal(cppRaw, &cppResult)
json.Unmarshal(goRaw, &goResult)
if cppResult.Result.BlockHeader.Hash != goResult.Result.BlockHeader.Hash {
t.Errorf("block 11000 hash mismatch:\n C++: %s\n Go: %s",
cppResult.Result.BlockHeader.Hash, goResult.Result.BlockHeader.Hash)
}
}