api_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739
  1. package api_test
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "net"
  7. "net/http"
  8. "net/http/httptest"
  9. "os"
  10. "path/filepath"
  11. "runtime"
  12. "strconv"
  13. "testing"
  14. "time"
  15. "github.com/go-chi/render"
  16. _ "github.com/go-sql-driver/mysql"
  17. _ "github.com/lib/pq"
  18. _ "github.com/mattn/go-sqlite3"
  19. "github.com/rs/zerolog"
  20. "github.com/drakkan/sftpgo/api"
  21. "github.com/drakkan/sftpgo/config"
  22. "github.com/drakkan/sftpgo/dataprovider"
  23. "github.com/drakkan/sftpgo/logger"
  24. "github.com/drakkan/sftpgo/sftpd"
  25. )
  26. const (
  27. defaultUsername = "test_user"
  28. defaultPassword = "test_password"
  29. testPubKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1"
  30. logSender = "APITesting"
  31. userPath = "/api/v1/user"
  32. activeConnectionsPath = "/api/v1/sftp_connection"
  33. quotaScanPath = "/api/v1/quota_scan"
  34. )
  35. var (
  36. defaultPerms = []string{dataprovider.PermAny}
  37. homeBasePath string
  38. testServer *httptest.Server
  39. )
  40. func TestMain(m *testing.M) {
  41. if runtime.GOOS == "windows" {
  42. homeBasePath = "C:\\"
  43. } else {
  44. homeBasePath = "/tmp"
  45. }
  46. configDir := ".."
  47. logfilePath := filepath.Join(configDir, "sftpgo_api_test.log")
  48. confName := "sftpgo.conf"
  49. logger.InitLogger(logfilePath, 5, 1, 28, false, zerolog.DebugLevel)
  50. configFilePath := filepath.Join(configDir, confName)
  51. config.LoadConfig(configFilePath)
  52. providerConf := config.GetProviderConf()
  53. err := dataprovider.Initialize(providerConf, configDir)
  54. if err != nil {
  55. logger.Warn(logSender, "error initializing data provider: %v", err)
  56. os.Exit(1)
  57. }
  58. dataProvider := dataprovider.GetProvider()
  59. httpdConf := config.GetHTTPDConfig()
  60. router := api.GetHTTPRouter()
  61. httpdConf.BindPort = 8081
  62. api.SetBaseURL("http://127.0.0.1:8081")
  63. sftpd.SetDataProvider(dataProvider)
  64. api.SetDataProvider(dataProvider)
  65. go func() {
  66. logger.Debug(logSender, "initializing HTTP server with config %+v", httpdConf)
  67. s := &http.Server{
  68. Addr: fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort),
  69. Handler: router,
  70. ReadTimeout: 300 * time.Second,
  71. WriteTimeout: 300 * time.Second,
  72. MaxHeaderBytes: 1 << 20, // 1MB
  73. }
  74. if err := s.ListenAndServe(); err != nil {
  75. logger.Error(logSender, "could not start HTTP server: %v", err)
  76. }
  77. }()
  78. testServer = httptest.NewServer(api.GetHTTPRouter())
  79. defer testServer.Close()
  80. waitTCPListening(fmt.Sprintf("%s:%d", httpdConf.BindAddress, httpdConf.BindPort))
  81. exitCode := m.Run()
  82. os.Remove(logfilePath)
  83. os.Exit(exitCode)
  84. }
  85. func TestBasicUserHandling(t *testing.T) {
  86. user, _, err := api.AddUser(getTestUser(), http.StatusOK)
  87. if err != nil {
  88. t.Errorf("unable to add user: %v", err)
  89. }
  90. user.MaxSessions = 10
  91. user.QuotaSize = 4096
  92. user.QuotaFiles = 2
  93. user.UploadBandwidth = 128
  94. user.DownloadBandwidth = 64
  95. user, _, err = api.UpdateUser(user, http.StatusOK)
  96. if err != nil {
  97. t.Errorf("unable to update user: %v", err)
  98. }
  99. users, _, err := api.GetUsers(0, 0, defaultUsername, http.StatusOK)
  100. if err != nil {
  101. t.Errorf("unable to get users: %v", err)
  102. }
  103. if len(users) != 1 {
  104. t.Errorf("number of users mismatch, expected: 1, actual: %v", len(users))
  105. }
  106. _, err = api.RemoveUser(user, http.StatusOK)
  107. if err != nil {
  108. t.Errorf("unable to remove: %v", err)
  109. }
  110. }
  111. func TestAddUserNoCredentials(t *testing.T) {
  112. u := getTestUser()
  113. u.Password = ""
  114. u.PublicKey = []string{}
  115. _, _, err := api.AddUser(u, http.StatusBadRequest)
  116. if err != nil {
  117. t.Errorf("unexpected error adding user with no credentials: %v", err)
  118. }
  119. }
  120. func TestAddUserNoUsername(t *testing.T) {
  121. u := getTestUser()
  122. u.Username = ""
  123. _, _, err := api.AddUser(u, http.StatusBadRequest)
  124. if err != nil {
  125. t.Errorf("unexpected error adding user with no home dir: %v", err)
  126. }
  127. }
  128. func TestAddUserNoHomeDir(t *testing.T) {
  129. u := getTestUser()
  130. u.HomeDir = ""
  131. _, _, err := api.AddUser(u, http.StatusBadRequest)
  132. if err != nil {
  133. t.Errorf("unexpected error adding user with no home dir: %v", err)
  134. }
  135. }
  136. func TestAddUserInvalidHomeDir(t *testing.T) {
  137. u := getTestUser()
  138. u.HomeDir = "relative_path"
  139. _, _, err := api.AddUser(u, http.StatusBadRequest)
  140. if err != nil {
  141. t.Errorf("unexpected error adding user with invalid home dir: %v", err)
  142. }
  143. }
  144. func TestAddUserNoPerms(t *testing.T) {
  145. u := getTestUser()
  146. u.Permissions = []string{}
  147. _, _, err := api.AddUser(u, http.StatusBadRequest)
  148. if err != nil {
  149. t.Errorf("unexpected error adding user with no perms: %v", err)
  150. }
  151. }
  152. func TestAddUserInvalidPerms(t *testing.T) {
  153. u := getTestUser()
  154. u.Permissions = []string{"invalidPerm"}
  155. _, _, err := api.AddUser(u, http.StatusBadRequest)
  156. if err != nil {
  157. t.Errorf("unexpected error adding user with no perms: %v", err)
  158. }
  159. }
  160. func TestUserPublicKey(t *testing.T) {
  161. u := getTestUser()
  162. invalidPubKey := "invalid"
  163. validPubKey := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC03jj0D+djk7pxIf/0OhrxrchJTRZklofJ1NoIu4752Sq02mdXmarMVsqJ1cAjV5LBVy3D1F5U6XW4rppkXeVtd04Pxb09ehtH0pRRPaoHHlALiJt8CoMpbKYMA8b3KXPPriGxgGomvtU2T2RMURSwOZbMtpsugfjYSWenyYX+VORYhylWnSXL961LTyC21ehd6d6QnW9G7E5hYMITMY9TuQZz3bROYzXiTsgN0+g6Hn7exFQp50p45StUMfV/SftCMdCxlxuyGny2CrN/vfjO7xxOo2uv7q1qm10Q46KPWJQv+pgZ/OfL+EDjy07n5QVSKHlbx+2nT4Q0EgOSQaCTYwn3YjtABfIxWwgAFdyj6YlPulCL22qU4MYhDcA6PSBwDdf8hvxBfvsiHdM+JcSHvv8/VeJhk6CmnZxGY0fxBupov27z3yEO8nAg8k+6PaUiW1MSUfuGMF/ktB8LOstXsEPXSszuyXiOv4DaryOXUiSn7bmRqKcEFlJusO6aZP0= nicola@p1"
  164. u.PublicKey = []string{invalidPubKey}
  165. _, _, err := api.AddUser(u, http.StatusBadRequest)
  166. if err != nil {
  167. t.Errorf("unexpected error adding user with invalid pub key: %v", err)
  168. }
  169. u.PublicKey = []string{validPubKey}
  170. user, _, err := api.AddUser(u, http.StatusOK)
  171. if err != nil {
  172. t.Errorf("unable to add user: %v", err)
  173. }
  174. user.PublicKey = []string{validPubKey, invalidPubKey}
  175. _, _, err = api.UpdateUser(user, http.StatusBadRequest)
  176. if err != nil {
  177. t.Errorf("update user with invalid public key must fail: %v", err)
  178. }
  179. user.PublicKey = []string{validPubKey, validPubKey, validPubKey}
  180. _, _, err = api.UpdateUser(user, http.StatusOK)
  181. if err != nil {
  182. t.Errorf("unable to update user: %v", err)
  183. }
  184. _, err = api.RemoveUser(user, http.StatusOK)
  185. if err != nil {
  186. t.Errorf("unable to remove: %v", err)
  187. }
  188. }
  189. func TestUpdateUser(t *testing.T) {
  190. user, _, err := api.AddUser(getTestUser(), http.StatusOK)
  191. if err != nil {
  192. t.Errorf("unable to add user: %v", err)
  193. }
  194. user.HomeDir = filepath.Join(homeBasePath, "testmod")
  195. user.UID = 33
  196. user.GID = 101
  197. user.MaxSessions = 10
  198. user.QuotaSize = 4096
  199. user.QuotaFiles = 2
  200. user.Permissions = []string{dataprovider.PermCreateDirs, dataprovider.PermDelete, dataprovider.PermDownload}
  201. user.UploadBandwidth = 1024
  202. user.DownloadBandwidth = 512
  203. user, _, err = api.UpdateUser(user, http.StatusOK)
  204. if err != nil {
  205. t.Errorf("unable to update user: %v", err)
  206. }
  207. _, err = api.RemoveUser(user, http.StatusOK)
  208. if err != nil {
  209. t.Errorf("unable to remove: %v", err)
  210. }
  211. }
  212. func TestUpdateUserNoCredentials(t *testing.T) {
  213. user, _, err := api.AddUser(getTestUser(), http.StatusOK)
  214. if err != nil {
  215. t.Errorf("unable to add user: %v", err)
  216. }
  217. user.Password = ""
  218. user.PublicKey = []string{}
  219. // password and public key will be omitted from json serialization if empty and so they will remain unchanged
  220. // and no validation error will be raised
  221. _, _, err = api.UpdateUser(user, http.StatusOK)
  222. if err != nil {
  223. t.Errorf("unexpected error updating user with no credentials: %v", err)
  224. }
  225. _, err = api.RemoveUser(user, http.StatusOK)
  226. if err != nil {
  227. t.Errorf("unable to remove: %v", err)
  228. }
  229. }
  230. func TestUpdateUserEmptyHomeDir(t *testing.T) {
  231. user, _, err := api.AddUser(getTestUser(), http.StatusOK)
  232. if err != nil {
  233. t.Errorf("unable to add user: %v", err)
  234. }
  235. user.HomeDir = ""
  236. _, _, err = api.UpdateUser(user, http.StatusBadRequest)
  237. if err != nil {
  238. t.Errorf("unexpected error updating user with empty home dir: %v", err)
  239. }
  240. _, err = api.RemoveUser(user, http.StatusOK)
  241. if err != nil {
  242. t.Errorf("unable to remove: %v", err)
  243. }
  244. }
  245. func TestUpdateUserInvalidHomeDir(t *testing.T) {
  246. user, _, err := api.AddUser(getTestUser(), http.StatusOK)
  247. if err != nil {
  248. t.Errorf("unable to add user: %v", err)
  249. }
  250. user.HomeDir = "relative_path"
  251. _, _, err = api.UpdateUser(user, http.StatusBadRequest)
  252. if err != nil {
  253. t.Errorf("unexpected error updating user with empty home dir: %v", err)
  254. }
  255. _, err = api.RemoveUser(user, http.StatusOK)
  256. if err != nil {
  257. t.Errorf("unable to remove: %v", err)
  258. }
  259. }
  260. func TestUpdateNonExistentUser(t *testing.T) {
  261. _, _, err := api.UpdateUser(getTestUser(), http.StatusNotFound)
  262. if err != nil {
  263. t.Errorf("unable to update user: %v", err)
  264. }
  265. }
  266. func TestGetNonExistentUser(t *testing.T) {
  267. _, _, err := api.GetUserByID(0, http.StatusNotFound)
  268. if err != nil {
  269. t.Errorf("unable to get user: %v", err)
  270. }
  271. }
  272. func TestDeleteNonExistentUser(t *testing.T) {
  273. _, err := api.RemoveUser(getTestUser(), http.StatusNotFound)
  274. if err != nil {
  275. t.Errorf("unable to remove user: %v", err)
  276. }
  277. }
  278. func TestAddDuplicateUser(t *testing.T) {
  279. user, _, err := api.AddUser(getTestUser(), http.StatusOK)
  280. if err != nil {
  281. t.Errorf("unable to add user: %v", err)
  282. }
  283. _, _, err = api.AddUser(getTestUser(), http.StatusInternalServerError)
  284. if err != nil {
  285. t.Errorf("unable to add second user: %v", err)
  286. }
  287. _, _, err = api.AddUser(getTestUser(), http.StatusOK)
  288. if err == nil {
  289. t.Errorf("adding a duplicate user must fail")
  290. }
  291. _, err = api.RemoveUser(user, http.StatusOK)
  292. if err != nil {
  293. t.Errorf("unable to remove user: %v", err)
  294. }
  295. }
  296. func TestGetUsers(t *testing.T) {
  297. user1, _, err := api.AddUser(getTestUser(), http.StatusOK)
  298. if err != nil {
  299. t.Errorf("unable to add user: %v", err)
  300. }
  301. u := getTestUser()
  302. u.Username = defaultUsername + "1"
  303. user2, _, err := api.AddUser(u, http.StatusOK)
  304. if err != nil {
  305. t.Errorf("unable to add second user: %v", err)
  306. }
  307. users, _, err := api.GetUsers(0, 0, "", http.StatusOK)
  308. if err != nil {
  309. t.Errorf("unable to get users: %v", err)
  310. }
  311. if len(users) < 2 {
  312. t.Errorf("at least 2 users are expected")
  313. }
  314. users, _, err = api.GetUsers(1, 0, "", http.StatusOK)
  315. if err != nil {
  316. t.Errorf("unable to get users: %v", err)
  317. }
  318. if len(users) != 1 {
  319. t.Errorf("1 user is expected")
  320. }
  321. users, _, err = api.GetUsers(1, 1, "", http.StatusOK)
  322. if err != nil {
  323. t.Errorf("unable to get users: %v", err)
  324. }
  325. if len(users) != 1 {
  326. t.Errorf("1 user is expected")
  327. }
  328. _, _, err = api.GetUsers(1, 1, "", http.StatusInternalServerError)
  329. if err == nil {
  330. t.Errorf("get users must succeed, we requested a fail for a good request")
  331. }
  332. _, err = api.RemoveUser(user1, http.StatusOK)
  333. if err != nil {
  334. t.Errorf("unable to remove user: %v", err)
  335. }
  336. _, err = api.RemoveUser(user2, http.StatusOK)
  337. if err != nil {
  338. t.Errorf("unable to remove user: %v", err)
  339. }
  340. }
  341. func TestGetQuotaScans(t *testing.T) {
  342. _, _, err := api.GetQuotaScans(http.StatusOK)
  343. if err != nil {
  344. t.Errorf("unable to get quota scans: %v", err)
  345. }
  346. _, _, err = api.GetQuotaScans(http.StatusInternalServerError)
  347. if err == nil {
  348. t.Errorf("quota scan request must succeed, we requested to check a wrong status code")
  349. }
  350. }
  351. func TestStartQuotaScan(t *testing.T) {
  352. user, _, err := api.AddUser(getTestUser(), http.StatusOK)
  353. if err != nil {
  354. t.Errorf("unable to add user: %v", err)
  355. }
  356. _, err = api.StartQuotaScan(user, http.StatusCreated)
  357. if err != nil {
  358. t.Errorf("unable to start quota scan: %v", err)
  359. }
  360. _, err = api.RemoveUser(user, http.StatusOK)
  361. if err != nil {
  362. t.Errorf("unable to remove user: %v", err)
  363. }
  364. }
  365. func TestGetSFTPConnections(t *testing.T) {
  366. _, _, err := api.GetSFTPConnections(http.StatusOK)
  367. if err != nil {
  368. t.Errorf("unable to get sftp connections: %v", err)
  369. }
  370. _, _, err = api.GetSFTPConnections(http.StatusInternalServerError)
  371. if err == nil {
  372. t.Errorf("get sftp connections request must succeed, we requested to check a wrong status code")
  373. }
  374. }
  375. func TestCloseActiveSFTPConnection(t *testing.T) {
  376. _, err := api.CloseSFTPConnection("non_existent_id", http.StatusNotFound)
  377. if err != nil {
  378. t.Errorf("unexpected error closing non existent sftp connection: %v", err)
  379. }
  380. }
  381. // test using mock http server
  382. func TestBasicUserHandlingMock(t *testing.T) {
  383. user := getTestUser()
  384. userAsJSON := getUserAsJSON(t, user)
  385. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  386. rr := executeRequest(req)
  387. checkResponseCode(t, http.StatusOK, rr.Code)
  388. err := render.DecodeJSON(rr.Body, &user)
  389. if err != nil {
  390. t.Errorf("Error get user: %v", err)
  391. }
  392. req, _ = http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  393. rr = executeRequest(req)
  394. checkResponseCode(t, http.StatusInternalServerError, rr.Code)
  395. user.MaxSessions = 10
  396. user.UploadBandwidth = 128
  397. userAsJSON = getUserAsJSON(t, user)
  398. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
  399. rr = executeRequest(req)
  400. checkResponseCode(t, http.StatusOK, rr.Code)
  401. req, _ = http.NewRequest(http.MethodGet, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  402. rr = executeRequest(req)
  403. checkResponseCode(t, http.StatusOK, rr.Code)
  404. var updatedUser dataprovider.User
  405. err = render.DecodeJSON(rr.Body, &updatedUser)
  406. if err != nil {
  407. t.Errorf("Error decoding updated user: %v", err)
  408. }
  409. if user.MaxSessions != updatedUser.MaxSessions || user.UploadBandwidth != updatedUser.UploadBandwidth {
  410. t.Errorf("Error modifying user actual: %v, %v", updatedUser.MaxSessions, updatedUser.UploadBandwidth)
  411. }
  412. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  413. rr = executeRequest(req)
  414. checkResponseCode(t, http.StatusOK, rr.Code)
  415. }
  416. func TestGetUserByIdInvalidParamsMock(t *testing.T) {
  417. req, _ := http.NewRequest(http.MethodGet, userPath+"/0", nil)
  418. rr := executeRequest(req)
  419. checkResponseCode(t, http.StatusNotFound, rr.Code)
  420. req, _ = http.NewRequest(http.MethodGet, userPath+"/a", nil)
  421. rr = executeRequest(req)
  422. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  423. }
  424. func TestAddUserNoUsernameMock(t *testing.T) {
  425. user := getTestUser()
  426. user.Username = ""
  427. userAsJSON := getUserAsJSON(t, user)
  428. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  429. rr := executeRequest(req)
  430. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  431. }
  432. func TestAddUserInvalidHomeDirMock(t *testing.T) {
  433. user := getTestUser()
  434. user.HomeDir = "relative_path"
  435. userAsJSON := getUserAsJSON(t, user)
  436. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  437. rr := executeRequest(req)
  438. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  439. }
  440. func TestAddUserInvalidPermsMock(t *testing.T) {
  441. user := getTestUser()
  442. user.Permissions = []string{}
  443. userAsJSON := getUserAsJSON(t, user)
  444. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  445. rr := executeRequest(req)
  446. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  447. }
  448. func TestAddUserInvalidJsonMock(t *testing.T) {
  449. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer([]byte("invalid json")))
  450. rr := executeRequest(req)
  451. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  452. }
  453. func TestUpdateUserInvalidJsonMock(t *testing.T) {
  454. user := getTestUser()
  455. userAsJSON := getUserAsJSON(t, user)
  456. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  457. rr := executeRequest(req)
  458. checkResponseCode(t, http.StatusOK, rr.Code)
  459. err := render.DecodeJSON(rr.Body, &user)
  460. if err != nil {
  461. t.Errorf("Error get user: %v", err)
  462. }
  463. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer([]byte("Invalid json")))
  464. rr = executeRequest(req)
  465. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  466. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  467. rr = executeRequest(req)
  468. checkResponseCode(t, http.StatusOK, rr.Code)
  469. }
  470. func TestUpdateUserInvalidParamsMock(t *testing.T) {
  471. user := getTestUser()
  472. userAsJSON := getUserAsJSON(t, user)
  473. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  474. rr := executeRequest(req)
  475. checkResponseCode(t, http.StatusOK, rr.Code)
  476. err := render.DecodeJSON(rr.Body, &user)
  477. if err != nil {
  478. t.Errorf("Error get user: %v", err)
  479. }
  480. user.HomeDir = ""
  481. userAsJSON = getUserAsJSON(t, user)
  482. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(user.ID, 10), bytes.NewBuffer(userAsJSON))
  483. rr = executeRequest(req)
  484. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  485. userID := user.ID
  486. user.ID = 0
  487. userAsJSON = getUserAsJSON(t, user)
  488. req, _ = http.NewRequest(http.MethodPut, userPath+"/"+strconv.FormatInt(userID, 10), bytes.NewBuffer(userAsJSON))
  489. rr = executeRequest(req)
  490. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  491. user.ID = userID
  492. req, _ = http.NewRequest(http.MethodPut, userPath+"/0", bytes.NewBuffer(userAsJSON))
  493. rr = executeRequest(req)
  494. checkResponseCode(t, http.StatusNotFound, rr.Code)
  495. req, _ = http.NewRequest(http.MethodPut, userPath+"/a", bytes.NewBuffer(userAsJSON))
  496. rr = executeRequest(req)
  497. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  498. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  499. rr = executeRequest(req)
  500. checkResponseCode(t, http.StatusOK, rr.Code)
  501. }
  502. func TestGetUsersMock(t *testing.T) {
  503. user := getTestUser()
  504. userAsJSON := getUserAsJSON(t, user)
  505. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  506. rr := executeRequest(req)
  507. checkResponseCode(t, http.StatusOK, rr.Code)
  508. err := render.DecodeJSON(rr.Body, &user)
  509. if err != nil {
  510. t.Errorf("Error get user: %v", err)
  511. }
  512. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=510&offset=0&order=ASC&username="+defaultUsername, nil)
  513. rr = executeRequest(req)
  514. checkResponseCode(t, http.StatusOK, rr.Code)
  515. var users []dataprovider.User
  516. err = render.DecodeJSON(rr.Body, &users)
  517. if err != nil {
  518. t.Errorf("Error decoding users: %v", err)
  519. }
  520. if len(users) != 1 {
  521. t.Errorf("1 user is expected")
  522. }
  523. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=a&offset=0&order=ASC", nil)
  524. rr = executeRequest(req)
  525. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  526. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=a&order=ASC", nil)
  527. rr = executeRequest(req)
  528. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  529. req, _ = http.NewRequest(http.MethodGet, userPath+"?limit=1&offset=0&order=ASCa", nil)
  530. rr = executeRequest(req)
  531. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  532. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  533. rr = executeRequest(req)
  534. checkResponseCode(t, http.StatusOK, rr.Code)
  535. }
  536. func TestDeleteUserInvalidParamsMock(t *testing.T) {
  537. req, _ := http.NewRequest(http.MethodDelete, userPath+"/0", nil)
  538. rr := executeRequest(req)
  539. checkResponseCode(t, http.StatusNotFound, rr.Code)
  540. req, _ = http.NewRequest(http.MethodDelete, userPath+"/a", nil)
  541. rr = executeRequest(req)
  542. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  543. }
  544. func TestGetQuotaScansMock(t *testing.T) {
  545. req, err := http.NewRequest("GET", quotaScanPath, nil)
  546. if err != nil {
  547. t.Errorf("error get quota scan: %v", err)
  548. }
  549. rr := executeRequest(req)
  550. checkResponseCode(t, http.StatusOK, rr.Code)
  551. }
  552. func TestStartQuotaScanMock(t *testing.T) {
  553. user := getTestUser()
  554. userAsJSON := getUserAsJSON(t, user)
  555. req, _ := http.NewRequest(http.MethodPost, userPath, bytes.NewBuffer(userAsJSON))
  556. rr := executeRequest(req)
  557. checkResponseCode(t, http.StatusOK, rr.Code)
  558. err := render.DecodeJSON(rr.Body, &user)
  559. if err != nil {
  560. t.Errorf("Error get user: %v", err)
  561. }
  562. _, err = os.Stat(user.HomeDir)
  563. if err == nil {
  564. os.Remove(user.HomeDir)
  565. }
  566. // simulate a duplicate quota scan
  567. userAsJSON = getUserAsJSON(t, user)
  568. sftpd.AddQuotaScan(user.Username)
  569. req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
  570. rr = executeRequest(req)
  571. checkResponseCode(t, http.StatusConflict, rr.Code)
  572. sftpd.RemoveQuotaScan(user.Username)
  573. userAsJSON = getUserAsJSON(t, user)
  574. req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
  575. rr = executeRequest(req)
  576. checkResponseCode(t, http.StatusCreated, rr.Code)
  577. req, _ = http.NewRequest(http.MethodGet, quotaScanPath, nil)
  578. rr = executeRequest(req)
  579. checkResponseCode(t, http.StatusOK, rr.Code)
  580. var scans []sftpd.ActiveQuotaScan
  581. err = render.DecodeJSON(rr.Body, &scans)
  582. if err != nil {
  583. t.Errorf("Error get active scans: %v", err)
  584. }
  585. for len(scans) > 0 {
  586. req, _ = http.NewRequest(http.MethodGet, quotaScanPath, nil)
  587. rr = executeRequest(req)
  588. checkResponseCode(t, http.StatusOK, rr.Code)
  589. err = render.DecodeJSON(rr.Body, &scans)
  590. if err != nil {
  591. t.Errorf("Error get active scans: %v", err)
  592. break
  593. }
  594. }
  595. _, err = os.Stat(user.HomeDir)
  596. if err != nil && os.IsNotExist(err) {
  597. os.MkdirAll(user.HomeDir, 0777)
  598. }
  599. req, _ = http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
  600. rr = executeRequest(req)
  601. checkResponseCode(t, http.StatusCreated, rr.Code)
  602. req, _ = http.NewRequest(http.MethodDelete, userPath+"/"+strconv.FormatInt(user.ID, 10), nil)
  603. rr = executeRequest(req)
  604. checkResponseCode(t, http.StatusOK, rr.Code)
  605. }
  606. func TestStartQuotaScanBadUserMock(t *testing.T) {
  607. user := getTestUser()
  608. userAsJSON := getUserAsJSON(t, user)
  609. req, _ := http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer(userAsJSON))
  610. rr := executeRequest(req)
  611. checkResponseCode(t, http.StatusNotFound, rr.Code)
  612. }
  613. func TestStartQuotaScanNonExistentUserMock(t *testing.T) {
  614. req, _ := http.NewRequest(http.MethodPost, quotaScanPath, bytes.NewBuffer([]byte("invalid json")))
  615. rr := executeRequest(req)
  616. checkResponseCode(t, http.StatusBadRequest, rr.Code)
  617. }
  618. func TestGetSFTPConnectionsMock(t *testing.T) {
  619. req, _ := http.NewRequest(http.MethodGet, activeConnectionsPath, nil)
  620. rr := executeRequest(req)
  621. checkResponseCode(t, http.StatusOK, rr.Code)
  622. }
  623. func TestDeleteActiveConnectionMock(t *testing.T) {
  624. req, _ := http.NewRequest(http.MethodDelete, activeConnectionsPath+"/connectionID", nil)
  625. rr := executeRequest(req)
  626. checkResponseCode(t, http.StatusNotFound, rr.Code)
  627. }
  628. func TestNotFoundMock(t *testing.T) {
  629. req, _ := http.NewRequest(http.MethodGet, "/non/existing/path", nil)
  630. rr := executeRequest(req)
  631. checkResponseCode(t, http.StatusNotFound, rr.Code)
  632. }
  633. func TestMethodNotAllowedMock(t *testing.T) {
  634. req, _ := http.NewRequest(http.MethodPost, activeConnectionsPath, nil)
  635. rr := executeRequest(req)
  636. checkResponseCode(t, http.StatusMethodNotAllowed, rr.Code)
  637. }
  638. func waitTCPListening(address string) {
  639. for {
  640. conn, err := net.Dial("tcp", address)
  641. if err != nil {
  642. logger.WarnToConsole("tcp server %v not listening: %v\n", address, err)
  643. time.Sleep(100 * time.Millisecond)
  644. continue
  645. }
  646. logger.InfoToConsole("tcp server %v now listening\n", address)
  647. defer conn.Close()
  648. break
  649. }
  650. }
  651. func getTestUser() dataprovider.User {
  652. return dataprovider.User{
  653. Username: defaultUsername,
  654. Password: defaultPassword,
  655. HomeDir: filepath.Join(homeBasePath, defaultUsername),
  656. Permissions: defaultPerms,
  657. }
  658. }
  659. func getUserAsJSON(t *testing.T, user dataprovider.User) []byte {
  660. json, err := json.Marshal(user)
  661. if err != nil {
  662. t.Errorf("error get user as json: %v", err)
  663. return []byte("{}")
  664. }
  665. return json
  666. }
  667. func executeRequest(req *http.Request) *httptest.ResponseRecorder {
  668. rr := httptest.NewRecorder()
  669. testServer.Config.Handler.ServeHTTP(rr, req)
  670. return rr
  671. }
  672. func checkResponseCode(t *testing.T, expected, actual int) {
  673. if expected != actual {
  674. t.Errorf("Expected response code %d. Got %d", expected, actual)
  675. }
  676. }