Skip to content

Commit

Permalink
test: fix faucet test (backport #4543) (#4544)
Browse files Browse the repository at this point in the history
* test: fix faucet test (#4543)

* test: fix faucet test

* cl

(cherry picked from commit c60540e)

# Conflicts:
#	ignite/pkg/cosmosfaucet/client_http.go

* fixes

---------

Co-authored-by: Julien Robert <[email protected]>
  • Loading branch information
mergify[bot] and julienrbrt authored Feb 26, 2025
1 parent 6e09085 commit b40b587
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 28 deletions.
2 changes: 1 addition & 1 deletion changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

- [#4532](https://github.com/ignite/cli/pull/4532) Fix non working _shortcuts_ in validator home config
- [#4538](https://github.com/ignite/cli/pull/4538) Create a simple spinner for non-terminal interactions
- [#4540](https://github.com/ignite/cli/pull/4540) Skip logs / gibberish when parsing commands outputs
- [#4540](https://github.com/ignite/cli/pull/4540), [#4543](https://github.com/ignite/cli/pull/4543) Skip logs / gibberish when parsing commands outputs

## [`v28.8.0`](https://github.com/ignite/cli/releases/tag/v28.8.0)

Expand Down
114 changes: 90 additions & 24 deletions ignite/pkg/chaincmd/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,47 +143,113 @@ type buffer struct {

// JSONEnsuredBytes ensures that encoding format for returned bytes is always
// JSON even if the written data is originally encoded in YAML.
// This method is purposely verbose to trim gibberish output.
func (b *buffer) JSONEnsuredBytes() ([]byte, error) {
bz := b.Bytes()
content := strings.TrimSpace(string(bz))

// check for valid json
// Early detection - check first non-whitespace character
if len(content) > 0 {
firstChar := content[0]

// Quick check for JSON format (starts with { or [)
if firstChar == '{' || firstChar == '[' {
// Attempt to validate and extract clean JSON
return cleanAndValidateJSON(bz)
}

// Quick check for YAML format (common indicators)
if firstChar == '-' || strings.HasPrefix(content, "---") ||
strings.Contains(content, ":\n") || strings.Contains(content, ": ") {
// Likely YAML, convert to JSON directly
var out any
if err := yaml.Unmarshal(bz, &out); err == nil {
return yaml.YAMLToJSON(bz)
}
}
}

// If format wasn't immediately obvious, try the more thorough approach
return fallbackFormatDetection(bz)
}

// cleanAndValidateJSON attempts to extract valid JSON from potentially messy output
func cleanAndValidateJSON(bz []byte) ([]byte, error) {
// Find the first JSON opening character
startIndex := strings.IndexAny(string(bz), "{[")
if startIndex >= 0 {
// check if we need to find the matching closing bracket
opening := bz[startIndex]
var closing byte
if opening == '{' {
closing = '}'
} else {
closing = ']'
if startIndex < 0 {
return bz, nil // No JSON structure found
}

// Determine matching closing character
opening := bz[startIndex]
var closing byte
if opening == '{' {
closing = '}'
} else {
closing = ']'
}

endIndex := findMatchingCloseBracket(bz[startIndex:], opening, closing)
if endIndex < 0 {
// no proper closing found, try last instance
endIndex = bytes.LastIndexByte(bz, closing)
if endIndex <= startIndex {
return bz[startIndex:], nil // Return from start to end if no closing found
}
} else {
endIndex += startIndex
}

// look for the last matching closing bracket
endIndex := bytes.LastIndexByte(bz, closing)
if endIndex > startIndex {
// extract what appears to be valid JSON
bz = bz[startIndex : endIndex+1]
// validate JSON
jsonData := bz[startIndex : endIndex+1]
var jsonTest any
if err := json.Unmarshal(jsonData, &jsonTest); err == nil {
return jsonData, nil
}

// if validation failed, return from start to end
return bz[startIndex:], nil
}

// verify it's actually valid JSON
var jsonTest any
if err := json.Unmarshal(bz, &jsonTest); err == nil {
return bz, nil
// findMatchingCloseBracket finds the index of the matching closing bracket
// accounting for nested structures
func findMatchingCloseBracket(data []byte, openChar, closeChar byte) int {
depth := 0
for i, b := range data {
if b == openChar {
depth++
} else if b == closeChar {
depth--
if depth == 0 {
return i // Found matching closing bracket
}
}
}
return -1 // No matching bracket found
}

// fallbackFormatDetection tries different approaches to detect and convert format
func fallbackFormatDetection(bz []byte) ([]byte, error) {
// first try to find and extract JSON
startIndex := strings.IndexAny(string(bz), "{[")
if startIndex >= 0 {
result, err := cleanAndValidateJSON(bz)
if err == nil {
return result, nil
}

// if extraction failed but we found a start, return from there
return bz[startIndex:], nil
}

// fallback to yaml parsing
var out any
if err := yaml.Unmarshal(bz, &out); err == nil {
return yaml.YAMLToJSON(bz)
}

// if neither JSON nor YAML parsing succeeded, return the original bytes
// starting from the first opening brace if found, or the entire buffer
if startIndex >= 0 {
return bz[startIndex:], nil
}

// nothing worked, return original
return bz, nil
}

Expand Down
12 changes: 9 additions & 3 deletions ignite/pkg/cosmosfaucet/client_http.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import (
"bytes"
"context"
"encoding/json"
"io"
"net/http"

"github.com/ignite/cli/v28/ignite/pkg/errors"
)

// ErrTransferRequest is an error that occurs when a transfer request fails.
type ErrTransferRequest struct {
Body string
StatusCode int
}

Expand Down Expand Up @@ -48,12 +50,16 @@ func (c HTTPClient) Transfer(ctx context.Context, req TransferRequest) (Transfer
defer hres.Body.Close()

if hres.StatusCode != http.StatusOK {
return TransferResponse{}, ErrTransferRequest{hres.StatusCode}
bodyBytes, _ := io.ReadAll(hres.Body)
return TransferResponse{}, ErrTransferRequest{Body: string(bodyBytes), StatusCode: hres.StatusCode}
}

var res TransferResponse
err = json.NewDecoder(hres.Body).Decode(&res)
return res, err
if err = json.NewDecoder(hres.Body).Decode(&res); err != nil {
return TransferResponse{}, err
}

return res, nil
}

// FaucetInfo fetch the faucet info for clients to determine if this is a real faucet and
Expand Down

0 comments on commit b40b587

Please sign in to comment.