user_test.go 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "net/http"
  6. "os"
  7. "sync"
  8. "testing"
  9. "time"
  10. controller "github.com/gravitl/netmaker/controllers"
  11. "github.com/gravitl/netmaker/models"
  12. "github.com/gravitl/netmaker/mongoconn"
  13. "github.com/stretchr/testify/assert"
  14. )
  15. type databaseError struct {
  16. Inner *int
  17. Errors int
  18. }
  19. //should be use models.SuccessResponse and models.SuccessfulUserLoginResponse
  20. //rather than creating new type but having trouble decoding that way
  21. type Auth struct {
  22. Username string
  23. AuthToken string
  24. }
  25. type Success struct {
  26. Code int
  27. Message string
  28. Response Auth
  29. }
  30. type AuthorizeTestCase struct {
  31. testname string
  32. name string
  33. password string
  34. code int
  35. tokenExpected bool
  36. errMessage string
  37. }
  38. func TestMain(m *testing.M) {
  39. mongoconn.ConnectDatabase()
  40. var waitgroup sync.WaitGroup
  41. waitgroup.Add(1)
  42. go controller.HandleRESTRequests(&waitgroup)
  43. //wait for http server to start
  44. time.Sleep(time.Second * 1)
  45. os.Exit(m.Run())
  46. }
  47. func TestAdminCreation(t *testing.T) {
  48. var admin models.UserAuthParams
  49. var user models.User
  50. admin.UserName = "admin"
  51. admin.Password = "password"
  52. t.Run("AdminCreationSuccess", func(t *testing.T) {
  53. if adminExists(t) {
  54. deleteAdmin(t)
  55. }
  56. response, err := api(t, admin, http.MethodPost, "http://localhost:8081/users/createadmin", "")
  57. assert.Nil(t, err, err)
  58. defer response.Body.Close()
  59. err = json.NewDecoder(response.Body).Decode(&user)
  60. assert.Nil(t, err, err)
  61. assert.Equal(t, admin.UserName, user.UserName)
  62. assert.Equal(t, true, user.IsAdmin)
  63. assert.Equal(t, http.StatusOK, response.StatusCode)
  64. assert.True(t, adminExists(t), "Admin creation failed")
  65. })
  66. t.Run("AdminCreationFailure", func(t *testing.T) {
  67. if !adminExists(t) {
  68. addAdmin(t)
  69. }
  70. response, err := api(t, admin, http.MethodPost, "http://localhost:8081/users/createadmin", "")
  71. assert.Nil(t, err, err)
  72. defer response.Body.Close()
  73. var message models.ErrorResponse
  74. err = json.NewDecoder(response.Body).Decode(&message)
  75. assert.Nil(t, err, err)
  76. assert.Equal(t, http.StatusUnauthorized, response.StatusCode)
  77. assert.Equal(t, http.StatusUnauthorized, message.Code)
  78. assert.Equal(t, "W1R3: Admin already exists! ", message.Message)
  79. })
  80. }
  81. func TestGetUser(t *testing.T) {
  82. //ensure admin exists
  83. if !adminExists(t) {
  84. addAdmin(t)
  85. }
  86. //authenticate
  87. t.Run("GetUserWithValidToken", func(t *testing.T) {
  88. token, err := authenticate(t)
  89. assert.Nil(t, err, err)
  90. response, err := api(t, "", http.MethodGet, "http://localhost:8081/users/admin", token)
  91. assert.Nil(t, err, err)
  92. defer response.Body.Close()
  93. var user models.User
  94. json.NewDecoder(response.Body).Decode(&user)
  95. assert.Equal(t, http.StatusOK, response.StatusCode)
  96. assert.Equal(t, "admin", user.UserName)
  97. assert.Equal(t, true, user.IsAdmin)
  98. })
  99. t.Run("GetUserWithInvalidToken", func(t *testing.T) {
  100. response, err := api(t, "", http.MethodGet, "http://localhost:8081/users/admin", "secretkey")
  101. assert.Nil(t, err, err)
  102. defer response.Body.Close()
  103. t.Log(response.Body)
  104. })
  105. }
  106. func TestUpdateUser(t *testing.T) {
  107. if !adminExists(t) {
  108. addAdmin(t)
  109. }
  110. token, err := authenticate(t)
  111. assert.Nil(t, err, err)
  112. var admin models.UserAuthParams
  113. var user models.User
  114. var message models.ErrorResponse
  115. t.Run("UpdateWrongToken", func(t *testing.T) {
  116. admin.UserName = "admin"
  117. admin.Password = "admin"
  118. response, err := api(t, admin, http.MethodPut, "http://localhost:8081/users/admin", "secretkey")
  119. assert.Nil(t, err, err)
  120. defer response.Body.Close()
  121. err = json.NewDecoder(response.Body).Decode(&message)
  122. assert.Nil(t, err, err)
  123. assert.Equal(t, "W1R3: Error Verifying Auth Token.", message.Message)
  124. assert.Equal(t, http.StatusUnauthorized, response.StatusCode)
  125. })
  126. t.Run("UpdateSuccess", func(t *testing.T) {
  127. admin.UserName = "admin"
  128. admin.Password = "password"
  129. response, err := api(t, admin, http.MethodPut, "http://localhost:8081/users/admin", token)
  130. assert.Nil(t, err, err)
  131. defer response.Body.Close()
  132. err = json.NewDecoder(response.Body).Decode(&user)
  133. assert.Nil(t, err, err)
  134. assert.Equal(t, admin.UserName, user.UserName)
  135. assert.Equal(t, true, user.IsAdmin)
  136. assert.Equal(t, http.StatusOK, response.StatusCode)
  137. })
  138. }
  139. func TestDeleteUser(t *testing.T) {
  140. if !adminExists(t) {
  141. addAdmin(t)
  142. }
  143. token, err := authenticate(t)
  144. assert.Nil(t, err, err)
  145. t.Run("DeleteUser-WongAdmin", func(t *testing.T) {
  146. //skip for now ... shouldn't panic
  147. t.Skip()
  148. function := func() {
  149. _, _ = api(t, "", http.MethodDelete, "http://localhost:8081/users/xxxx", token)
  150. }
  151. assert.Panics(t, function, "")
  152. })
  153. t.Run("DeleteUser-InvalidCredentials", func(t *testing.T) {
  154. response, err := api(t, "", http.MethodDelete, "http://localhost:8081/users/admin", "secretkey")
  155. assert.Nil(t, err, err)
  156. var message models.ErrorResponse
  157. json.NewDecoder(response.Body).Decode(&message)
  158. assert.Equal(t, "W1R3: Error Verifying Auth Token.", message.Message)
  159. assert.Equal(t, http.StatusUnauthorized, response.StatusCode)
  160. })
  161. t.Run("DeleteUser-ValidCredentials", func(t *testing.T) {
  162. response, err := api(t, "", http.MethodDelete, "http://localhost:8081/users/admin", token)
  163. assert.Nil(t, err, err)
  164. var body string
  165. json.NewDecoder(response.Body).Decode(&body)
  166. assert.Equal(t, "admin deleted.", body)
  167. assert.Equal(t, http.StatusOK, response.StatusCode)
  168. })
  169. t.Run("DeleteUser-NoAdmin", func(t *testing.T) {
  170. //skip for now ... shouldn't panic
  171. t.Skip()
  172. function := func() {
  173. _, _ = api(t, "", http.MethodDelete, "http://localhost:8081/users/admin", token)
  174. }
  175. assert.Panics(t, function, "")
  176. })
  177. addAdmin(t)
  178. }
  179. func TestAuthenticateUser(t *testing.T) {
  180. cases := []AuthorizeTestCase{
  181. AuthorizeTestCase{
  182. testname: "Invalid User",
  183. name: "invaliduser",
  184. password: "password",
  185. code: http.StatusBadRequest,
  186. tokenExpected: false,
  187. errMessage: "W1R3: User invaliduser not found.",
  188. },
  189. AuthorizeTestCase{
  190. testname: "empty user",
  191. name: "",
  192. password: "password",
  193. code: http.StatusBadRequest,
  194. tokenExpected: false,
  195. errMessage: "W1R3: Username can't be empty",
  196. },
  197. AuthorizeTestCase{
  198. testname: "empty password",
  199. name: "admin",
  200. password: "",
  201. code: http.StatusBadRequest,
  202. tokenExpected: false,
  203. errMessage: "W1R3: Password can't be empty",
  204. },
  205. AuthorizeTestCase{
  206. testname: "Invalid Password",
  207. name: "admin",
  208. password: "xxxxxxx",
  209. code: http.StatusUnauthorized,
  210. tokenExpected: false,
  211. errMessage: "W1R3: Wrong Password.",
  212. },
  213. AuthorizeTestCase{
  214. testname: "Valid User",
  215. name: "admin",
  216. password: "password",
  217. code: http.StatusOK,
  218. tokenExpected: true,
  219. errMessage: "W1R3: Device Admin Authorized",
  220. },
  221. }
  222. if !adminExists(t) {
  223. addAdmin(t)
  224. }
  225. for _, tc := range cases {
  226. t.Run(tc.testname, func(t *testing.T) {
  227. var admin models.User
  228. admin.UserName = tc.name
  229. admin.Password = tc.password
  230. response, err := api(t, admin, http.MethodPost, "http://localhost:8081/users/authenticate", "secretkey")
  231. assert.Nil(t, err, err)
  232. defer response.Body.Close()
  233. if tc.tokenExpected {
  234. var body Success
  235. err = json.NewDecoder(response.Body).Decode(&body)
  236. assert.Nil(t, err, err)
  237. assert.NotEmpty(t, body.Response.AuthToken, "token not returned")
  238. assert.Equal(t, "W1R3: Device admin Authorized", body.Message)
  239. } else {
  240. var bad models.ErrorResponse
  241. json.NewDecoder(response.Body).Decode(&bad)
  242. assert.Equal(t, tc.errMessage, bad.Message)
  243. }
  244. assert.Equal(t, tc.code, response.StatusCode)
  245. })
  246. }
  247. }
  248. func adminExists(t *testing.T) bool {
  249. response, err := http.Get("http://localhost:8081/users/hasadmin")
  250. assert.Nil(t, err, err)
  251. assert.Equal(t, http.StatusOK, response.StatusCode)
  252. defer response.Body.Close()
  253. var body bool
  254. json.NewDecoder(response.Body).Decode(&body)
  255. return body
  256. }
  257. func api(t *testing.T, data interface{}, method, url, authorization string) (*http.Response, error) {
  258. var request *http.Request
  259. var err error
  260. if data != "" {
  261. payload, err := json.Marshal(data)
  262. assert.Nil(t, err, err)
  263. request, err = http.NewRequest(method, url, bytes.NewBuffer(payload))
  264. assert.Nil(t, err, err)
  265. request.Header.Set("Content-Type", "application/json")
  266. } else {
  267. request, err = http.NewRequest(method, url, nil)
  268. assert.Nil(t, err, err)
  269. }
  270. if authorization != "" {
  271. request.Header.Set("Authorization", "Bearer "+authorization)
  272. }
  273. client := http.Client{}
  274. return client.Do(request)
  275. }
  276. func addAdmin(t *testing.T) {
  277. var admin models.User
  278. admin.UserName = "admin"
  279. admin.Password = "password"
  280. response, err := api(t, admin, http.MethodPost, "http://localhost:8081/users/createadmin", "secretkey")
  281. assert.Nil(t, err, err)
  282. assert.Equal(t, http.StatusOK, response.StatusCode)
  283. }
  284. func authenticate(t *testing.T) (string, error) {
  285. var admin models.User
  286. admin.UserName = "admin"
  287. admin.Password = "password"
  288. response, err := api(t, admin, http.MethodPost, "http://localhost:8081/users/authenticate", "secretkey")
  289. assert.Nil(t, err, err)
  290. var body Success
  291. err = json.NewDecoder(response.Body).Decode(&body)
  292. assert.Nil(t, err, err)
  293. assert.NotEmpty(t, body.Response.AuthToken, "token not returned")
  294. assert.Equal(t, "W1R3: Device admin Authorized", body.Message)
  295. return body.Response.AuthToken, nil
  296. }
  297. func deleteAdmin(t *testing.T) {
  298. if !adminExists(t) {
  299. return
  300. }
  301. token, err := authenticate(t)
  302. assert.Nil(t, err, err)
  303. _, err = api(t, "", http.MethodDelete, "http://localhost:8081/users/admin", token)
  304. assert.Nil(t, err, err)
  305. }