github.com/ngocphuongnb/tetua@v0.0.7-alpha/app/web/web_test.go (about) 1 package web_test 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net/http" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/PuerkitoBio/goquery" 13 "github.com/ngocphuongnb/tetua/app/auth" 14 "github.com/ngocphuongnb/tetua/app/cache" 15 "github.com/ngocphuongnb/tetua/app/config" 16 "github.com/ngocphuongnb/tetua/app/entities" 17 "github.com/ngocphuongnb/tetua/app/fs" 18 "github.com/ngocphuongnb/tetua/app/mock" 19 mockrepository "github.com/ngocphuongnb/tetua/app/mock/repository" 20 "github.com/ngocphuongnb/tetua/app/repositories" 21 "github.com/ngocphuongnb/tetua/app/server" 22 "github.com/ngocphuongnb/tetua/app/web" 23 "github.com/stretchr/testify/assert" 24 "github.com/tdewolff/minify/v2" 25 "github.com/tdewolff/minify/v2/xml" 26 ) 27 28 var m = minify.New() 29 var mockLogger *mock.MockLogger 30 var post1, post2 *entities.Post 31 var file1, file2, file3 *entities.File 32 var topic1 *entities.Topic 33 34 func init() { 35 m.AddFunc("xml", xml.Minify) 36 fs.New("disk_mock", []fs.FSDisk{&mock.Disk{}}) 37 cache.Roles = []*entities.Role{auth.ROLE_ADMIN, auth.ROLE_USER, auth.ROLE_GUEST} 38 mockLogger = mock.CreateLogger(true) 39 mock.CreateRepositories() 40 config.Settings([]*config.SettingItem{{ 41 Name: "app_base_url", 42 Value: "http://localhost:8080", 43 }}) 44 45 topic1, _ = repositories.Topic.Create(context.Background(), &entities.Topic{ 46 ID: 1, 47 Name: "Test Topic", 48 Slug: "test-topic", 49 }) 50 51 post1, _ = repositories.Post.Create(context.Background(), &entities.Post{ 52 ID: 1, 53 Name: "test post 1", 54 Slug: "test-post-1", 55 Draft: false, 56 UserID: 1, 57 Topics: []*entities.Topic{topic1}, 58 TopicIDs: []int{topic1.ID}, 59 }) 60 post2, _ = repositories.Post.Create(context.Background(), &entities.Post{ 61 ID: 2, 62 Name: "test post 2", 63 Slug: "test-post-2", 64 Draft: false, 65 UserID: 2, 66 Topics: []*entities.Topic{topic1}, 67 TopicIDs: []int{topic1.ID}, 68 }) 69 70 file1, _ = repositories.File.Create(context.Background(), &entities.File{ 71 ID: 1, 72 Disk: "disk_mock", 73 Path: "/test/file1.jpg", 74 Size: 100, 75 Type: "image/jpg", 76 UserID: 1, 77 }) 78 file2, _ = repositories.File.Create(context.Background(), &entities.File{ 79 ID: 2, 80 Disk: "disk_mock", 81 Path: "/test/file2.jpg", 82 Size: 100, 83 Type: "image/jpg", 84 UserID: 1, 85 }) 86 file3, _ = repositories.File.Create(context.Background(), &entities.File{ 87 ID: 3, 88 Disk: "disk_mock", 89 Path: "/test/file3.jpg", 90 Size: 100, 91 Type: "image/jpg", 92 UserID: 2, 93 }) 94 } 95 96 func TestWeb(t *testing.T) { 97 web.NewServer(web.Config{ 98 JwtSigningKey: config.APP_KEY, 99 Theme: config.APP_THEME, 100 }) 101 } 102 103 func TestFeedError(t *testing.T) { 104 mockrepository.FakeRepoErrors["post_find"] = errors.New("Error finding posts") 105 mockServer := mock.CreateServer() 106 mockServer.Get("/feed", func(c server.Context) error { 107 return web.Feed(c) 108 }) 109 110 body, resp := mock.GetRequest(mockServer, "/feed") 111 assert.Equal(t, "Error", body) 112 assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) 113 } 114 115 func TestFeed(t *testing.T) { 116 mockrepository.FakeRepoErrors["post_find"] = nil 117 mockServer := mock.CreateServer() 118 mockServer.Get("/feed", func(c server.Context) error { 119 return web.Feed(c) 120 }) 121 122 body, _ := mock.GetRequest(mockServer, "/feed") 123 body, err := m.String("xml", body) 124 assert.Nil(t, err) 125 126 expectFeed, _ := m.String("xml", fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?> 127 <rss version="2.0" 128 xmlns:content="http://purl.org/rss/1.0/modules/content/"> 129 <channel> 130 <title>Tetua</title> 131 <link>http://localhost:8080/</link> 132 <description>Tetua</description> 133 <item> 134 <title>test post 1</title> 135 <link>http://localhost:8080/test-post-1-1.html</link> 136 <description/> 137 <author>testuser1</author> 138 <guid>1</guid> 139 <pubDate>%s</pubDate> 140 </item> 141 <item> 142 <title>test post 2</title> 143 <link>http://localhost:8080/test-post-2-2.html</link> 144 <description/> 145 <author>testuser2</author> 146 <guid>2</guid> 147 <pubDate>%s</pubDate> 148 </item> 149 </channel> 150 </rss>`, post1.CreatedAt.Format(time.RFC1123Z), post2.CreatedAt.Format(time.RFC1123Z))) 151 152 assert.Equal(t, expectFeed, body) 153 } 154 155 func TestFileError(t *testing.T) { 156 mockrepository.FakeRepoErrors["file_find"] = errors.New("Error finding files") 157 mockServer := mock.CreateServer() 158 mockServer.Get("/files", web.FileList) 159 160 _, resp := mock.GetRequest(mockServer, "/files") 161 assert.Equal(t, http.StatusInternalServerError, resp.StatusCode) 162 } 163 164 func TestFileList(t *testing.T) { 165 mockrepository.FakeRepoErrors["file_find"] = nil 166 167 fileLinks := []string{ 168 file1.Url(), 169 file2.Url(), 170 } 171 172 mockServer := mock.CreateServer() 173 mockServer.Get("/files", func(c server.Context) error { 174 c.Locals("user", &entities.User{ID: 1}) 175 return web.FileList(c) 176 }) 177 178 body, resp := mock.GetRequest(mockServer, "/files") 179 doc, err := goquery.NewDocumentFromReader(strings.NewReader(body)) 180 assert.Nil(t, err) 181 foundLinks := make([]string, 0) 182 doc.Find(".files-list > div").Each(func(i int, s *goquery.Selection) { 183 href, _ := s.Find("a").Attr("href") 184 foundLinks = append(foundLinks, href) 185 }) 186 187 assert.Equal(t, fileLinks, foundLinks) 188 assert.Equal(t, http.StatusOK, resp.StatusCode) 189 } 190 191 func TestFileDeleteError1(t *testing.T) { 192 mockrepository.FakeRepoErrors["file_deleteByID"] = errors.New("Error deleting file") 193 mockServer := mock.CreateServer() 194 mockServer.Delete("/files/:id", func(c server.Context) error { 195 file3, _ := repositories.File.ByID(context.Background(), 3) 196 c.Locals("file", file3) 197 return web.FileDelete(c) 198 }) 199 200 body, resp := mock.Request(mockServer, "DELETE", "/files/3") 201 assert.Equal(t, errors.New("Error deleting file"), mockLogger.Last().Params[0]) 202 assert.Equal(t, http.StatusBadRequest, resp.StatusCode) 203 assert.Equal(t, `{"type":"error","message":"Error deleting file"}`, body) 204 } 205 206 func TestFileDeleteError2(t *testing.T) { 207 mockrepository.FakeRepoErrors["file_deleteByID"] = nil 208 mockServer := mock.CreateServer() 209 mockServer.Delete("/files/:id", func(c server.Context) error { 210 file3, _ := repositories.File.ByID(context.Background(), 3) 211 file3.Path = "/delete/error" 212 c.Locals("file", file3) 213 return web.FileDelete(c) 214 }) 215 216 body, resp := mock.Request(mockServer, "DELETE", "/files/3") 217 assert.Equal(t, errors.New("Delete file error"), mockLogger.Last().Params[0]) 218 assert.Equal(t, http.StatusBadRequest, resp.StatusCode) 219 assert.Equal(t, `{"type":"error","message":"Error deleting file"}`, body) 220 } 221 222 func TestFileDelete(t *testing.T) { 223 mockrepository.FakeRepoErrors["file_deleteByID"] = nil 224 repositories.File.Create(context.Background(), file3) 225 mockServer := mock.CreateServer() 226 mockServer.Delete("/files/:id", func(c server.Context) error { 227 file3, _ := repositories.File.ByID(context.Background(), 3) 228 file3.Path = "/test/file3.jpg" 229 c.Locals("file", file3) 230 return web.FileDelete(c) 231 }) 232 233 body, resp := mock.Request(mockServer, "DELETE", "/files/3") 234 235 assert.Equal(t, http.StatusOK, resp.StatusCode) 236 assert.Equal(t, `{"type":"success","message":"File deleted"}`, body) 237 } 238 239 func TestFileUpload(t *testing.T) { 240 mockServer := mock.CreateServer() 241 mockServer.Post("/files", func(c server.Context) error { 242 return web.Upload(c) 243 }) 244 245 req := mock.CreateUploadRequest("POST", "/files", "some_field", "file.jpg") 246 body, _ := mock.SendRequest(mockServer, req) 247 assert.Equal(t, errors.New("there is no uploaded file associated with the given key"), mockLogger.Last().Params[0]) 248 assert.Equal(t, `{"error":"Error saving file"}`, body) 249 250 req = mock.CreateUploadRequest("POST", "/files", "file", "error.jpg") 251 body, _ = mock.SendRequest(mockServer, req) 252 assert.Equal(t, errors.New("PutMultipart error"), mockLogger.Last().Params[0]) 253 assert.Equal(t, `{"error":"Error saving file"}`, body) 254 255 mockrepository.FakeRepoErrors["file_create"] = errors.New("Error creating file") 256 req = mock.CreateUploadRequest("POST", "/files", "file", "image.jpg") 257 body, _ = mock.SendRequest(mockServer, req) 258 assert.Equal(t, errors.New("Error creating file"), mockLogger.Last().Params[0]) 259 assert.Equal(t, `{"error":"Error saving file"}`, body) 260 261 mockrepository.FakeRepoErrors["file_create"] = nil 262 req = mock.CreateUploadRequest("POST", "/files", "file", "image.jpg") 263 body, _ = mock.SendRequest(mockServer, req) 264 assert.Equal(t, `{"size":100,"type":"image/jpeg","url":"/disk_mock/image.jpg"}`, body) 265 } 266 267 func TestIndex(t *testing.T) { 268 mockServer := mock.CreateServer() 269 mockServer.Get("/", func(c server.Context) error { 270 return web.Index(c) 271 }) 272 273 mockrepository.FakeRepoErrors["post_paginate"] = errors.New("Error paginating posts") 274 body, resp := mock.GetRequest(mockServer, "/") 275 assert.Equal(t, http.StatusBadGateway, resp.StatusCode) 276 assert.Equal(t, errors.New("Error paginating posts"), mockLogger.Last().Params[0]) 277 assert.Equal(t, true, strings.Contains(body, `<h1>Something went wrong</h1>`)) 278 279 mockrepository.FakeRepoErrors["post_paginate"] = nil 280 mockrepository.FakeRepoErrors["post_find"] = errors.New("Error finding post") 281 body, resp = mock.GetRequest(mockServer, "/") 282 assert.Equal(t, http.StatusBadGateway, resp.StatusCode) 283 assert.Equal(t, errors.New("Error finding post"), mockLogger.Last().Params[0]) 284 assert.Equal(t, true, strings.Contains(body, `<h1>Something went wrong</h1>`)) 285 286 mockrepository.FakeRepoErrors["post_paginate"] = nil 287 mockrepository.FakeRepoErrors["post_find"] = nil 288 body, resp = mock.GetRequest(mockServer, "/") 289 290 doc, err := goquery.NewDocumentFromReader(strings.NewReader(body)) 291 assert.Nil(t, err) 292 postLinks := []string{post1.Url(), post2.Url()} 293 mainLinks := make([]string, 0) 294 sideLinks := make([]string, 0) 295 doc.Find("main article").Each(func(i int, s *goquery.Selection) { 296 href, _ := s.Find("a.overlay").Attr("href") 297 mainLinks = append(mainLinks, href) 298 }) 299 300 doc.Find(".right article").Each(func(i int, s *goquery.Selection) { 301 href, _ := s.Find("a").Attr("href") 302 sideLinks = append(sideLinks, href) 303 }) 304 305 assert.Equal(t, postLinks, mainLinks) 306 assert.Equal(t, postLinks, sideLinks) 307 assert.Equal(t, http.StatusOK, resp.StatusCode) 308 } 309 310 func TestSearch(t *testing.T) { 311 mockServer := mock.CreateServer() 312 mockServer.Get("/search", func(c server.Context) error { 313 return web.Search(c) 314 }) 315 316 mockrepository.FakeRepoErrors["post_paginate"] = errors.New("Error paginating posts") 317 body, resp := mock.GetRequest(mockServer, "/search?q=post") 318 assert.Equal(t, http.StatusBadGateway, resp.StatusCode) 319 assert.Equal(t, errors.New("Error paginating posts"), mockLogger.Last().Params[0]) 320 assert.Equal(t, true, strings.Contains(body, `<h1>Something went wrong</h1>`)) 321 322 mockrepository.FakeRepoErrors["post_paginate"] = nil 323 mockrepository.FakeRepoErrors["post_find"] = nil 324 body, resp = mock.GetRequest(mockServer, "/search?q=post") 325 326 doc, err := goquery.NewDocumentFromReader(strings.NewReader(body)) 327 assert.Nil(t, err) 328 postLinks := []string{post1.Url(), post2.Url()} 329 mainLinks := make([]string, 0) 330 doc.Find("main article").Each(func(i int, s *goquery.Selection) { 331 href, _ := s.Find("a.overlay").Attr("href") 332 mainLinks = append(mainLinks, href) 333 }) 334 335 assert.Equal(t, postLinks, mainLinks) 336 assert.Equal(t, true, strings.Contains(body, `<title>post - Search result for post - Tetua</title>`)) 337 } 338 339 func TestTopicView(t *testing.T) { 340 mockServer := mock.CreateServer() 341 mockServer.Get("/:slug", func(c server.Context) error { 342 return web.TopicView(c) 343 }) 344 345 body, resp := mock.GetRequest(mockServer, "/test-topic") 346 assert.Equal(t, http.StatusNotFound, resp.StatusCode) 347 assert.Equal(t, true, strings.Contains(body, `<title>Topic not found`)) 348 assert.Equal(t, true, strings.Contains(body, `<h1>Topic not found</h1>`)) 349 350 post1.TopicIDs = []int{topic1.ID} 351 post2.TopicIDs = []int{topic1.ID} 352 repositories.Post.Update(context.Background(), post1) 353 repositories.Post.Update(context.Background(), post2) 354 cache.CacheTopics() 355 356 mockrepository.FakeRepoErrors["post_paginate"] = errors.New("Error paginating posts") 357 body, resp = mock.GetRequest(mockServer, "/test-topic") 358 assert.Equal(t, http.StatusBadGateway, resp.StatusCode) 359 assert.Equal(t, errors.New("Error paginating posts"), mockLogger.Last().Params[0]) 360 assert.Equal(t, true, strings.Contains(body, `<h1>Something went wrong</h1>`)) 361 362 mockrepository.FakeRepoErrors["post_paginate"] = nil 363 mockrepository.FakeRepoErrors["post_find"] = errors.New("Error finding post") 364 body, resp = mock.GetRequest(mockServer, "/test-topic") 365 assert.Equal(t, http.StatusBadGateway, resp.StatusCode) 366 assert.Equal(t, errors.New("Error finding post"), mockLogger.Last().Params[0]) 367 assert.Equal(t, true, strings.Contains(body, `<h1>Something went wrong</h1>`)) 368 369 mockrepository.FakeRepoErrors["post_find"] = nil 370 body, resp = mock.GetRequest(mockServer, "/test-topic") 371 assert.Equal(t, http.StatusOK, resp.StatusCode) 372 assert.Equal(t, true, strings.Contains(body, `<title>Test Topic`)) 373 374 doc, err := goquery.NewDocumentFromReader(strings.NewReader(body)) 375 assert.Nil(t, err) 376 postLinks := []string{post1.Url(), post2.Url()} 377 mainLinks := make([]string, 0) 378 sideLinks := make([]string, 0) 379 doc.Find("main article").Each(func(i int, s *goquery.Selection) { 380 href, _ := s.Find("a.overlay").Attr("href") 381 mainLinks = append(mainLinks, href) 382 }) 383 384 doc.Find(".right article").Each(func(i int, s *goquery.Selection) { 385 href, _ := s.Find("a").Attr("href") 386 sideLinks = append(sideLinks, href) 387 }) 388 389 assert.Equal(t, postLinks, mainLinks) 390 assert.Equal(t, postLinks, sideLinks) 391 assert.Equal(t, http.StatusOK, resp.StatusCode) 392 } 393 394 func TestTopicFeedError(t *testing.T) { 395 mockrepository.FakeRepoErrors["post_find"] = errors.New("Error finding posts") 396 mockServer := mock.CreateServer() 397 mockServer.Get("/:slug/feed", func(c server.Context) error { 398 return web.TopicFeed(c) 399 }) 400 401 topic1.Slug = "test-topic-updated" 402 repositories.Topic.Update(context.Background(), topic1) 403 cache.CacheTopics() 404 body, resp := mock.GetRequest(mockServer, "/test-topic/feed") 405 assert.Equal(t, "Topic not found", body) 406 assert.Equal(t, http.StatusNotFound, resp.StatusCode) 407 408 topic1.Slug = "test-topic" 409 mockrepository.FakeRepoErrors["post_find"] = nil 410 repositories.Topic.Update(context.Background(), topic1) 411 cache.CacheTopics() 412 body, resp = mock.GetRequest(mockServer, "/test-topic/feed") 413 assert.Equal(t, http.StatusOK, resp.StatusCode) 414 415 body, err := m.String("xml", body) 416 assert.Nil(t, err) 417 418 expectFeed, _ := m.String("xml", fmt.Sprintf(`<?xml version="1.0" encoding="UTF-8"?> 419 <rss version="2.0" 420 xmlns:content="http://purl.org/rss/1.0/modules/content/"> 421 <channel> 422 <title>%s</title> 423 <link>%s</link> 424 <description></description> 425 <item> 426 <title>%s</title> 427 <link>%s</link> 428 <description></description> 429 <author>%s</author> 430 <guid>%d</guid> 431 <pubDate>%s</pubDate> 432 </item> 433 <item> 434 <title>%s</title> 435 <link>%s</link> 436 <description></description> 437 <author>%s</author> 438 <guid>%d</guid> 439 <pubDate>%s</pubDate> 440 </item> 441 </channel> 442 </rss>`, 443 topic1.Name, 444 topic1.Url(), 445 446 post1.Name, 447 post1.Url(), 448 post1.User.Username, 449 post1.ID, 450 post1.CreatedAt.Format(time.RFC1123Z), 451 452 post2.Name, 453 post2.Url(), 454 post2.User.Username, 455 post2.ID, 456 post2.CreatedAt.Format(time.RFC1123Z), 457 )) 458 assert.Equal(t, expectFeed, body) 459 }