Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions go/provider/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ func (c *client) LeaseStatus(ctx context.Context, id mtypes.LeaseID) (LeaseStatu
return obj, nil
}

func (c *client) LeaseEvents(ctx context.Context, id mtypes.LeaseID, _ string, follow bool) (*LeaseKubeEvents, error) {
func (c *client) LeaseEvents(ctx context.Context, id mtypes.LeaseID, services string, follow bool) (*LeaseKubeEvents, error) {
endpoint, err := url.Parse(c.host.String() + "/" + LeaseEventsPath(id))
if err != nil {
return nil, err
Expand All @@ -619,6 +619,10 @@ func (c *client) LeaseEvents(ctx context.Context, id mtypes.LeaseID, _ string, f
query := url.Values{}
query.Set("follow", strconv.FormatBool(follow))

if services != "" {
query.Set("service", services)
}

endpoint.RawQuery = query.Encode()
rCl := c.NewReqClient(ctx)

Expand Down Expand Up @@ -782,7 +786,7 @@ func (c *client) LeaseLogs(ctx context.Context,
id mtypes.LeaseID,
services string,
follow bool,
_ int64,
tailLines int64,
) (*ServiceLogs, error) {
endpoint, err := url.Parse(c.host.String() + "/" + ServiceLogsPath(id))
if err != nil {
Expand All @@ -801,7 +805,11 @@ func (c *client) LeaseLogs(ctx context.Context,
query.Set("follow", strconv.FormatBool(follow))

if services != "" {
query.Set("services", services)
query.Set("service", services)
}

if tailLines > 0 {
query.Set("tail", strconv.FormatInt(tailLines, 10))
}

endpoint.RawQuery = query.Encode()
Expand Down
147 changes: 147 additions & 0 deletions go/provider/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@ package rest

import (
"context"
"crypto/tls"
"errors"
"net/http"
"net/http/httptest"
"net/url"
"sync"
"testing"

"github.com/gorilla/websocket"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/require"

mtypes "pkg.akt.dev/go/node/market/v1"
_ "pkg.akt.dev/go/sdkutil"
)

Expand Down Expand Up @@ -70,3 +78,142 @@ func TestNewClientWithProviderURL(t *testing.T) {
})

}

// captureQueryServer spins up an httptest.NewTLSServer that records the query
// string of the first websocket upgrade request, then closes the connection.
// The provider gateway uses singular `service` and `tail` query params; these
// tests assert the client sends exactly those keys (and not the legacy plural
// `services`).
//
// Cross-reference: akash-network/provider gateway/rest/middleware.go
// requestStreamParams reads vars.Get("service") and vars.Get("tail").
func captureQueryServer(t *testing.T) (*httptest.Server, func() url.Values) {
t.Helper()
var (
mu sync.Mutex
q url.Values
)
upgrader := websocket.Upgrader{
CheckOrigin: func(*http.Request) bool { return true },
}
srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
mu.Lock()
q = r.URL.Query()
mu.Unlock()

conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
return
}
_ = conn.Close()
}))
return srv, func() url.Values {
mu.Lock()
defer mu.Unlock()
return q
}
}

// newTestClient builds a *client pointed at the test server's URL with a TLS
// config that trusts the httptest self-signed certificate. Same-package
// access lets us replace tlsCfg directly, avoiding any production-surface
// change.
func newTestClient(t *testing.T, ctx context.Context, providerURL string) *client {
t.Helper()
addr, err := sdk.AccAddressFromBech32("akash1365yvmc4s7awdyj3n2sav7xfx76adc6dnmlx63")
require.NoError(t, err)
cl, err := NewClient(ctx, addr, WithProviderURL(providerURL))
require.NoError(t, err)
c := cl.(*client)
c.tlsCfg = &tls.Config{InsecureSkipVerify: true} // nolint: gosec // httptest self-signed cert
return c
}

func testLeaseID() mtypes.LeaseID {
const akashAddr = "akash1365yvmc4s7awdyj3n2sav7xfx76adc6dnmlx63"
return mtypes.LeaseID{
Owner: akashAddr,
DSeq: 1,
GSeq: 1,
OSeq: 1,
Provider: akashAddr,
}
}

func TestLeaseLogs_ForwardsServiceAndTailToGateway(t *testing.T) {
srv, getQuery := captureQueryServer(t)
defer srv.Close()

ctx := context.Background()
c := newTestClient(t, ctx, srv.URL)
lid := testLeaseID()

out, err := c.LeaseLogs(ctx, lid, "db-replica,api", true, 50)
require.NoError(t, err)
require.NotNil(t, out)
<-out.OnClose // wait for reader goroutine to drain after server close

q := getQuery()
require.Equal(t, "db-replica,api", q.Get("service"),
"gateway requestStreamParams reads vars.Get(\"service\") β€” must be singular")
require.Equal(t, "50", q.Get("tail"),
"tailLines must be forwarded as ?tail=N")
require.Equal(t, "true", q.Get("follow"))
require.Empty(t, q.Get("services"),
"legacy plural 'services' key is silently dropped by the gateway β€” must not be sent")
}

func TestLeaseLogs_OmitsEmptyServiceAndZeroTail(t *testing.T) {
srv, getQuery := captureQueryServer(t)
defer srv.Close()

ctx := context.Background()
c := newTestClient(t, ctx, srv.URL)
lid := testLeaseID()

out, err := c.LeaseLogs(ctx, lid, "", false, 0)
require.NoError(t, err)
<-out.OnClose

q := getQuery()
require.Empty(t, q.Get("service"), "empty service filter must not be sent")
require.Empty(t, q.Get("tail"), "tail <= 0 must not be sent (gateway default is -1)")
require.Equal(t, "false", q.Get("follow"))
}

func TestLeaseEvents_ForwardsServiceToGateway(t *testing.T) {
srv, getQuery := captureQueryServer(t)
defer srv.Close()

ctx := context.Background()
c := newTestClient(t, ctx, srv.URL)
lid := testLeaseID()

out, err := c.LeaseEvents(ctx, lid, "db-replica", true)
require.NoError(t, err)
require.NotNil(t, out)
<-out.OnClose

q := getQuery()
require.Equal(t, "db-replica", q.Get("service"))
require.Equal(t, "true", q.Get("follow"))
require.Empty(t, q.Get("services"))
}

func TestLeaseEvents_OmitsEmptyService(t *testing.T) {
srv, getQuery := captureQueryServer(t)
defer srv.Close()

ctx := context.Background()
c := newTestClient(t, ctx, srv.URL)
lid := testLeaseID()

out, err := c.LeaseEvents(ctx, lid, "", false)
require.NoError(t, err)
<-out.OnClose

q := getQuery()
require.Empty(t, q.Get("service"))
require.Equal(t, "false", q.Get("follow"))
require.Empty(t, q.Get("services"))
}
Comment thread
gosuri marked this conversation as resolved.