From 8a5eeb0b30b8868d1e91ed66cd70f45db42e1554 Mon Sep 17 00:00:00 2001 From: Pantani Date: Thu, 5 Feb 2026 17:34:44 -0300 Subject: [PATCH 1/2] feat: improve the `httpstatuschecker` by injecting clients --- .../httpstatuschecker/httpstatuschecker.go | 9 ++++ .../httpstatuschecker_test.go | 34 +++++++++++--- ignite/pkg/jsonfile/jsonfile.go | 15 ++++++- ignite/pkg/jsonfile/jsonfile_test.go | 45 +++++++++++++++---- 4 files changed, 86 insertions(+), 17 deletions(-) diff --git a/ignite/pkg/httpstatuschecker/httpstatuschecker.go b/ignite/pkg/httpstatuschecker/httpstatuschecker.go index e41b936c81..8441975597 100644 --- a/ignite/pkg/httpstatuschecker/httpstatuschecker.go +++ b/ignite/pkg/httpstatuschecker/httpstatuschecker.go @@ -22,6 +22,15 @@ func Method(name string) Option { } } +// Client configures http client. +func Client(client *http.Client) Option { + return func(cr *checker) { + if client != nil { + cr.c = client + } + } +} + // Check checks if given http addr is alive by applying options. func Check(ctx context.Context, addr string, options ...Option) (isAvailable bool, err error) { cr := &checker{ diff --git a/ignite/pkg/httpstatuschecker/httpstatuschecker_test.go b/ignite/pkg/httpstatuschecker/httpstatuschecker_test.go index 22dcb2d95a..2323b1b9ae 100644 --- a/ignite/pkg/httpstatuschecker/httpstatuschecker_test.go +++ b/ignite/pkg/httpstatuschecker/httpstatuschecker_test.go @@ -1,14 +1,26 @@ package httpstatuschecker import ( + "bytes" "context" + "errors" + "io" "net/http" - "net/http/httptest" "testing" "github.com/stretchr/testify/require" ) +type roundTripperFunc func(*http.Request) (*http.Response, error) + +func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +} + +func newTestClient(fn roundTripperFunc) *http.Client { + return &http.Client{Transport: fn} +} + func TestCheckStatus(t *testing.T) { cases := []struct { name string @@ -21,12 +33,17 @@ func TestCheckStatus(t *testing.T) { } for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - w.WriteHeader(tt.returnedStatus) - })) - defer ts.Close() + client := newTestClient(func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: tt.returnedStatus, + Body: io.NopCloser(bytes.NewReader(nil)), + Header: make(http.Header), + ContentLength: 0, + Request: req, + }, nil + }) - isAvailable, err := Check(context.Background(), ts.URL) + isAvailable, err := Check(context.Background(), "http://example.com", Client(client)) require.NoError(t, err) require.Equal(t, tt.isAvaiable, isAvailable) }) @@ -34,7 +51,10 @@ func TestCheckStatus(t *testing.T) { } func TestCheckServerUnreachable(t *testing.T) { - isAvailable, err := Check(context.Background(), "http://localhost:63257") + client := newTestClient(func(*http.Request) (*http.Response, error) { + return nil, errors.New("dial tcp: connection refused") + }) + isAvailable, err := Check(context.Background(), "http://example.com", Client(client)) require.NoError(t, err) require.False(t, isAvailable) } diff --git a/ignite/pkg/jsonfile/jsonfile.go b/ignite/pkg/jsonfile/jsonfile.go index 3bc5d8e77c..ede873ed00 100644 --- a/ignite/pkg/jsonfile/jsonfile.go +++ b/ignite/pkg/jsonfile/jsonfile.go @@ -87,6 +87,19 @@ func FromPath(path string) (*JSONFile, error) { // tarballFileName is extracted from it and is returned instead of the URL // content. func FromURL(ctx context.Context, url, destPath, tarballFileName string) (*JSONFile, error) { + return fromURL(ctx, url, destPath, tarballFileName, http.DefaultClient) +} + +// FromURLWithClient fetches the file using the provided HTTP client. +// If client is nil, http.DefaultClient is used. +func FromURLWithClient(ctx context.Context, url, destPath, tarballFileName string, client *http.Client) (*JSONFile, error) { + if client == nil { + client = http.DefaultClient + } + return fromURL(ctx, url, destPath, tarballFileName, client) +} + +func fromURL(ctx context.Context, url, destPath, tarballFileName string, client *http.Client) (*JSONFile, error) { // TODO create a cache system to avoid download genesis with the same hash again // Download the file from URL @@ -95,7 +108,7 @@ func FromURL(ctx context.Context, url, destPath, tarballFileName string) (*JSONF return nil, err } - resp, err := http.DefaultClient.Do(req) + resp, err := client.Do(req) if err != nil { return nil, err } diff --git a/ignite/pkg/jsonfile/jsonfile_test.go b/ignite/pkg/jsonfile/jsonfile_test.go index d98d100d16..4d0134fd35 100644 --- a/ignite/pkg/jsonfile/jsonfile_test.go +++ b/ignite/pkg/jsonfile/jsonfile_test.go @@ -5,8 +5,8 @@ import ( "context" "encoding/json" "fmt" + "io" "net/http" - "net/http/httptest" "os" "reflect" "testing" @@ -19,6 +19,26 @@ import ( "github.com/ignite/cli/v29/ignite/pkg/tarball" ) +type roundTripperFunc func(*http.Request) (*http.Response, error) + +func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { + return f(req) +} + +func newTestClient(statusCode int, body []byte) *http.Client { + return &http.Client{ + Transport: roundTripperFunc(func(req *http.Request) (*http.Response, error) { + return &http.Response{ + StatusCode: statusCode, + Body: io.NopCloser(bytes.NewReader(body)), + Header: make(http.Header), + ContentLength: int64(len(body)), + Request: req, + }, nil + }), + } +} + func TestJSONFile_Field(t *testing.T) { type ( invalidStruct struct { @@ -356,17 +376,24 @@ func TestFromURL(t *testing.T) { t.Run(tt.name, func(t *testing.T) { url := tt.args.url if url == "" { - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { - file, err := os.ReadFile(tt.args.filepath) - require.NoError(t, err) - _, err = w.Write(file) - require.NoError(t, err) - })) - url = ts.URL + url = "https://example.com/testdata" + } + + var body []byte + if tt.args.filepath != "" { + var err error + body, err = os.ReadFile(tt.args.filepath) + require.NoError(t, err) + } + + statusCode := http.StatusOK + if tt.err == ErrInvalidURL { + statusCode = http.StatusNotFound } + client := newTestClient(statusCode, body) filepath := fmt.Sprintf("%s/jsonfile.json", t.TempDir()) - got, err := FromURL(context.TODO(), url, filepath, tt.args.tarballFileName) + got, err := FromURLWithClient(context.TODO(), url, filepath, tt.args.tarballFileName, client) if tt.err != nil { require.Error(t, err) require.ErrorIs(t, err, tt.err) From 49f1402638c5f47fc945d028700645efea8c7e26 Mon Sep 17 00:00:00 2001 From: Pantani Date: Thu, 5 Feb 2026 17:36:23 -0300 Subject: [PATCH 2/2] add changelog --- changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.md b/changelog.md index cb45038df5..993fe9de7b 100644 --- a/changelog.md +++ b/changelog.md @@ -7,6 +7,10 @@ - [#4864](https://github.com/ignite/cli/pull/4864) Mismatch for message names. - [#4735](https://github.com/ignite/cli/issues/4735) Cleanup `xgenny` runner to avoid duplicated generators. +## Features + +- [#4869](https://github.com/ignite/cli/pull/4869) Improve the httpstatuschecker by injecting clients. + ## [`v29.7.0`](https://github.com/ignite/cli/releases/tag/v29.7.0) ## Changes