api_test.go 23 KB

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