From af61e360d268666f0bc3db853c985f636e664b5a Mon Sep 17 00:00:00 2001 From: Yader Velasquez Date: Fri, 16 Feb 2024 12:42:28 -0600 Subject: [PATCH] Add more test coverage --- analytics/routes.go | 32 ------ analytics/routes_test.go | 57 +++++++--- .../{analytics.json => analytics_lists.json} | 0 analytics/samples/analytics_shorts.json | 61 +++++++++++ core/routes_test.go | 101 ++++++++++++++++++ core/samples/org_list.json | 39 +++++++ 6 files changed, 246 insertions(+), 44 deletions(-) rename analytics/samples/{analytics.json => analytics_lists.json} (100%) create mode 100644 analytics/samples/analytics_shorts.json create mode 100644 core/samples/org_list.json diff --git a/analytics/routes.go b/analytics/routes.go index 80fdd27..b4cbf56 100644 --- a/analytics/routes.go +++ b/analytics/routes.go @@ -27,7 +27,6 @@ type Service struct { func (s *Service) RegisterRoutes() { s.eg.Use(auth.AuthRequired()) - s.eg.GET("/:type", s.List).Name = s.RouteName("list") s.eg.GET("/:type/:id", s.Detail).Name = s.RouteName("detail") } @@ -236,37 +235,6 @@ func (s *Service) Detail(c echo.Context) error { return gctx.Render(http.StatusOK, "analytics_detail.html", gmap) } -func (s *Service) List(c echo.Context) error { - aType := c.Param("type") - var list interface{} - var err error - switch aType { - case "links": - list, err = models.GetOrgLinksAnalytics(c.Request().Context(), nil) - if err != nil { - return err - } - case "shorts": - list, err = models.GetLinkShortsAnalytics(c.Request().Context(), nil) - if err != nil { - return err - } - case "lists": - list, err = models.GetListsAnalytics(c.Request().Context(), nil) - if err != nil { - return err - } - - default: - return echo.NotFoundHandler(c) - } - gctx := c.(*server.Context) - lt := localizer.GetSessionLocalizer(c) - pd := localizer.NewPageData(lt.Translate("")) - gmap := gobwebs.Map{"pd": pd, "list": list, "aType": aType} - return gctx.Render(http.StatusOK, "analytics_list.html", gmap) -} - func (s *Service) RouteName(value string) string { return fmt.Sprintf("%s:%s", s.name, value) } diff --git a/analytics/routes_test.go b/analytics/routes_test.go index 0dfd80a..b33cd55 100644 --- a/analytics/routes_test.go +++ b/analytics/routes_test.go @@ -7,6 +7,7 @@ import ( "links/models" "net/http" "net/http/httptest" + "net/url" "sort" "testing" "time" @@ -30,13 +31,13 @@ func TestHandler(t *testing.T) { go srv.Run() dbCtx := cmd.NewDBContext(srv.DB, "America/Managua") - httpmock.Activate() - defer httpmock.DeactivateAndReset() - jsonResponse, err := httpmock.NewJsonResponder(http.StatusOK, httpmock.File("samples/analytics.json")) - c.NoError(err) - httpmock.RegisterResponder("POST", "http://127.0.0.1:8080/query", jsonResponse) + t.Run("analytics short details", func(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + jsonResponse, err := httpmock.NewJsonResponder(http.StatusOK, httpmock.File("samples/analytics_shorts.json")) + c.NoError(err) - t.Run("checkout success", func(t *testing.T) { + httpmock.RegisterResponder("POST", "http://127.0.0.1:8080/query", jsonResponse) short := &models.LinkShort{ Title: "Testing short", URL: "http://testing.com", @@ -45,12 +46,7 @@ func TestHandler(t *testing.T) { UserID: int(user.ID), DomainID: 1, } - err := short.Store(dbCtx) - c.NoError(err) - req := httptest.NewRequest(http.MethodGet, "/", nil) - - // Add fake analytics entries - err = analytics.AddAnalytics(dbCtx, req, short.ID, analytics.LinkShortAnalyticsFilter, "") + err = short.Store(dbCtx) c.NoError(err) request := httptest.NewRequest(http.MethodGet, "/shorts/1", nil) request.Header.Set(echo.HeaderContentType, echo.MIMEApplicationForm) @@ -67,6 +63,43 @@ func TestHandler(t *testing.T) { c.NoError(err) c.Equal(http.StatusOK, recorder.Code) }) + + t.Run("analytics list detail", func(t *testing.T) { + httpmock.Activate() + defer httpmock.DeactivateAndReset() + jsonResponse, err := httpmock.NewJsonResponder(http.StatusOK, httpmock.File("samples/analytics_lists.json")) + c.NoError(err) + + httpmock.RegisterResponder("POST", "http://127.0.0.1:8080/query", jsonResponse) + list := &models.Listing{ + Title: "Testing lists", + Slug: "testing-list", + OrgID: 1, + UserID: int(user.ID), + DomainID: 1, + } + err = list.Store(dbCtx) + c.NoError(err) + + q := make(url.Values) + q.Add("date-start", "2023-12-12") + q.Add("date-end", "2024-02-12") + request := httptest.NewRequest(http.MethodGet, "/lists/1?"+q.Encode(), nil) + request.Header.Set(echo.HeaderContentType, echo.MIMEApplicationForm) + recorder := httptest.NewRecorder() + ctx := &server.Context{ + Server: srv, + Context: e.NewContext(request, recorder), + User: user, + } + ctx.SetPath("/:slug/analytics/:type/:id") + ctx.SetParamNames("slug", "type", "id") + ctx.SetParamValues("personal-org", "lists", fmt.Sprint(list.ID)) + err = cmd.MakeRequest(srv, analyticsService.Detail, ctx) + c.NoError(err) + c.Equal(http.StatusOK, recorder.Code) + + }) } func TestAPI(t *testing.T) { diff --git a/analytics/samples/analytics.json b/analytics/samples/analytics_lists.json similarity index 100% rename from analytics/samples/analytics.json rename to analytics/samples/analytics_lists.json diff --git a/analytics/samples/analytics_shorts.json b/analytics/samples/analytics_shorts.json new file mode 100644 index 0000000..01183d2 --- /dev/null +++ b/analytics/samples/analytics_shorts.json @@ -0,0 +1,61 @@ +{ + "data": { + "analytics": { + "title": "New Short", + "clicksOverTime": [ + { + "key": "2024-01-21", + "val": 10 + }, + { + "key": "2024-01-28", + "val": 10 + }, + { + "key": "2024-02-04", + "val": 10 + }, + { + "key": "2024-02-11", + "val": 10 + }, + { + "key": "2024-01-14", + "val": 10 + } + ], + "shortLink": [ + { + "id": 12, + "title": "Title", + "clicks": 12 + } + ], + "clicksCountry": [ + { + "key": "Country", + "val": 1000 + } + ], + "clicksCity": [ + { + "key": "City", + "val": 1000 + } + + ], + "clicksDevice": [ + { + "key": "Device", + "val": 1000 + } + ], + "clicksReferrer": [ + { + "key": "Referrer", + "val": 1000 + } + ] + } + } +} diff --git a/core/routes_test.go b/core/routes_test.go index bab6c5f..88c471b 100644 --- a/core/routes_test.go +++ b/core/routes_test.go @@ -2,6 +2,7 @@ package core_test import ( "database/sql" + "fmt" "links/cmd" "links/core" "links/models" @@ -35,6 +36,77 @@ func TestHandlers(t *testing.T) { }) c.NoError(err) + t.Run("invalid domain", func(t *testing.T) { + invalidD := &models.Domain{ + Name: "invalid", + LookupName: "foo.com", + OrgID: sql.NullInt64{Valid: true, Int64: 1}, + Level: models.DomainLevelUser, + Service: models.DomainServiceLinks, + Status: models.DomainStatusApproved, + IsActive: false, + } + err := invalidD.Store(dbCtx) + c.NoError(err) + + request := httptest.NewRequest(http.MethodGet, "/invalid/"+invalidD.LookupName, nil) + recorder := httptest.NewRecorder() + ctx := &server.Context{ + Server: srv, + Context: e.NewContext(request, recorder), + User: loggedInUser, + } + ctx.SetPath("/invalid/:d") + ctx.SetParamNames("d") + ctx.SetParamValues(invalidD.LookupName) + err = cmd.MakeRequest(srv, coreService.InvalidDomain, ctx) + c.NoError(err) + htmlBody := recorder.Body.String() + c.True(strings.Contains(htmlBody, "Invalid Domain")) + + }) + + t.Run("homepage", func(t *testing.T) { + d := &models.Domain{ + Name: "valid user domain", + LookupName: "foo.com", + OrgID: sql.NullInt64{Valid: false, Int64: 0}, + Level: models.DomainLevelSystem, + Service: models.DomainServiceLinks, + Status: models.DomainStatusApproved, + IsActive: true, + } + err := d.Store(dbCtx) + c.NoError(err) + request := httptest.NewRequest(http.MethodGet, "/", nil) + recorder := httptest.NewRecorder() + ctx := &server.Context{ + Server: srv, + Context: e.NewContext(request, recorder), + User: loggedInUser, + } + ctx.SetPath("/") + err = cmd.MakeRequestWithDomain(srv, coreService.Homepage, ctx, d) + c.NoError(err) + }) + + t.Run("feature tour", func(t *testing.T) { + request := httptest.NewRequest(http.MethodGet, "/tour", nil) + recorder := httptest.NewRecorder() + ctx := &server.Context{ + Server: srv, + Context: e.NewContext(request, recorder), + User: loggedInUser, + } + ctx.SetPath("/tour") + err = cmd.MakeRequestWithDomain(srv, coreService.FeatureTour, ctx, domains[0]) + c.NoError(err) + c.Equal(http.StatusOK, recorder.Code) + htmlBody := recorder.Body.String() + c.True(strings.Contains(htmlBody, "Explore Features")) + + }) + t.Run("home link list", func(t *testing.T) { httpmock.Activate() defer httpmock.DeactivateAndReset() @@ -387,6 +459,35 @@ func TestHandlers(t *testing.T) { c.Equal(http.StatusMovedPermanently, recorder.Code) }) + t.Run("org lists", func(t *testing.T) { + domains, err := models.GetDomains(dbCtx, &database.FilterOptions{ + Filter: sq.And{ + sq.Eq{"d.lookup_name": "foo.com"}, + }, + Limit: 1, + }) + c.NoError(err) + domain := domains[0] + httpmock.Activate() + defer httpmock.DeactivateAndReset() + jsonResponse, err := httpmock.NewJsonResponder(http.StatusOK, + httpmock.File("samples/org_list.json")) + c.NoError(err) + httpmock.RegisterResponder("POST", "http://127.0.0.1:8080/query", jsonResponse) + + request := httptest.NewRequest(http.MethodPost, fmt.Sprintf("/organizations?d=%s", domain.LookupName), nil) + recorder := httptest.NewRecorder() + ctx := &server.Context{ + Server: srv, + Context: e.NewContext(request, recorder), + User: loggedInUser, + } + ctx.SetPath("/organizations") + err = cmd.MakeRequest(srv, coreService.OrgList, ctx) + c.NoError(err) + c.Equal(http.StatusOK, recorder.Code) + }) + t.Run("qr redirect", func(t *testing.T) { httpmock.Activate() defer httpmock.DeactivateAndReset() diff --git a/core/samples/org_list.json b/core/samples/org_list.json new file mode 100644 index 0000000..7387500 --- /dev/null +++ b/core/samples/org_list.json @@ -0,0 +1,39 @@ +{ + "data": { + "getOrganizations": [ + { + "id": 1, + "name": "Org 1", + "slug": "org-1", + "isActive": true, + "settings": { + "billing": { + "status": 1 + } + } + }, + { + "id": 59, + "name": "Org 2", + "slug": "org-2", + "isActive": true, + "settings": { + "billing": { + "status": 2 + } + } + }, + { + "id": 60, + "name": "Org 3", + "slug": "org-3", + "isActive": true, + "settings": { + "billing": { + "status": 0 + } + } + } + ] + } +} -- 2.45.2