user_handler_test.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. package api_test
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "net/http/httptest"
  6. "reflect"
  7. "strings"
  8. "testing"
  9. "time"
  10. "github.com/go-chi/chi"
  11. "github.com/porter-dev/porter/internal/config"
  12. "github.com/porter-dev/porter/internal/models"
  13. "github.com/porter-dev/porter/internal/repository"
  14. "github.com/porter-dev/porter/internal/repository/test"
  15. "github.com/porter-dev/porter/server/api"
  16. "github.com/porter-dev/porter/server/router"
  17. sessionstore "github.com/porter-dev/porter/internal/auth"
  18. lr "github.com/porter-dev/porter/internal/logger"
  19. vr "github.com/porter-dev/porter/internal/validator"
  20. )
  21. type tester struct {
  22. app *api.App
  23. repo *repository.Repository
  24. store *sessionstore.PGStore
  25. router *chi.Mux
  26. req *http.Request
  27. rr *httptest.ResponseRecorder
  28. cookie *http.Cookie
  29. }
  30. type userTest struct {
  31. initializers []func(t *tester)
  32. msg string
  33. method string
  34. endpoint string
  35. body string
  36. expStatus int
  37. expBody string
  38. useCookie bool
  39. validators []func(c *userTest, tester *tester, t *testing.T)
  40. }
  41. func (t *tester) execute() {
  42. t.router.ServeHTTP(t.rr, t.req)
  43. }
  44. func (t *tester) reset() {
  45. t.rr = httptest.NewRecorder()
  46. t.req = nil
  47. }
  48. func (t *tester) createUserSession(email string, pw string) {
  49. req, _ := http.NewRequest(
  50. "POST",
  51. "/api/users",
  52. strings.NewReader(`{"email":"`+email+`","password":"`+pw+`"}`),
  53. )
  54. t.req = req
  55. t.execute()
  56. if cookies := t.rr.Result().Cookies(); len(cookies) > 0 {
  57. t.cookie = cookies[0]
  58. }
  59. t.reset()
  60. }
  61. func initUserDefault(tester *tester) {
  62. tester.createUserSession("belanger@getporter.dev", "hello")
  63. }
  64. func initUserWithClusters(tester *tester) {
  65. initUserDefault(tester)
  66. user, _ := tester.repo.User.ReadUserByEmail("belanger@getporter.dev")
  67. user.Clusters = []models.ClusterConfig{
  68. models.ClusterConfig{
  69. Name: "cluster-test",
  70. Server: "https://localhost",
  71. Context: "context-test",
  72. User: "test-admin",
  73. },
  74. }
  75. user.RawKubeConfig = []byte("apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin")
  76. tester.repo.User.UpdateUser(user)
  77. }
  78. func newTester(canQuery bool) *tester {
  79. appConf := config.Conf{
  80. Debug: true,
  81. Server: config.ServerConf{
  82. Port: 8080,
  83. CookieName: "porter",
  84. CookieSecret: []byte("secret"),
  85. TimeoutRead: time.Second * 5,
  86. TimeoutWrite: time.Second * 10,
  87. TimeoutIdle: time.Second * 15,
  88. },
  89. // unimportant here
  90. Db: config.DBConf{},
  91. }
  92. logger := lr.NewConsole(appConf.Debug)
  93. validator := vr.New()
  94. repo := test.NewRepository(canQuery)
  95. store, _ := sessionstore.NewStore(repo, appConf.Server)
  96. app := api.New(logger, repo, validator, store, appConf.Server.CookieName)
  97. r := router.New(app, store, appConf.Server.CookieName)
  98. return &tester{
  99. app: app,
  100. repo: repo,
  101. store: store,
  102. router: r,
  103. req: nil,
  104. rr: httptest.NewRecorder(),
  105. cookie: nil,
  106. }
  107. }
  108. func testUserRequests(t *testing.T, tests []*userTest, canQuery bool) {
  109. for _, c := range tests {
  110. // create a new tester
  111. tester := newTester(canQuery)
  112. // if there's an initializer, call it
  113. for _, init := range c.initializers {
  114. init(tester)
  115. }
  116. req, err := http.NewRequest(
  117. c.method,
  118. c.endpoint,
  119. strings.NewReader(c.body),
  120. )
  121. tester.req = req
  122. if c.useCookie {
  123. req.AddCookie(tester.cookie)
  124. }
  125. if err != nil {
  126. t.Fatal(err)
  127. }
  128. tester.execute()
  129. rr := tester.rr
  130. // first, check that the status matches
  131. if status := rr.Code; status != c.expStatus {
  132. t.Errorf("%s, handler returned wrong status code: got %v want %v",
  133. c.msg, status, c.expStatus)
  134. }
  135. // if there's a validator, call it
  136. for _, validate := range c.validators {
  137. validate(c, tester, t)
  138. }
  139. }
  140. }
  141. var createUserTests = []*userTest{
  142. &userTest{
  143. msg: "Create user",
  144. method: "POST",
  145. endpoint: "/api/users",
  146. body: `{
  147. "email": "belanger@getporter.dev",
  148. "password": "hello"
  149. }`,
  150. expStatus: http.StatusCreated,
  151. expBody: "",
  152. },
  153. &userTest{
  154. msg: "Create user invalid email",
  155. method: "POST",
  156. endpoint: "/api/users",
  157. body: `{
  158. "email": "notanemail",
  159. "password": "hello"
  160. }`,
  161. expStatus: http.StatusUnprocessableEntity,
  162. expBody: `{"code":601,"errors":["email validation failed"]}`,
  163. validators: []func(c *userTest, tester *tester, t *testing.T){
  164. BasicBodyValidator,
  165. },
  166. },
  167. &userTest{
  168. msg: "Create user missing field",
  169. method: "POST",
  170. endpoint: "/api/users",
  171. body: `{
  172. "password": "hello"
  173. }`,
  174. expStatus: http.StatusUnprocessableEntity,
  175. expBody: `{"code":601,"errors":["required validation failed"]}`,
  176. validators: []func(c *userTest, tester *tester, t *testing.T){
  177. BasicBodyValidator,
  178. },
  179. },
  180. &userTest{
  181. initializers: []func(tester *tester){
  182. initUserDefault,
  183. },
  184. msg: "Create user same email",
  185. method: "POST",
  186. endpoint: "/api/users",
  187. body: `{
  188. "email": "belanger@getporter.dev",
  189. "password": "hello"
  190. }`,
  191. expStatus: http.StatusUnprocessableEntity,
  192. expBody: `{"code":601,"errors":["email already taken"]}`,
  193. validators: []func(c *userTest, tester *tester, t *testing.T){
  194. BasicBodyValidator,
  195. },
  196. },
  197. &userTest{
  198. msg: "Create user invalid field type",
  199. method: "POST",
  200. endpoint: "/api/users",
  201. body: `{
  202. "email": "belanger@getporter.dev",
  203. "password": 0
  204. }`,
  205. expStatus: http.StatusBadRequest,
  206. expBody: `{"code":600,"errors":["could not process request"]}`,
  207. validators: []func(c *userTest, tester *tester, t *testing.T){
  208. BasicBodyValidator,
  209. },
  210. },
  211. }
  212. func TestHandleCreateUser(t *testing.T) {
  213. testUserRequests(t, createUserTests, true)
  214. }
  215. var createUserTestsWriteFail = []*userTest{
  216. &userTest{
  217. msg: "Create user db connection down",
  218. method: "POST",
  219. endpoint: "/api/users",
  220. body: `{
  221. "email": "belanger@getporter.dev",
  222. "password": "hello"
  223. }`,
  224. expStatus: http.StatusInternalServerError,
  225. expBody: `{"code":500,"errors":["could not read from database"]}`,
  226. validators: []func(c *userTest, tester *tester, t *testing.T){
  227. BasicBodyValidator,
  228. },
  229. },
  230. }
  231. func TestHandleCreateUserWriteFail(t *testing.T) {
  232. testUserRequests(t, createUserTestsWriteFail, false)
  233. }
  234. var loginUserTests = []*userTest{
  235. &userTest{
  236. initializers: []func(tester *tester){
  237. initUserDefault,
  238. },
  239. msg: "Login user successful",
  240. method: "POST",
  241. endpoint: "/api/login",
  242. body: `{
  243. "email": "belanger@getporter.dev",
  244. "password": "hello"
  245. }`,
  246. expStatus: http.StatusOK,
  247. expBody: ``,
  248. validators: []func(c *userTest, tester *tester, t *testing.T){
  249. BasicBodyValidator,
  250. },
  251. },
  252. &userTest{
  253. initializers: []func(tester *tester){
  254. initUserDefault,
  255. },
  256. msg: "Login user already logged in",
  257. method: "POST",
  258. endpoint: "/api/login",
  259. body: `{
  260. "email": "belanger@getporter.dev",
  261. "password": "hello"
  262. }`,
  263. expStatus: http.StatusOK,
  264. expBody: ``,
  265. useCookie: true,
  266. validators: []func(c *userTest, tester *tester, t *testing.T){
  267. BasicBodyValidator,
  268. },
  269. },
  270. &userTest{
  271. msg: "Login user unregistered email",
  272. method: "POST",
  273. endpoint: "/api/login",
  274. body: `{
  275. "email": "belanger@getporter.dev",
  276. "password": "hello"
  277. }`,
  278. expStatus: http.StatusUnauthorized,
  279. expBody: `{"code":401,"errors":["email not registered"]}`,
  280. validators: []func(c *userTest, tester *tester, t *testing.T){
  281. BasicBodyValidator,
  282. },
  283. },
  284. &userTest{
  285. initializers: []func(tester *tester){
  286. initUserDefault,
  287. },
  288. msg: "Login user incorrect password",
  289. method: "POST",
  290. endpoint: "/api/login",
  291. body: `{
  292. "email": "belanger@getporter.dev",
  293. "password": "notthepassword"
  294. }`,
  295. expStatus: http.StatusUnauthorized,
  296. expBody: `{"code":401,"errors":["incorrect password"]}`,
  297. useCookie: true,
  298. validators: []func(c *userTest, tester *tester, t *testing.T){
  299. BasicBodyValidator,
  300. },
  301. },
  302. }
  303. func TestHandleLoginUser(t *testing.T) {
  304. testUserRequests(t, loginUserTests, true)
  305. }
  306. var logoutUserTests = []*userTest{
  307. &userTest{
  308. initializers: []func(tester *tester){
  309. initUserDefault,
  310. },
  311. msg: "Logout user successful",
  312. method: "POST",
  313. endpoint: "/api/logout",
  314. body: `{
  315. "email": "belanger@getporter.dev",
  316. "password": "hello"
  317. }`,
  318. expStatus: http.StatusOK,
  319. expBody: ``,
  320. useCookie: true,
  321. validators: []func(c *userTest, tester *tester, t *testing.T){
  322. func(c *userTest, tester *tester, t *testing.T) {
  323. req, err := http.NewRequest(
  324. "GET",
  325. "/api/users/1",
  326. strings.NewReader(""),
  327. )
  328. req.AddCookie(tester.cookie)
  329. if err != nil {
  330. t.Fatal(err)
  331. }
  332. rr2 := httptest.NewRecorder()
  333. tester.router.ServeHTTP(rr2, req)
  334. if status := rr2.Code; status != http.StatusForbidden {
  335. t.Errorf("%s, handler returned wrong status: got %v want %v",
  336. "validator failed", status, http.StatusForbidden)
  337. }
  338. },
  339. },
  340. },
  341. }
  342. func TestHandleLogoutUser(t *testing.T) {
  343. testUserRequests(t, logoutUserTests, true)
  344. }
  345. var readUserTests = []*userTest{
  346. &userTest{
  347. initializers: []func(tester *tester){
  348. initUserWithClusters,
  349. },
  350. msg: "Read user successful",
  351. method: "GET",
  352. endpoint: "/api/users/1",
  353. body: "",
  354. expStatus: http.StatusOK,
  355. expBody: `{"id":1,"email":"belanger@getporter.dev","clusters":[{"name":"cluster-test","server":"https://localhost","context":"context-test","user":"test-admin"}],"rawKubeConfig":"apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin"}`,
  356. useCookie: true,
  357. validators: []func(c *userTest, tester *tester, t *testing.T){
  358. UserModelBodyValidator,
  359. },
  360. },
  361. &userTest{
  362. initializers: []func(tester *tester){
  363. initUserDefault,
  364. },
  365. msg: "Read user unauthorized",
  366. method: "GET",
  367. endpoint: "/api/users/2",
  368. body: "",
  369. expStatus: http.StatusForbidden,
  370. expBody: http.StatusText(http.StatusForbidden) + "\n",
  371. validators: []func(c *userTest, tester *tester, t *testing.T){
  372. BasicBodyValidator,
  373. },
  374. },
  375. }
  376. func TestHandleReadUser(t *testing.T) {
  377. testUserRequests(t, readUserTests, true)
  378. }
  379. var readUserClustersTests = []*userTest{
  380. &userTest{
  381. initializers: []func(tester *tester){
  382. initUserWithClusters,
  383. },
  384. msg: "Read user successful",
  385. method: "GET",
  386. endpoint: "/api/users/1/clusters",
  387. body: "",
  388. expStatus: http.StatusOK,
  389. useCookie: true,
  390. expBody: `[{"name":"cluster-test","server":"https://localhost","context":"context-test","user":"test-admin"}]`,
  391. validators: []func(c *userTest, tester *tester, t *testing.T){
  392. ClusterBodyValidator,
  393. },
  394. },
  395. }
  396. func TestHandleReadUserClusters(t *testing.T) {
  397. testUserRequests(t, readUserClustersTests, true)
  398. }
  399. var readUserClustersAllTests = []*userTest{
  400. &userTest{
  401. initializers: []func(tester *tester){
  402. initUserWithClusters,
  403. },
  404. msg: "Read user successful",
  405. method: "GET",
  406. endpoint: "/api/users/1/clusters/all",
  407. body: "",
  408. expStatus: http.StatusOK,
  409. useCookie: true,
  410. expBody: `[{"name":"cluster-test","server":"https://localhost","context":"context-test","user":"test-admin"}]`,
  411. validators: []func(c *userTest, tester *tester, t *testing.T){
  412. ClusterBodyValidator,
  413. },
  414. },
  415. &userTest{
  416. initializers: []func(tester *tester){
  417. initUserWithClusters,
  418. func(tester *tester) {
  419. initUserDefault(tester)
  420. user, _ := tester.repo.User.ReadUserByEmail("belanger@getporter.dev")
  421. user.Clusters = []models.ClusterConfig{}
  422. user.RawKubeConfig = []byte("apiVersion: \xc5\n")
  423. tester.repo.User.UpdateUser(user)
  424. },
  425. },
  426. msg: "Read user with invalid utf-8 \xc5 in kubeconfig",
  427. method: "GET",
  428. endpoint: "/api/users/1/clusters/all",
  429. body: "",
  430. expStatus: http.StatusBadRequest,
  431. useCookie: true,
  432. expBody: `{"code":600,"errors":["could not process request"]}`,
  433. validators: []func(c *userTest, tester *tester, t *testing.T){
  434. ClusterBodyValidator,
  435. },
  436. },
  437. }
  438. func TestHandleReadUserClustersAll(t *testing.T) {
  439. testUserRequests(t, readUserClustersAllTests, true)
  440. }
  441. var updateUserTests = []*userTest{
  442. &userTest{
  443. initializers: []func(tester *tester){
  444. initUserDefault,
  445. },
  446. msg: "Update user successful",
  447. method: "PUT",
  448. endpoint: "/api/users/1",
  449. body: `{"rawKubeConfig":"apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin", "allowedClusters":[]}`,
  450. expStatus: http.StatusNoContent,
  451. expBody: "",
  452. useCookie: true,
  453. validators: []func(c *userTest, tester *tester, t *testing.T){
  454. func(c *userTest, tester *tester, t *testing.T) {
  455. req, err := http.NewRequest(
  456. "GET",
  457. "/api/users/1",
  458. strings.NewReader(""),
  459. )
  460. req.AddCookie(tester.cookie)
  461. if err != nil {
  462. t.Fatal(err)
  463. }
  464. rr2 := httptest.NewRecorder()
  465. tester.router.ServeHTTP(rr2, req)
  466. gotBody := &models.UserExternal{}
  467. expBody := &models.UserExternal{}
  468. json.Unmarshal(rr2.Body.Bytes(), gotBody)
  469. json.Unmarshal([]byte(`{"id":1,"email":"belanger@getporter.dev","clusters":[],"rawKubeConfig":"apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin"}`), expBody)
  470. if !reflect.DeepEqual(gotBody, expBody) {
  471. t.Errorf("%s, handler returned wrong body: got %v want %v",
  472. "validator failed", gotBody, expBody)
  473. }
  474. },
  475. },
  476. },
  477. &userTest{
  478. initializers: []func(tester *tester){
  479. initUserDefault,
  480. },
  481. msg: "Update user successful without allowedClusters parameter",
  482. method: "PUT",
  483. endpoint: "/api/users/1",
  484. body: `{"rawKubeConfig":"apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin"}`,
  485. expStatus: http.StatusNoContent,
  486. expBody: "",
  487. useCookie: true,
  488. validators: []func(c *userTest, tester *tester, t *testing.T){
  489. func(c *userTest, tester *tester, t *testing.T) {
  490. req, err := http.NewRequest(
  491. "GET",
  492. "/api/users/1",
  493. strings.NewReader(""),
  494. )
  495. req.AddCookie(tester.cookie)
  496. if err != nil {
  497. t.Fatal(err)
  498. }
  499. rr2 := httptest.NewRecorder()
  500. tester.router.ServeHTTP(rr2, req)
  501. gotBody := &models.UserExternal{}
  502. expBody := &models.UserExternal{}
  503. json.Unmarshal(rr2.Body.Bytes(), gotBody)
  504. json.Unmarshal([]byte(`{"id":1,"email":"belanger@getporter.dev","clusters":[],"rawKubeConfig":"apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin"}`), expBody)
  505. if !reflect.DeepEqual(gotBody, expBody) {
  506. t.Errorf("%s, handler returned wrong body: got %v want %v",
  507. "validator failed", gotBody, expBody)
  508. }
  509. },
  510. },
  511. },
  512. &userTest{
  513. initializers: []func(tester *tester){
  514. initUserDefault,
  515. },
  516. msg: "Update user successful with allowedClusters",
  517. method: "PUT",
  518. endpoint: "/api/users/1",
  519. body: `{"rawKubeConfig":"apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin", "allowedClusters":["cluster-test"]}`,
  520. expStatus: http.StatusNoContent,
  521. expBody: "",
  522. useCookie: true,
  523. validators: []func(c *userTest, tester *tester, t *testing.T){
  524. func(c *userTest, tester *tester, t *testing.T) {
  525. req, err := http.NewRequest(
  526. "GET",
  527. "/api/users/1",
  528. strings.NewReader(""),
  529. )
  530. req.AddCookie(tester.cookie)
  531. if err != nil {
  532. t.Fatal(err)
  533. }
  534. rr2 := httptest.NewRecorder()
  535. tester.router.ServeHTTP(rr2, req)
  536. gotBody := &models.UserExternal{}
  537. expBody := &models.UserExternal{}
  538. json.Unmarshal(rr2.Body.Bytes(), gotBody)
  539. json.Unmarshal([]byte(`{"id":1,"email":"belanger@getporter.dev","clusters":[{"name":"cluster-test","server":"https://localhost","context":"context-test","user":"test-admin"}],"rawKubeConfig":"apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin"}`), expBody)
  540. if !reflect.DeepEqual(gotBody, expBody) {
  541. t.Errorf("%s, handler returned wrong body: got %v want %v",
  542. "validator failed", gotBody, expBody)
  543. }
  544. },
  545. },
  546. },
  547. &userTest{
  548. initializers: []func(tester *tester){
  549. initUserWithClusters,
  550. },
  551. msg: "Update user successful without rawKubeConfig",
  552. method: "PUT",
  553. endpoint: "/api/users/1",
  554. body: `{"allowedClusters":[]}`,
  555. expStatus: http.StatusNoContent,
  556. expBody: "",
  557. useCookie: true,
  558. validators: []func(c *userTest, tester *tester, t *testing.T){
  559. func(c *userTest, tester *tester, t *testing.T) {
  560. req, err := http.NewRequest(
  561. "GET",
  562. "/api/users/1",
  563. strings.NewReader(""),
  564. )
  565. req.AddCookie(tester.cookie)
  566. if err != nil {
  567. t.Fatal(err)
  568. }
  569. rr2 := httptest.NewRecorder()
  570. tester.router.ServeHTTP(rr2, req)
  571. gotBody := &models.UserExternal{}
  572. expBody := &models.UserExternal{}
  573. json.Unmarshal(rr2.Body.Bytes(), gotBody)
  574. json.Unmarshal([]byte(`{"id":1,"email":"belanger@getporter.dev","clusters":[],"rawKubeConfig":"apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin"}`), expBody)
  575. if !reflect.DeepEqual(gotBody, expBody) {
  576. t.Errorf("%s, handler returned wrong body: got %v want %v",
  577. "validator failed", gotBody, expBody)
  578. }
  579. },
  580. },
  581. },
  582. &userTest{
  583. initializers: []func(tester *tester){
  584. initUserDefault,
  585. },
  586. msg: "Update user invalid id",
  587. method: "PUT",
  588. endpoint: "/api/users/alsdfjk",
  589. body: `{"rawKubeConfig":"apiVersion: v1\nkind: Config\npreferences: {}\ncurrent-context: context-test\nclusters:\n- cluster:\n server: https://localhost\n name: cluster-test\ncontexts:\n- context:\n cluster: cluster-test\n user: test-admin\n name: context-test\nusers:\n- name: test-admin", "allowedClusters":[]}`,
  590. expStatus: http.StatusForbidden,
  591. expBody: http.StatusText(http.StatusForbidden) + "\n",
  592. validators: []func(c *userTest, tester *tester, t *testing.T){
  593. BasicBodyValidator,
  594. },
  595. },
  596. &userTest{
  597. initializers: []func(tester *tester){
  598. initUserDefault,
  599. },
  600. msg: "Update user bad kubeconfig",
  601. method: "PUT",
  602. endpoint: "/api/users/1",
  603. body: `{"rawKubeConfig":"notvalidyaml", "allowedClusters":[]}`,
  604. expStatus: http.StatusBadRequest,
  605. expBody: `{"code":600,"errors":["could not process request"]}`,
  606. useCookie: true,
  607. validators: []func(c *userTest, tester *tester, t *testing.T){
  608. BasicBodyValidator,
  609. },
  610. },
  611. }
  612. func TestHandleUpdateUser(t *testing.T) {
  613. testUserRequests(t, updateUserTests, true)
  614. }
  615. var deleteUserTests = []*userTest{
  616. &userTest{
  617. initializers: []func(tester *tester){
  618. initUserDefault,
  619. },
  620. msg: "Delete user successful",
  621. method: "DELETE",
  622. endpoint: "/api/users/1",
  623. body: `{"password":"hello"}`,
  624. expStatus: http.StatusNoContent,
  625. expBody: "",
  626. useCookie: true,
  627. validators: []func(c *userTest, tester *tester, t *testing.T){
  628. func(c *userTest, tester *tester, t *testing.T) {
  629. req, err := http.NewRequest(
  630. "GET",
  631. "/api/users/1",
  632. strings.NewReader(""),
  633. )
  634. req.AddCookie(tester.cookie)
  635. if err != nil {
  636. t.Fatal(err)
  637. }
  638. rr2 := httptest.NewRecorder()
  639. tester.router.ServeHTTP(rr2, req)
  640. gotBody := &models.UserExternal{}
  641. expBody := &models.UserExternal{}
  642. if status := rr2.Code; status != 404 {
  643. t.Errorf("DELETE user validation, handler returned wrong status code: got %v want %v",
  644. status, 404)
  645. }
  646. json.Unmarshal(rr2.Body.Bytes(), gotBody)
  647. json.Unmarshal([]byte(`{"code":602,"errors":["could not find requested object"]}`), expBody)
  648. if !reflect.DeepEqual(gotBody, expBody) {
  649. t.Errorf("%s, handler returned wrong body: got %v want %v",
  650. "validator failed", gotBody, expBody)
  651. }
  652. },
  653. },
  654. },
  655. &userTest{
  656. initializers: []func(tester *tester){
  657. initUserDefault,
  658. },
  659. msg: "Delete user invalid id",
  660. method: "DELETE",
  661. endpoint: "/api/users/aldkjf",
  662. body: `{"password":"hello"}`,
  663. expStatus: http.StatusForbidden,
  664. expBody: http.StatusText(http.StatusForbidden) + "\n",
  665. validators: []func(c *userTest, tester *tester, t *testing.T){
  666. BasicBodyValidator,
  667. },
  668. },
  669. &userTest{
  670. initializers: []func(tester *tester){
  671. initUserDefault,
  672. },
  673. msg: "Delete user missing password",
  674. method: "DELETE",
  675. endpoint: "/api/users/1",
  676. body: `{}`,
  677. expStatus: http.StatusUnprocessableEntity,
  678. expBody: `{"code":601,"errors":["required validation failed"]}`,
  679. useCookie: true,
  680. validators: []func(c *userTest, tester *tester, t *testing.T){
  681. BasicBodyValidator,
  682. },
  683. },
  684. }
  685. func TestHandleDeleteUser(t *testing.T) {
  686. testUserRequests(t, deleteUserTests, true)
  687. }
  688. func BasicBodyValidator(c *userTest, tester *tester, t *testing.T) {
  689. if body := tester.rr.Body.String(); body != c.expBody {
  690. t.Errorf("%s, handler returned wrong body: got %v want %v",
  691. c.msg, body, c.expBody)
  692. }
  693. }
  694. func UserModelBodyValidator(c *userTest, tester *tester, t *testing.T) {
  695. gotBody := &models.UserExternal{}
  696. expBody := &models.UserExternal{}
  697. json.Unmarshal(tester.rr.Body.Bytes(), gotBody)
  698. json.Unmarshal([]byte(c.expBody), expBody)
  699. if !reflect.DeepEqual(gotBody, expBody) {
  700. t.Errorf("%s, handler returned wrong body: got %v want %v",
  701. c.msg, gotBody, expBody)
  702. }
  703. }
  704. func ClusterBodyValidator(c *userTest, tester *tester, t *testing.T) {
  705. // if status is expected to be 200, parse the body for UserExternal
  706. gotBody := &[]models.ClusterConfigExternal{}
  707. expBody := &[]models.ClusterConfigExternal{}
  708. json.Unmarshal(tester.rr.Body.Bytes(), gotBody)
  709. json.Unmarshal([]byte(c.expBody), expBody)
  710. if !reflect.DeepEqual(gotBody, expBody) {
  711. t.Errorf("%s, handler returned wrong body: got %v want %v",
  712. c.msg, gotBody, expBody)
  713. }
  714. }