Skip to content

Commit 344f6b6

Browse files
committed
feat: add tests
1 parent f7e7753 commit 344f6b6

File tree

3 files changed

+161
-1
lines changed

3 files changed

+161
-1
lines changed

api/go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ require (
1919
github.com/mattn/go-sqlite3 v1.14.22
2020
github.com/nqd/flat v0.2.0
2121
github.com/oschwald/geoip2-golang v1.11.0
22+
github.com/stretchr/testify v1.9.0
2223
golang.org/x/crypto v0.17.0
2324
)
2425

2526
require (
2627
github.com/bytedance/sonic v1.9.1 // indirect
2728
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
29+
github.com/davecgh/go-spew v1.1.1 // indirect
2830
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
2931
github.com/gin-contrib/sse v0.1.0 // indirect
3032
github.com/go-playground/locales v0.14.1 // indirect
@@ -44,6 +46,7 @@ require (
4446
github.com/modern-go/reflect2 v1.0.2 // indirect
4547
github.com/oschwald/maxminddb-golang v1.13.0 // indirect
4648
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
49+
github.com/pmezard/go-difflib v1.0.0 // indirect
4750
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
4851
github.com/ugorji/go/codec v1.2.11 // indirect
4952
golang.org/x/arch v0.3.0 // indirect

api/main.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import (
4343
// @schemes http
4444
// @BasePath /api
4545

46-
func main() {
46+
func setup() *gin.Engine {
4747
// init logs with syslog
4848
logs.Init("nethsecurity_controller")
4949

@@ -160,6 +160,11 @@ func main() {
160160
}))
161161
})
162162

163+
return router
164+
}
165+
166+
func main() {
167+
router := setup()
163168
// run server
164169
router.Run(configuration.Config.ListenAddress)
165170
}

