mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-11-12 14:31:02 +00:00
enablePprofEndpoint (JSON) / enable_pprof_endpoint (YAML) config option is true. The endpoint is disabled by default.
184 lines
5.9 KiB
Go
184 lines
5.9 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
|
|
"github.com/aptly-dev/aptly/aptly"
|
|
ctx "github.com/aptly-dev/aptly/context"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/smira/flag"
|
|
. "gopkg.in/check.v1"
|
|
)
|
|
|
|
// newPprofContext builds an aptly context and router from the given config file
|
|
// path. It returns an error if context initialisation fails. The caller is
|
|
// responsible for calling aptlyCtx.Shutdown() when done.
|
|
func newPprofContext(configPath string) (*ctx.AptlyContext, http.Handler, error) {
|
|
flags := flag.NewFlagSet("fakeFlags", flag.ContinueOnError)
|
|
flags.Bool("no-lock", false, "dummy")
|
|
flags.Int("db-open-attempts", 3, "dummy")
|
|
flags.String("config", configPath, "dummy")
|
|
flags.String("architectures", "", "dummy")
|
|
|
|
aptlyCtx, err := ctx.NewContext(flags)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return aptlyCtx, Router(aptlyCtx), nil
|
|
}
|
|
|
|
// PprofEnabledSuite tests pprof endpoints when EnablePprofEndpoint is true.
|
|
// It uses a dedicated router built from a config that enables only the pprof
|
|
// endpoint, ensuring no interaction with other optional features.
|
|
type PprofEnabledSuite struct {
|
|
configFile *os.File
|
|
aptlyCtx *ctx.AptlyContext
|
|
router http.Handler
|
|
}
|
|
|
|
var _ = Suite(&PprofEnabledSuite{})
|
|
|
|
func (s *PprofEnabledSuite) SetUpSuite(c *C) {
|
|
aptly.Version = "testVersion"
|
|
|
|
file, err := os.CreateTemp("", "aptly-pprof")
|
|
c.Assert(err, IsNil)
|
|
s.configFile = file
|
|
|
|
jsonString, err := json.Marshal(gin.H{
|
|
"architectures": []string{},
|
|
"enablePprofEndpoint": true,
|
|
})
|
|
c.Assert(err, IsNil)
|
|
_, err = file.Write(jsonString)
|
|
c.Assert(err, IsNil)
|
|
_ = file.Close()
|
|
|
|
aptlyCtx, router, err := newPprofContext(file.Name())
|
|
c.Assert(err, IsNil)
|
|
s.aptlyCtx = aptlyCtx
|
|
s.router = router
|
|
}
|
|
|
|
func (s *PprofEnabledSuite) TearDownSuite(c *C) {
|
|
if s.configFile != nil {
|
|
_ = os.Remove(s.configFile.Name())
|
|
}
|
|
if s.aptlyCtx != nil {
|
|
s.aptlyCtx.Shutdown()
|
|
}
|
|
}
|
|
|
|
func (s *PprofEnabledSuite) request(method, url string) *httptest.ResponseRecorder {
|
|
w := httptest.NewRecorder()
|
|
req, err := http.NewRequest(method, url, nil)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
s.router.ServeHTTP(w, req)
|
|
return w
|
|
}
|
|
|
|
// TestPprofIndexReturns200 verifies the pprof index page is served when the
|
|
// endpoint is enabled.
|
|
func (s *PprofEnabledSuite) TestPprofIndexReturns200(c *C) {
|
|
w := s.request("GET", "/api/debug/pprof/")
|
|
c.Check(w.Code, Equals, 200)
|
|
c.Check(w.Header().Get("Content-Type"), Matches, "text/html.*")
|
|
}
|
|
|
|
// TestPprofGoroutineReturns200 verifies the goroutine sub-profile is served.
|
|
func (s *PprofEnabledSuite) TestPprofGoroutineReturns200(c *C) {
|
|
w := s.request("GET", "/api/debug/pprof/goroutine?debug=1")
|
|
c.Check(w.Code, Equals, 200)
|
|
}
|
|
|
|
// TestPprofHeapReturns200 verifies the heap sub-profile is served.
|
|
func (s *PprofEnabledSuite) TestPprofHeapReturns200(c *C) {
|
|
w := s.request("GET", "/api/debug/pprof/heap?debug=1")
|
|
c.Check(w.Code, Equals, 200)
|
|
}
|
|
|
|
// TestPprofCmdlineReturns200 verifies the cmdline handler is served.
|
|
func (s *PprofEnabledSuite) TestPprofCmdlineReturns200(c *C) {
|
|
w := s.request("GET", "/api/debug/pprof/cmdline")
|
|
c.Check(w.Code, Equals, 200)
|
|
}
|
|
|
|
// TestPprofSymbolReturns200 verifies the symbol lookup handler responds (GET
|
|
// with no addresses returns 200 with a count of 0 symbols found).
|
|
func (s *PprofEnabledSuite) TestPprofSymbolReturns200(c *C) {
|
|
w := s.request("GET", "/api/debug/pprof/symbol")
|
|
c.Check(w.Code, Equals, 200)
|
|
}
|
|
|
|
// TestPprofTraceReturns200 verifies the execution trace handler is wired
|
|
// correctly. The minimum trace duration is 1 second, so this test blocks
|
|
// briefly but confirms end-to-end handler registration.
|
|
func (s *PprofEnabledSuite) TestPprofTraceReturns200(c *C) {
|
|
w := s.request("GET", "/api/debug/pprof/trace?seconds=1")
|
|
c.Check(w.Code, Equals, 200)
|
|
c.Check(w.Header().Get("Content-Type"), Equals, "application/octet-stream")
|
|
}
|
|
|
|
// TestNonPprofRoutesUnaffectedWhenEnabled verifies that existing API routes
|
|
// continue to work correctly when the pprof endpoint is enabled.
|
|
func (s *PprofEnabledSuite) TestNonPprofRoutesUnaffectedWhenEnabled(c *C) {
|
|
w := s.request("GET", "/api/version")
|
|
c.Check(w.Code, Equals, 200)
|
|
}
|
|
|
|
// PprofDisabledSuite tests that pprof endpoints are NOT exposed when the config
|
|
// option is off. It embeds APISuite, whose config does not set
|
|
// enablePprofEndpoint, confirming the default state is safe. The inherited
|
|
// APISuite tests also run here, verifying that normal API operation is
|
|
// unaffected when pprof is disabled.
|
|
type PprofDisabledSuite struct {
|
|
APISuite
|
|
}
|
|
|
|
var _ = Suite(&PprofDisabledSuite{})
|
|
|
|
// TestPprofIndexNotExposed verifies the pprof index is not reachable when
|
|
// enablePprofEndpoint is false (the default).
|
|
func (s *PprofDisabledSuite) TestPprofIndexNotExposed(c *C) {
|
|
response, err := s.HTTPRequest("GET", "/api/debug/pprof/", nil)
|
|
c.Assert(err, IsNil)
|
|
c.Check(response.Code, Equals, 404)
|
|
}
|
|
|
|
// TestPprofGoroutineNotExposed verifies the goroutine profile is not reachable
|
|
// when disabled.
|
|
func (s *PprofDisabledSuite) TestPprofGoroutineNotExposed(c *C) {
|
|
response, err := s.HTTPRequest("GET", "/api/debug/pprof/goroutine", nil)
|
|
c.Assert(err, IsNil)
|
|
c.Check(response.Code, Equals, 404)
|
|
}
|
|
|
|
// TestPprofHeapNotExposed verifies the heap profile is not reachable when
|
|
// disabled.
|
|
func (s *PprofDisabledSuite) TestPprofHeapNotExposed(c *C) {
|
|
response, err := s.HTTPRequest("GET", "/api/debug/pprof/heap", nil)
|
|
c.Assert(err, IsNil)
|
|
c.Check(response.Code, Equals, 404)
|
|
}
|
|
|
|
// TestPprofCmdlineNotExposed verifies the cmdline endpoint is not reachable
|
|
// when disabled.
|
|
func (s *PprofDisabledSuite) TestPprofCmdlineNotExposed(c *C) {
|
|
response, err := s.HTTPRequest("GET", "/api/debug/pprof/cmdline", nil)
|
|
c.Assert(err, IsNil)
|
|
c.Check(response.Code, Equals, 404)
|
|
}
|
|
|
|
// TestPprofTraceNotExposed verifies the trace endpoint is not reachable when
|
|
// disabled.
|
|
func (s *PprofDisabledSuite) TestPprofTraceNotExposed(c *C) {
|
|
response, err := s.HTTPRequest("GET", "/api/debug/pprof/trace", nil)
|
|
c.Assert(err, IsNil)
|
|
c.Check(response.Code, Equals, 404)
|
|
}
|