Skip to content

Commit

Permalink
refactored admin server and api + health endpoint tests
Browse files Browse the repository at this point in the history
  • Loading branch information
otherview committed Oct 30, 2024
1 parent df30451 commit b124448
Show file tree
Hide file tree
Showing 14 changed files with 127 additions and 141 deletions.
44 changes: 0 additions & 44 deletions api/accounts/accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,8 @@
package accounts_test

import (
"bytes"
"encoding/json"
"fmt"
"io"
"math/big"
"net/http"
"net/http/httptest"
Expand Down Expand Up @@ -578,45 +576,3 @@ func batchCallWithNonExistingRevision(t *testing.T) {
assert.Equal(t, http.StatusBadRequest, statusCode, "bad revision")
assert.Equal(t, "revision: leveldb: not found\n", string(res), "revision not found")
}

func httpPost(t *testing.T, url string, body interface{}) ([]byte, int) {
data, err := json.Marshal(body)
if err != nil {
t.Fatal(err)
}
res, err := http.Post(url, "application/x-www-form-urlencoded", bytes.NewReader(data)) //#nosec G107
if err != nil {
t.Fatal(err)
}
r, err := io.ReadAll(res.Body)
res.Body.Close()
if err != nil {
t.Fatal(err)
}
return r, res.StatusCode
}

func httpGet(t *testing.T, url string) ([]byte, int) {
res, err := http.Get(url) //#nosec G107
if err != nil {
t.Fatal(err)
}
r, err := io.ReadAll(res.Body)
res.Body.Close()
if err != nil {
t.Fatal(err)
}
return r, res.StatusCode
}

func httpGetAccount(t *testing.T, path string) *accounts.Account {
res, statusCode := httpGet(t, ts.URL+"/accounts/"+path)
var acc accounts.Account
if err := json.Unmarshal(res, &acc); err != nil {
t.Fatal(err)
}

assert.Equal(t, http.StatusOK, statusCode, "get account failed")

return &acc
}
25 changes: 25 additions & 0 deletions api/admin/admin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package admin

import (
"log/slog"
"net/http"

"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/vechain/thor/v2/api/admin/loglevel"
"github.com/vechain/thor/v2/health"

healthAPI "github.com/vechain/thor/v2/api/admin/health"
)

func New(logLevel *slog.LevelVar, health *health.Health) http.HandlerFunc {
router := mux.NewRouter()
router.PathPrefix("/admin")

loglevel.New(logLevel).Mount(router, "/loglevel")
healthAPI.New(health).Mount(router, "/health")

handler := handlers.CompressHandler(router)

return handler.ServeHTTP
}
2 changes: 1 addition & 1 deletion api/health/health.go → api/admin/health/health.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (h *Health) handleGetHealth(w http.ResponseWriter, _ *http.Request) error {
func (h *Health) Mount(root *mux.Router, pathPrefix string) {
sub := root.PathPrefix(pathPrefix).Subrouter()

sub.Path("/").
sub.Path("").
Methods(http.MethodGet).
Name("health").
HandlerFunc(utils.WrapHandlerFunc(h.handleGetHealth))
Expand Down
52 changes: 52 additions & 0 deletions api/admin/health/health_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2024 The VeChainThor developers

// Distributed under the GNU Lesser General Public License v3.0 software license, see the accompanying
// file LICENSE or <https://www.gnu.org/licenses/lgpl-3.0.html>

package health

import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"testing"

"github.com/gorilla/mux"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vechain/thor/v2/health"
)

var ts *httptest.Server

func TestHealth(t *testing.T) {
initAPIServer(t)

var healthStatus health.Status
respBody, statusCode := httpGet(t, ts.URL+"/health")
require.NoError(t, json.Unmarshal(respBody, &healthStatus))
assert.False(t, healthStatus.Healthy)
assert.Equal(t, http.StatusServiceUnavailable, statusCode)
}

func initAPIServer(_ *testing.T) {
router := mux.NewRouter()
New(&health.Health{}).Mount(router, "/health")

ts = httptest.NewServer(router)
}

func httpGet(t *testing.T, url string) ([]byte, int) {
res, err := http.Get(url) //#nosec G107
if err != nil {
t.Fatal(err)
}
defer res.Body.Close()

r, err := io.ReadAll(res.Body)
if err != nil {
t.Fatal(err)
}
return r, res.StatusCode
}
File renamed without changes.
32 changes: 24 additions & 8 deletions api/admin.go → api/admin/loglevel/log_level.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,52 @@
// Distributed under the GNU Lesser General Public License v3.0 software license, see the accompanying
// file LICENSE or <https://www.gnu.org/licenses/lgpl-3.0.html>

package api
package loglevel

import (
"log/slog"
"net/http"

"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/vechain/thor/v2/api/utils"
"github.com/vechain/thor/v2/log"
)

type logLevelRequest struct {
Level string `json:"level"`
type LogLevel struct {
logLevel *slog.LevelVar
}

type logLevelResponse struct {
CurrentLevel string `json:"currentLevel"`
func New(logLevel *slog.LevelVar) *LogLevel {
return &LogLevel{
logLevel: logLevel,
}
}

func (l *LogLevel) Mount(root *mux.Router, pathPrefix string) {
sub := root.PathPrefix(pathPrefix).Subrouter()
sub.Path("").
Methods(http.MethodGet).
Name("get-log-level").
HandlerFunc(utils.WrapHandlerFunc(getLogLevelHandler(l.logLevel)))

sub.Path("").
Methods(http.MethodPost).
Name("post-log-level").
HandlerFunc(utils.WrapHandlerFunc(postLogLevelHandler(l.logLevel)))
}

func getLogLevelHandler(logLevel *slog.LevelVar) utils.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
return utils.WriteJSON(w, logLevelResponse{
return utils.WriteJSON(w, Response{
CurrentLevel: logLevel.Level().String(),
})
}
}

func postLogLevelHandler(logLevel *slog.LevelVar) utils.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) error {
var req logLevelRequest
var req Request

if err := utils.ParseJSON(r.Body, &req); err != nil {
return utils.BadRequest(errors.WithMessage(err, "Invalid request body"))
Expand All @@ -55,7 +71,7 @@ func postLogLevelHandler(logLevel *slog.LevelVar) utils.HandlerFunc {
return utils.BadRequest(errors.New("Invalid verbosity level"))
}

return utils.WriteJSON(w, logLevelResponse{
return utils.WriteJSON(w, Response{
CurrentLevel: logLevel.Level().String(),
})
}
Expand Down
11 changes: 7 additions & 4 deletions api/admin_test.go → api/admin/loglevel/log_level_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// Distributed under the GNU Lesser General Public License v3.0 software license, see the accompanying
// file LICENSE or <https://www.gnu.org/licenses/lgpl-3.0.html>

package api
package loglevel

import (
"bytes"
Expand All @@ -14,6 +14,8 @@ import (
"strings"
"testing"

"github.com/gorilla/mux"

"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -76,15 +78,16 @@ func TestLogLevelHandler(t *testing.T) {
}

rr := httptest.NewRecorder()
handler := http.HandlerFunc(HTTPHandler(&logLevel).ServeHTTP)
handler.ServeHTTP(rr, req)
router := mux.NewRouter()
New(&logLevel).Mount(router, "/admin/loglevel")
router.ServeHTTP(rr, req)

if status := rr.Code; status != tt.expectedStatus {
t.Errorf("handler returned wrong status code: got %v want %v", status, tt.expectedStatus)
}

if tt.expectedLevel != "" {
var response logLevelResponse
var response Response
if err := json.NewDecoder(rr.Body).Decode(&response); err != nil {
t.Fatalf("could not decode response: %v", err)
}
Expand Down
9 changes: 9 additions & 0 deletions api/admin/loglevel/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package loglevel

type Request struct {
Level string `json:"level"`
}

type Response struct {
CurrentLevel string `json:"currentLevel"`
}
29 changes: 5 additions & 24 deletions api/admin_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,21 @@ import (
"net/http"
"time"

"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/pkg/errors"
"github.com/vechain/thor/v2/api/utils"
"github.com/vechain/thor/v2/api/admin"
"github.com/vechain/thor/v2/co"
"github.com/vechain/thor/v2/health"
)

func HTTPHandler(logLevel *slog.LevelVar) http.Handler {
router := mux.NewRouter()
sub := router.PathPrefix("/admin").Subrouter()
sub.Path("/loglevel").
Methods(http.MethodGet).
Name("get-log-level").
HandlerFunc(utils.WrapHandlerFunc(getLogLevelHandler(logLevel)))

sub.Path("/loglevel").
Methods(http.MethodPost).
Name("post-log-level").
HandlerFunc(utils.WrapHandlerFunc(postLogLevelHandler(logLevel)))

return handlers.CompressHandler(router)
}

func StartAdminServer(addr string, logLevel *slog.LevelVar) (string, func(), error) {
func StartAdminServer(addr string, logLevel *slog.LevelVar, health *health.Health) (string, func(), error) {
listener, err := net.Listen("tcp", addr)
if err != nil {
return "", nil, errors.Wrapf(err, "listen admin API addr [%v]", addr)
}

router := mux.NewRouter()
router.PathPrefix("/admin").Handler(HTTPHandler(logLevel))
handler := handlers.CompressHandler(router)
adminHandler := admin.New(logLevel, health)

srv := &http.Server{Handler: handler, ReadHeaderTimeout: time.Second, ReadTimeout: 5 * time.Second}
srv := &http.Server{Handler: adminHandler, ReadHeaderTimeout: time.Second, ReadTimeout: 5 * time.Second}
var goes co.Goes
goes.Go(func() {
srv.Serve(listener)
Expand Down
6 changes: 0 additions & 6 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/vechain/thor/v2/api/debug"
"github.com/vechain/thor/v2/api/doc"
"github.com/vechain/thor/v2/api/events"
"github.com/vechain/thor/v2/api/health"
"github.com/vechain/thor/v2/api/node"
"github.com/vechain/thor/v2/api/subscriptions"
"github.com/vechain/thor/v2/api/transactions"
Expand All @@ -29,8 +28,6 @@ import (
"github.com/vechain/thor/v2/state"
"github.com/vechain/thor/v2/thor"
"github.com/vechain/thor/v2/txpool"

healthstatus "github.com/vechain/thor/v2/health"
)

var logger = log.WithContext("pkg", "api")
Expand All @@ -43,7 +40,6 @@ func New(
logDB *logdb.LogDB,
bft bft.Committer,
nw node.Network,
healthStatus *healthstatus.Health,
forkConfig thor.ForkConfig,
allowedOrigins string,
backtraceLimit uint32,
Expand Down Expand Up @@ -78,8 +74,6 @@ func New(
accounts.New(repo, stater, callGasLimit, forkConfig, bft).
Mount(router, "/accounts")

health.New(healthStatus).Mount(router, "/health")

if !skipLogs {
events.New(repo, logDB, logsLimit).
Mount(router, "/logs/event")
Expand Down
14 changes: 0 additions & 14 deletions api/blocks/blocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package blocks_test

import (
"encoding/json"
"io"
"math"
"math/big"
"net/http"
Expand Down Expand Up @@ -267,16 +266,3 @@ func checkExpandedBlock(t *testing.T, expBl *block.Block, actBl *blocks.JSONExpa
assert.Equal(t, tx.ID(), actBl.Transactions[i].ID, "txid should be equal")
}
}

func httpGet(t *testing.T, url string) ([]byte, int) {
res, err := http.Get(url) //#nosec G107
if err != nil {
t.Fatal(err)
}
r, err := io.ReadAll(res.Body)
res.Body.Close()
if err != nil {
t.Fatal(err)
}
return r, res.StatusCode
}
Loading

0 comments on commit b124448

Please sign in to comment.