mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-28 21:26:40 +00:00
568 lines
19 KiB
Go
568 lines
19 KiB
Go
package instance
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/mail"
|
|
"testing"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/netbirdio/netbird/management/server/account"
|
|
"github.com/netbirdio/netbird/management/server/idp"
|
|
nbinstance "github.com/netbirdio/netbird/management/server/instance"
|
|
"github.com/netbirdio/netbird/management/server/mock_server"
|
|
"github.com/netbirdio/netbird/management/server/types"
|
|
"github.com/netbirdio/netbird/shared/auth"
|
|
"github.com/netbirdio/netbird/shared/management/http/api"
|
|
"github.com/netbirdio/netbird/shared/management/status"
|
|
)
|
|
|
|
// mockInstanceManager implements instance.Manager for testing
|
|
type mockInstanceManager struct {
|
|
isSetupRequired bool
|
|
isSetupRequiredFn func(ctx context.Context) (bool, error)
|
|
createOwnerUserFn func(ctx context.Context, email, password, name string) (*idp.UserData, error)
|
|
rollbackSetupFn func(ctx context.Context, userID string) error
|
|
getVersionInfoFn func(ctx context.Context) (*nbinstance.VersionInfo, error)
|
|
}
|
|
|
|
func (m *mockInstanceManager) IsSetupRequired(ctx context.Context) (bool, error) {
|
|
if m.isSetupRequiredFn != nil {
|
|
return m.isSetupRequiredFn(ctx)
|
|
}
|
|
return m.isSetupRequired, nil
|
|
}
|
|
|
|
func (m *mockInstanceManager) CreateOwnerUser(ctx context.Context, email, password, name string) (*idp.UserData, error) {
|
|
if m.createOwnerUserFn != nil {
|
|
return m.createOwnerUserFn(ctx, email, password, name)
|
|
}
|
|
|
|
// Default mock includes validation like the real manager
|
|
if !m.isSetupRequired {
|
|
return nil, status.Errorf(status.PreconditionFailed, "setup already completed")
|
|
}
|
|
if email == "" {
|
|
return nil, status.Errorf(status.InvalidArgument, "email is required")
|
|
}
|
|
if _, err := mail.ParseAddress(email); err != nil {
|
|
return nil, status.Errorf(status.InvalidArgument, "invalid email format")
|
|
}
|
|
if name == "" {
|
|
return nil, status.Errorf(status.InvalidArgument, "name is required")
|
|
}
|
|
if password == "" {
|
|
return nil, status.Errorf(status.InvalidArgument, "password is required")
|
|
}
|
|
if len(password) < 8 {
|
|
return nil, status.Errorf(status.InvalidArgument, "password must be at least 8 characters")
|
|
}
|
|
|
|
return &idp.UserData{
|
|
ID: "test-user-id",
|
|
Email: email,
|
|
Name: name,
|
|
}, nil
|
|
}
|
|
|
|
func (m *mockInstanceManager) RollbackSetup(ctx context.Context, userID string) error {
|
|
if m.rollbackSetupFn != nil {
|
|
return m.rollbackSetupFn(ctx, userID)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (m *mockInstanceManager) GetVersionInfo(ctx context.Context) (*nbinstance.VersionInfo, error) {
|
|
if m.getVersionInfoFn != nil {
|
|
return m.getVersionInfoFn(ctx)
|
|
}
|
|
return &nbinstance.VersionInfo{
|
|
CurrentVersion: "0.34.0",
|
|
DashboardVersion: "2.0.0",
|
|
ManagementVersion: "0.35.0",
|
|
ManagementUpdateAvailable: true,
|
|
}, nil
|
|
}
|
|
|
|
var _ nbinstance.Manager = (*mockInstanceManager)(nil)
|
|
|
|
func setupTestRouter(manager nbinstance.Manager) *mux.Router {
|
|
return setupTestRouterWithPAT(manager, nil)
|
|
}
|
|
|
|
func setupTestRouterWithPAT(manager nbinstance.Manager, accountManager account.Manager) *mux.Router {
|
|
router := mux.NewRouter()
|
|
AddEndpoints(manager, accountManager, router)
|
|
return router
|
|
}
|
|
|
|
func TestGetInstanceStatus_SetupRequired(t *testing.T) {
|
|
manager := &mockInstanceManager{isSetupRequired: true}
|
|
router := setupTestRouter(manager)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/instance", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
|
|
var response api.InstanceStatus
|
|
err := json.NewDecoder(rec.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
assert.True(t, response.SetupRequired)
|
|
}
|
|
|
|
func TestGetInstanceStatus_SetupNotRequired(t *testing.T) {
|
|
manager := &mockInstanceManager{isSetupRequired: false}
|
|
router := setupTestRouter(manager)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/instance", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
|
|
var response api.InstanceStatus
|
|
err := json.NewDecoder(rec.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
assert.False(t, response.SetupRequired)
|
|
}
|
|
|
|
func TestGetInstanceStatus_Error(t *testing.T) {
|
|
manager := &mockInstanceManager{
|
|
isSetupRequiredFn: func(ctx context.Context) (bool, error) {
|
|
return false, errors.New("database error")
|
|
},
|
|
}
|
|
router := setupTestRouter(manager)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/instance", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, rec.Code)
|
|
}
|
|
|
|
func TestSetup_Success(t *testing.T) {
|
|
manager := &mockInstanceManager{
|
|
isSetupRequired: true,
|
|
createOwnerUserFn: func(ctx context.Context, email, password, name string) (*idp.UserData, error) {
|
|
assert.Equal(t, "admin@example.com", email)
|
|
assert.Equal(t, "securepassword123", password)
|
|
assert.Equal(t, "Admin User", name)
|
|
return &idp.UserData{
|
|
ID: "created-user-id",
|
|
Email: email,
|
|
Name: name,
|
|
}, nil
|
|
},
|
|
}
|
|
router := setupTestRouter(manager)
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "Admin User"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
assert.Equal(t, "no-store", rec.Header().Get("Cache-Control"))
|
|
|
|
var response api.SetupResponse
|
|
err := json.NewDecoder(rec.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "created-user-id", response.UserId)
|
|
assert.Equal(t, "admin@example.com", response.Email)
|
|
}
|
|
|
|
func TestSetup_AlreadyCompleted(t *testing.T) {
|
|
manager := &mockInstanceManager{isSetupRequired: false}
|
|
router := setupTestRouter(manager)
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusPreconditionFailed, rec.Code)
|
|
}
|
|
|
|
func TestSetup_MissingEmail(t *testing.T) {
|
|
manager := &mockInstanceManager{isSetupRequired: true}
|
|
router := setupTestRouter(manager)
|
|
|
|
body := `{"password": "securepassword123"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusUnprocessableEntity, rec.Code)
|
|
}
|
|
|
|
func TestSetup_InvalidEmail(t *testing.T) {
|
|
manager := &mockInstanceManager{isSetupRequired: true}
|
|
router := setupTestRouter(manager)
|
|
|
|
body := `{"email": "not-an-email", "password": "securepassword123", "name": "User"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
// Note: Invalid email format uses mail.ParseAddress which is treated differently
|
|
// and returns 400 Bad Request instead of 422 Unprocessable Entity
|
|
assert.Equal(t, http.StatusUnprocessableEntity, rec.Code)
|
|
}
|
|
|
|
func TestSetup_MissingPassword(t *testing.T) {
|
|
manager := &mockInstanceManager{isSetupRequired: true}
|
|
router := setupTestRouter(manager)
|
|
|
|
body := `{"email": "admin@example.com", "name": "User"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusUnprocessableEntity, rec.Code)
|
|
}
|
|
|
|
func TestSetup_PasswordTooShort(t *testing.T) {
|
|
manager := &mockInstanceManager{isSetupRequired: true}
|
|
router := setupTestRouter(manager)
|
|
|
|
body := `{"email": "admin@example.com", "password": "short", "name": "User"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusUnprocessableEntity, rec.Code)
|
|
}
|
|
|
|
func TestSetup_InvalidJSON(t *testing.T) {
|
|
manager := &mockInstanceManager{isSetupRequired: true}
|
|
router := setupTestRouter(manager)
|
|
|
|
body := `{invalid json}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, rec.Code)
|
|
}
|
|
|
|
func TestSetup_CreateUserError(t *testing.T) {
|
|
manager := &mockInstanceManager{
|
|
isSetupRequired: true,
|
|
createOwnerUserFn: func(ctx context.Context, email, password, name string) (*idp.UserData, error) {
|
|
return nil, errors.New("user creation failed")
|
|
},
|
|
}
|
|
router := setupTestRouter(manager)
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "User"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, rec.Code)
|
|
}
|
|
|
|
func TestSetup_ManagerError(t *testing.T) {
|
|
manager := &mockInstanceManager{
|
|
isSetupRequired: true,
|
|
createOwnerUserFn: func(ctx context.Context, email, password, name string) (*idp.UserData, error) {
|
|
return nil, status.Errorf(status.Internal, "database error")
|
|
},
|
|
}
|
|
router := setupTestRouter(manager)
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "User"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, rec.Code)
|
|
}
|
|
|
|
func TestSetup_PAT_FeatureDisabled_IgnoresCreatePAT(t *testing.T) {
|
|
t.Setenv(nbinstance.SetupPATEnabledEnvKey, "false")
|
|
|
|
manager := &mockInstanceManager{isSetupRequired: true}
|
|
// NB_SETUP_PAT_ENABLED=false: request fields must be silently ignored
|
|
router := setupTestRouterWithPAT(manager, &mock_server.MockAccountManager{})
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "Admin", "create_pat": true}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
var response api.SetupResponse
|
|
require.NoError(t, json.NewDecoder(rec.Body).Decode(&response))
|
|
assert.Nil(t, response.PersonalAccessToken)
|
|
}
|
|
|
|
func TestSetup_PAT_FlagOmitted_NoPAT(t *testing.T) {
|
|
t.Setenv(nbinstance.SetupPATEnabledEnvKey, "true")
|
|
|
|
manager := &mockInstanceManager{isSetupRequired: true}
|
|
router := setupTestRouterWithPAT(manager, &mock_server.MockAccountManager{})
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "Admin"}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
var response api.SetupResponse
|
|
require.NoError(t, json.NewDecoder(rec.Body).Decode(&response))
|
|
assert.Nil(t, response.PersonalAccessToken)
|
|
}
|
|
|
|
func TestSetup_PAT_MissingExpireIn_DefaultsToOneDay(t *testing.T) {
|
|
t.Setenv(nbinstance.SetupPATEnabledEnvKey, "true")
|
|
|
|
createCalled := false
|
|
manager := &mockInstanceManager{
|
|
isSetupRequired: true,
|
|
createOwnerUserFn: func(ctx context.Context, email, password, name string) (*idp.UserData, error) {
|
|
createCalled = true
|
|
return &idp.UserData{ID: "u1", Email: email, Name: name}, nil
|
|
},
|
|
}
|
|
accountMgr := &mock_server.MockAccountManager{
|
|
GetAccountIDByUserIdFunc: func(_ context.Context, userAuth auth.UserAuth) (string, error) {
|
|
assert.Equal(t, "u1", userAuth.UserId)
|
|
return "acc-1", nil
|
|
},
|
|
CreatePATFunc: func(_ context.Context, accountID, initiator, target, name string, expiresIn int) (*types.PersonalAccessTokenGenerated, error) {
|
|
assert.Equal(t, "acc-1", accountID)
|
|
assert.Equal(t, "u1", initiator)
|
|
assert.Equal(t, "u1", target)
|
|
assert.Equal(t, "setup-token", name)
|
|
assert.Equal(t, 1, expiresIn)
|
|
return &types.PersonalAccessTokenGenerated{PlainToken: "nbp_plain"}, nil
|
|
},
|
|
}
|
|
router := setupTestRouterWithPAT(manager, accountMgr)
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "Admin", "create_pat": true}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
assert.True(t, createCalled)
|
|
var response api.SetupResponse
|
|
require.NoError(t, json.NewDecoder(rec.Body).Decode(&response))
|
|
require.NotNil(t, response.PersonalAccessToken)
|
|
assert.Equal(t, "nbp_plain", *response.PersonalAccessToken)
|
|
}
|
|
|
|
func TestSetup_PAT_ExpireOutOfRange(t *testing.T) {
|
|
t.Setenv(nbinstance.SetupPATEnabledEnvKey, "true")
|
|
|
|
manager := &mockInstanceManager{isSetupRequired: true}
|
|
router := setupTestRouterWithPAT(manager, &mock_server.MockAccountManager{})
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "Admin", "create_pat": true, "pat_expire_in": 0}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusUnprocessableEntity, rec.Code)
|
|
}
|
|
|
|
func TestSetup_PAT_Success(t *testing.T) {
|
|
t.Setenv(nbinstance.SetupPATEnabledEnvKey, "true")
|
|
|
|
manager := &mockInstanceManager{
|
|
isSetupRequired: true,
|
|
createOwnerUserFn: func(ctx context.Context, email, password, name string) (*idp.UserData, error) {
|
|
return &idp.UserData{ID: "owner-id", Email: email, Name: name}, nil
|
|
},
|
|
}
|
|
|
|
gotAccountArgs := struct {
|
|
userID string
|
|
email string
|
|
}{}
|
|
accountMgr := &mock_server.MockAccountManager{
|
|
GetAccountIDByUserIdFunc: func(_ context.Context, userAuth auth.UserAuth) (string, error) {
|
|
gotAccountArgs.userID = userAuth.UserId
|
|
gotAccountArgs.email = userAuth.Email
|
|
return "acc-1", nil
|
|
},
|
|
CreatePATFunc: func(_ context.Context, accountID, initiator, target, name string, expiresIn int) (*types.PersonalAccessTokenGenerated, error) {
|
|
assert.Equal(t, "acc-1", accountID)
|
|
assert.Equal(t, "owner-id", initiator)
|
|
assert.Equal(t, "owner-id", target)
|
|
assert.Equal(t, "setup-token", name)
|
|
assert.Equal(t, 30, expiresIn)
|
|
return &types.PersonalAccessTokenGenerated{PlainToken: "nbp_plain"}, nil
|
|
},
|
|
}
|
|
|
|
router := setupTestRouterWithPAT(manager, accountMgr)
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "Admin", "create_pat": true, "pat_expire_in": 30}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
assert.Equal(t, "no-store", rec.Header().Get("Cache-Control"))
|
|
var response api.SetupResponse
|
|
require.NoError(t, json.NewDecoder(rec.Body).Decode(&response))
|
|
assert.Equal(t, "owner-id", response.UserId)
|
|
require.NotNil(t, response.PersonalAccessToken)
|
|
assert.Equal(t, "nbp_plain", *response.PersonalAccessToken)
|
|
assert.Equal(t, "owner-id", gotAccountArgs.userID)
|
|
}
|
|
|
|
func TestSetup_PAT_AccountCreationFails_Rollback(t *testing.T) {
|
|
t.Setenv(nbinstance.SetupPATEnabledEnvKey, "true")
|
|
|
|
rolledBackFor := ""
|
|
manager := &mockInstanceManager{
|
|
isSetupRequired: true,
|
|
createOwnerUserFn: func(ctx context.Context, email, password, name string) (*idp.UserData, error) {
|
|
return &idp.UserData{ID: "owner-id", Email: email, Name: name}, nil
|
|
},
|
|
rollbackSetupFn: func(_ context.Context, userID string) error {
|
|
rolledBackFor = userID
|
|
return nil
|
|
},
|
|
}
|
|
accountMgr := &mock_server.MockAccountManager{
|
|
GetAccountIDByUserIdFunc: func(_ context.Context, _ auth.UserAuth) (string, error) {
|
|
return "", errors.New("db down")
|
|
},
|
|
}
|
|
|
|
router := setupTestRouterWithPAT(manager, accountMgr)
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "Admin", "create_pat": true, "pat_expire_in": 30}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, rec.Code)
|
|
assert.Equal(t, "owner-id", rolledBackFor, "RollbackSetup must be called with the created user id")
|
|
}
|
|
|
|
func TestSetup_PAT_CreatePATFails_Rollback(t *testing.T) {
|
|
t.Setenv(nbinstance.SetupPATEnabledEnvKey, "true")
|
|
|
|
rolledBackFor := ""
|
|
manager := &mockInstanceManager{
|
|
isSetupRequired: true,
|
|
createOwnerUserFn: func(ctx context.Context, email, password, name string) (*idp.UserData, error) {
|
|
return &idp.UserData{ID: "owner-id", Email: email, Name: name}, nil
|
|
},
|
|
rollbackSetupFn: func(_ context.Context, userID string) error {
|
|
rolledBackFor = userID
|
|
return nil
|
|
},
|
|
}
|
|
accountMgr := &mock_server.MockAccountManager{
|
|
GetAccountIDByUserIdFunc: func(_ context.Context, _ auth.UserAuth) (string, error) {
|
|
return "acc-1", nil
|
|
},
|
|
CreatePATFunc: func(_ context.Context, _, _, _, _ string, _ int) (*types.PersonalAccessTokenGenerated, error) {
|
|
return nil, status.Errorf(status.Internal, "token store unavailable")
|
|
},
|
|
}
|
|
|
|
router := setupTestRouterWithPAT(manager, accountMgr)
|
|
|
|
body := `{"email": "admin@example.com", "password": "securepassword123", "name": "Admin", "create_pat": true, "pat_expire_in": 30}`
|
|
req := httptest.NewRequest(http.MethodPost, "/setup", bytes.NewBufferString(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, rec.Code)
|
|
assert.Equal(t, "owner-id", rolledBackFor, "RollbackSetup must be called when CreatePAT fails")
|
|
}
|
|
|
|
func TestGetVersionInfo_Success(t *testing.T) {
|
|
manager := &mockInstanceManager{}
|
|
router := mux.NewRouter()
|
|
AddVersionEndpoint(manager, router)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/instance/version", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusOK, rec.Code)
|
|
|
|
var response api.InstanceVersionInfo
|
|
err := json.NewDecoder(rec.Body).Decode(&response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "0.34.0", response.ManagementCurrentVersion)
|
|
assert.NotNil(t, response.DashboardAvailableVersion)
|
|
assert.Equal(t, "2.0.0", *response.DashboardAvailableVersion)
|
|
assert.NotNil(t, response.ManagementAvailableVersion)
|
|
assert.Equal(t, "0.35.0", *response.ManagementAvailableVersion)
|
|
assert.True(t, response.ManagementUpdateAvailable)
|
|
}
|
|
|
|
func TestGetVersionInfo_Error(t *testing.T) {
|
|
manager := &mockInstanceManager{
|
|
getVersionInfoFn: func(ctx context.Context) (*nbinstance.VersionInfo, error) {
|
|
return nil, errors.New("failed to fetch versions")
|
|
},
|
|
}
|
|
router := mux.NewRouter()
|
|
AddVersionEndpoint(manager, router)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/instance/version", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(rec, req)
|
|
|
|
assert.Equal(t, http.StatusInternalServerError, rec.Code)
|
|
}
|