api/main_test.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"net/http"
7+
"net/http/httptest"
8+
"os"
9+
"testing"
10+
11+
"github.com/NethServer/nethsecurity-controller/api/configuration"
12+
"github.com/gin-gonic/gin"
13+
"github.com/stretchr/testify/assert"
14+
)
15+
16+
func TestMainEndpoints(t *testing.T) {
17+
18+
gin.SetMode(gin.TestMode)
19+
router := setupRouter()
20+
var token string
21+
22+
t.Run("TestLoginEndpoint", func(t *testing.T) {
23+
w := httptest.NewRecorder()
24+
var jsonResponse map[string]interface{}
25+
body := `{"username": "admin", "password": "admin"}`
26+
req, _ := http.NewRequest("POST", "/login", bytes.NewBuffer([]byte(body)))
27+
req.Header.Set("Content-Type", "application/json")
28+
router.ServeHTTP(w, req)
29+
json.NewDecoder(w.Body).Decode(&jsonResponse)
30+
token = jsonResponse["token"].(string)
31+
assert.Equal(t, http.StatusOK, w.Code)
32+
assert.NotEmpty(t, token)
33+
})
34+
35+
t.Run("TestRefreshEndpoint", func(t *testing.T) {
36+
w := httptest.NewRecorder()
37+
req, _ := http.NewRequest("GET", "/refresh", nil)
38+
req.Header.Set("Authorization", "Bearer "+token)
39+
router.ServeHTTP(w, req)
40+
assert.Equal(t, http.StatusOK, w.Code)
41+
})
42+
43+
t.Run("TestGet2FAStatusEndpoint", func(t *testing.T) {
44+
w := httptest.NewRecorder()
45+
req, _ := http.NewRequest("GET", "/2fa", nil)
46+
req.Header.Set("Authorization", "Bearer "+token)
47+
router.ServeHTTP(w, req)
48+
assert.Equal(t, http.StatusOK, w.Code)
49+
})
50+
51+
t.Run("TestLogoutEndpoint", func(t *testing.T) {
52+
w := httptest.NewRecorder()
53+
req, _ := http.NewRequest("POST", "/logout", nil)
54+
req.Header.Set("Authorization", "Bearer "+token)
55+
router.ServeHTTP(w, req)
56+
assert.Equal(t, http.StatusOK, w.Code)
57+
})
58+
59+
t.Run("TestGetAccountsEndpoint", func(t *testing.T) {
60+
w := httptest.NewRecorder()
61+
req, _ := http.NewRequest("GET", "/accounts", nil)
62+
req.Header.Set("Authorization", "Bearer "+token)
63+
router.ServeHTTP(w, req)
64+
assert.Equal(t, http.StatusOK, w.Code)
65+
// response is: gin.H{"accounts": accounts, "total": len(accounts)},
66+
var jsonResponse map[string]interface{}
67+
json.NewDecoder(w.Body).Decode(&jsonResponse)
68+
data := jsonResponse["data"].(map[string]interface{})
69+
assert.Equal(t, int(data["total"].(float64)), 1)
70+
assert.Equal(t, data["accounts"].([]interface{})[0].(map[string]interface{})["username"], "admin")
71+
assert.Equal(t, data["accounts"].([]interface{})[0].(map[string]interface{})["display_name"], "Administrator")
72+
assert.Equal(t, data["accounts"].([]interface{})[0].(map[string]interface{})["two_fa"], false)
73+
})
74+
75+
t.Run("TestRegisterUnitEndpoint", func(t *testing.T) {
76+
// create credentials directory
77+
if _, err := os.Stat(configuration.Config.CredentialsDir); os.IsNotExist(err) {
78+
if err := os.MkdirAll(configuration.Config.CredentialsDir, 0755); err != nil {
79+
t.Fatalf("failed to create directory: %v", err)
80+
}
81+
}
82+
// make sure configuration.Config.OpenVPNPKIDir does not exists
83+
os.RemoveAll(configuration.Config.OpenVPNPKIDir)
84+
body := `{"unit_id": "11", "username": "aa", "unit_name": "bbb", "password": "ccc"}`
85+
req, _ := http.NewRequest("POST", "/units/register", bytes.NewBuffer([]byte(body)))
86+
req.Header.Set("Content-Type", "application/json")
87+
req.Header.Set("RegistrationToken", "1234")
88+
w := httptest.NewRecorder()
89+
router.ServeHTTP(w, req)
90+
assert.Equal(t, http.StatusForbidden, w.Code)
91+
92+
// create OpenVPN directory
93+
if _, err := os.Stat(configuration.Config.OpenVPNPKIDir + "/issued"); os.IsNotExist(err) {
94+
if err := os.MkdirAll(configuration.Config.OpenVPNPKIDir+"/issued", 0755); err != nil {
95+
t.Fatalf("failed to create directory: %v", err)
96+
}
97+
if err := os.MkdirAll(configuration.Config.OpenVPNPKIDir+"/private", 0755); err != nil {
98+
t.Fatalf("failed to create directory: %v", err)
99+
}
100+
}
101+
// create fake certificate file and key file
102+
if _, err := os.Create(configuration.Config.OpenVPNPKIDir + "/issued/" + "11" + ".crt"); err != nil {
103+
t.Fatalf("failed to create file: %v", err)
104+
}
105+
if _, err := os.Create(configuration.Config.OpenVPNPKIDir + "/private/" + "11" + ".key"); err != nil {
106+
t.Fatalf("failed to create file: %v", err)
107+
}
108+
// create face ca.crt file
109+
if _, err := os.Create(configuration.Config.OpenVPNPKIDir + "/ca.crt"); err != nil {
110+
t.Fatalf("failed to create file: %v", err)
111+
}
112+
req, _ = http.NewRequest("POST", "/units/register", bytes.NewBuffer([]byte(body)))
113+
req.Header.Set("Content-Type", "application/json")
114+
req.Header.Set("RegistrationToken", "1234")
115+
w = httptest.NewRecorder()
116+
router.ServeHTTP(w, req)
117+
assert.Equal(t, http.StatusOK, w.Code)
118+
})
119+
120+
t.Run("TestNoRoute", func(t *testing.T) {
121+
w := httptest.NewRecorder()
122+
req, _ := http.NewRequest("GET", "/nonexistent", nil)
123+
router.ServeHTTP(w, req)
124+
assert.Equal(t, http.StatusNotFound, w.Code)
125+
})
126+
}
127+
128+
func setupRouter() *gin.Engine {
129+
os.Setenv("LISTEN_ADDRESS", "0.0.0.0:8000")
130+
os.Setenv("ADMIN_USERNAME", "admin")
131+
// default password is "password"
132+
os.Setenv("ADMIN_PASSWORD", "admin")
133+
os.Setenv("SECRET_JWT", "secret")
134+
os.Setenv("TOKENS_DIR", "./tokens")
135+
os.Setenv("CREDENTIALS_DIR", "./credentials")
136+
os.Setenv("PROMTAIL_ADDRESS", "127.0.0.1")
137+
os.Setenv("PROMTAIL_PORT", "6565")
138+
os.Setenv("PROMETHEUS_PATH", "/prometheus")
139+
os.Setenv("WEBSSH_PATH", "webssh")
140+
os.Setenv("GRAFANA_PATH", "/grafana")
141+
os.Setenv("REGISTRATION_TOKEN", "1234")
142+
os.Setenv("DATA_DIR", "data")
143+
os.Setenv("OVPN_DIR", "ovpn")
144+
os.Setenv("REPORT_DB_URI", "postgres://report:password@127.0.0.1:5432/report")
145+
os.Setenv("GRAFANA_POSTGRES_PASSWORD", "password")
146+
os.Setenv("ISSUER_2FA", "test")
147+
os.Setenv("SECRETS_DIR", "data")
148+
149+
router := setup()
150+
151+
return router
152+
}

0 commit comments

Comments
 (0)