mirror of
https://gitea.com/gitea/runner.git
synced 2026-11-04 22:37:55 +00:00
Migrates the runner to `connectrpc.com/connect/v2` by pinning actionslib v1.5.0, which carries https://gitea.com/gitea/actionslib/pulls/28. The wire behaviour towards Gitea is unchanged and works against Gitea servers on connect v1 and v2. The client keeps v1's unlimited response size, and the error codes and messages the runner checks stay the same. Reviewed-on: https://gitea.com/gitea/runner/pulls/1325 Reviewed-by: bircni <[email protected]> Co-authored-by: silverwind <[email protected]>
142 lines
5.2 KiB
Go
142 lines
5.2 KiB
Go
// Copyright 2026 The Gitea Authors. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package client
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"net"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.com/gitea/runner/internal/pkg/ver"
|
|
|
|
pingv1 "gitea.dev/actionslib/ping/v1"
|
|
"gitea.dev/actionslib/pkg/protocol"
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func TestGetHTTPClientUsesProxyFromEnvironment(t *testing.T) {
|
|
t.Setenv("HTTP_PROXY", "http://proxy.example.com:8080")
|
|
|
|
client := getHTTPClient("http://gitea.example.com", nil, time.Minute, nil)
|
|
require.Equal(t, time.Minute, client.Timeout)
|
|
transport, ok := client.Transport.(*http.Transport)
|
|
require.True(t, ok)
|
|
|
|
req, err := http.NewRequest(http.MethodGet, "http://gitea.example.com/api/actions/ping", nil)
|
|
require.NoError(t, err)
|
|
|
|
proxyURL, err := transport.Proxy(req)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, proxyURL)
|
|
require.Equal(t, "http://proxy.example.com:8080", proxyURL.String())
|
|
}
|
|
|
|
func TestGetHTTPClientAppliesTLSConfigOnlyToHTTPS(t *testing.T) {
|
|
tlsConfig := &tls.Config{}
|
|
require.Same(t, tlsConfig, getHTTPClient("https://gitea.example.com", tlsConfig, time.Minute, nil).Transport.(*http.Transport).TLSClientConfig)
|
|
require.Nil(t, getHTTPClient("http://gitea.example.com", tlsConfig, time.Minute, nil).Transport.(*http.Transport).TLSClientConfig)
|
|
}
|
|
|
|
func TestNewSetsBaseURLAndHeaders(t *testing.T) {
|
|
var gotPath string
|
|
gotHeaders := make(http.Header)
|
|
data := strings.Repeat("x", 4<<20)
|
|
body, err := proto.Marshal(&pingv1.PingResponse{Data: data})
|
|
require.NoError(t, err)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotPath = r.URL.Path
|
|
gotHeaders = r.Header.Clone()
|
|
w.Header().Set("Content-Type", "application/proto")
|
|
_, _ = w.Write(body)
|
|
}))
|
|
defer server.Close()
|
|
|
|
// trailing slash must be trimmed before "/api/actions" is appended
|
|
c := New(server.URL+"/", nil, "the-uuid", "the-token", time.Minute, map[string]string{
|
|
"X-Proxy-Token": "proxy-token",
|
|
protocol.UUIDHeader: "other-uuid",
|
|
protocol.TokenHeader: "other-token",
|
|
"Content-Type": "text/plain",
|
|
})
|
|
// Address returns the endpoint as supplied (untrimmed)
|
|
require.Equal(t, server.URL+"/", c.Address())
|
|
|
|
resp, err := c.Ping(t.Context(), &pingv1.PingRequest{Data: "hi"})
|
|
require.NoError(t, err)
|
|
require.Equal(t, data, resp.Data)
|
|
|
|
require.True(t, strings.HasPrefix(gotPath, "/api/actions/"), "unexpected path %q", gotPath)
|
|
require.Equal(t, "the-uuid", gotHeaders.Get(protocol.UUIDHeader))
|
|
require.Equal(t, "the-token", gotHeaders.Get(protocol.TokenHeader))
|
|
require.Equal(t, "proxy-token", gotHeaders.Get("X-Proxy-Token"))
|
|
require.Equal(t, "application/proto", gotHeaders.Get("Content-Type"))
|
|
require.Equal(t, "gitea-runner/"+ver.Version(), gotHeaders.Get("User-Agent"))
|
|
require.Equal(t, "1", gotHeaders.Get("Connect-Protocol-Version"))
|
|
require.Equal(t, "gzip", gotHeaders.Get("Accept-Encoding"))
|
|
require.Empty(t, gotHeaders.Get("Content-Encoding"))
|
|
}
|
|
|
|
func TestNewOmitsEmptyHeaders(t *testing.T) {
|
|
gotHeaders := make(http.Header)
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotHeaders = r.Header.Clone()
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer server.Close()
|
|
|
|
c := New(server.URL, nil, "", "", time.Minute, nil)
|
|
_, _ = c.Ping(t.Context(), &pingv1.PingRequest{Data: "hi"})
|
|
|
|
require.Empty(t, gotHeaders.Get(protocol.UUIDHeader))
|
|
require.Empty(t, gotHeaders.Get(protocol.TokenHeader))
|
|
}
|
|
|
|
func TestNewStopsRedirectLoop(t *testing.T) {
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
http.Redirect(w, r, r.URL.Path, http.StatusTemporaryRedirect)
|
|
}))
|
|
defer server.Close()
|
|
|
|
c := New(server.URL, nil, "", "", time.Minute, nil)
|
|
_, err := c.Ping(t.Context(), &pingv1.PingRequest{Data: "hi"})
|
|
require.ErrorContains(t, err, "stopped after 10 redirects")
|
|
}
|
|
|
|
func TestNewRedirectKeepsExtraHeadersOnlyOnSameHost(t *testing.T) {
|
|
var gotHeaders http.Header
|
|
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
gotHeaders = r.Header.Clone()
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}))
|
|
defer target.Close()
|
|
_, port, err := net.SplitHostPort(target.Listener.Addr().String())
|
|
require.NoError(t, err)
|
|
|
|
for _, tc := range []struct {
|
|
newOrigin func(http.Handler) *httptest.Server
|
|
host string
|
|
kept bool
|
|
}{
|
|
{httptest.NewServer, "127.0.0.1", true},
|
|
{httptest.NewServer, "localhost", false},
|
|
{httptest.NewTLSServer, "127.0.0.1", false},
|
|
} {
|
|
gotHeaders = nil
|
|
origin := tc.newOrigin(http.RedirectHandler("http://"+net.JoinHostPort(tc.host, port), http.StatusPermanentRedirect))
|
|
c := New(origin.URL, &tls.Config{InsecureSkipVerify: true}, "the-uuid", "the-token", time.Minute, map[string]string{"X-Proxy-Token": "proxy-token", "Content-Type": "text/plain"})
|
|
_, _ = c.Ping(t.Context(), &pingv1.PingRequest{Data: "hi"})
|
|
origin.Close()
|
|
|
|
require.NotNil(t, gotHeaders, origin.URL)
|
|
require.Equal(t, tc.kept, gotHeaders.Get("X-Proxy-Token") != "", "%s to %s", origin.URL, tc.host)
|
|
require.Equal(t, "the-token", gotHeaders.Get(protocol.TokenHeader))
|
|
require.Equal(t, "application/proto", gotHeaders.Get("Content-Type"))
|
|
}
|
|
}
|