From 24c478dd714ac7e66df110bf130fbb504900e45d Mon Sep 17 00:00:00 2001 From: Kamil Samigullin Date: Mon, 30 Apr 2018 13:48:54 +0300 Subject: [PATCH] fix #26: improve code coverage --- README.md | 7 ++++ http/availability/pkg_test.go | 17 +++++---- http/availability/printer.go | 8 ++-- http/availability/report.go | 32 +++++++--------- http/availability/report_test.go | 65 +++++++++++++++++++++++++++++++- 5 files changed, 98 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index e2619f1..cd06046 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,13 @@ $ check completion zsh > /path/to/zsh-completions/_check.zsh ## Notes +- brief roadmap + - [ ] v1: MVP + - [ ] v2: check redirects + - [ ] v3: check repository + - [ ] v4: check package + - [ ] v5: distributed run + - [ ] integrate with Status, SaaS - tested on Go 1.8, 1.9 and 1.10 --- diff --git a/http/availability/pkg_test.go b/http/availability/pkg_test.go index a10e62c..548912d 100644 --- a/http/availability/pkg_test.go +++ b/http/availability/pkg_test.go @@ -177,20 +177,21 @@ func (c *chain) ServeHTTP(rw http.ResponseWriter, req *http.Request) { c.Handler.ServeHTTP(rw, req) } -type PrinterMock struct { +type CrawlerMock struct { mock.Mock + shift func(availability.EventBus) } -func (m *PrinterMock) Sites() <-chan availability.Site { - args := m.Called() - return args.Get(0).(<-chan availability.Site) +func (m *CrawlerMock) Visit(url string, bus availability.EventBus) error { + go m.shift(bus) + return m.Called(url, bus).Error(0) } -type CrawlerMock struct { +type PrinterMock struct { mock.Mock } -func (m *CrawlerMock) Visit(url string, bus availability.EventBus) error { - args := m.Called(url, bus) - return args.Error(0) +func (m *PrinterMock) Sites() <-chan availability.Site { + args := m.Called() + return args.Get(0).(<-chan availability.Site) } diff --git a/http/availability/printer.go b/http/availability/printer.go index 97e14e4..71c56d1 100644 --- a/http/availability/printer.go +++ b/http/availability/printer.go @@ -62,9 +62,9 @@ func (p *Printer) Print() error { return errors.Simple("nothing to print") } for site := range p.report.Sites() { - if err := site.Error(); err != nil { - critical().Fprintf(w, "report %q has error %q\n", site.Name(), err) - if stack := errors.StackTrace(err); stack != nil { + if site.Error != nil { + critical().Fprintf(w, "report %q has error %q\n", site.Name, site.Error) + if stack := errors.StackTrace(site.Error); stack != nil { critical().Fprintf(ioutil.Discard, "stack trace: %#+v\n", stack) // for future } continue @@ -83,7 +83,7 @@ func (p *Printer) Print() error { } } if len(site.Problems) > 0 { - critical().Fprintf(w, "found problems on the site %q\n", site.Name()) + critical().Fprintf(w, "found problems on the site %q\n", site.Name) for i, problem := range site.Problems { critical().Fprintf(w, "- [%d] %s `%+v`\n", i, problem.Message, problem.Context) } diff --git a/http/availability/report.go b/http/availability/report.go index 15cbfc0..44aaed8 100644 --- a/http/availability/report.go +++ b/http/availability/report.go @@ -42,11 +42,11 @@ func (r *Report) Fill() *Report { wg.Add(1) go func(site *Site) { var copied Site - copied.name = site.name + copied.Name = site.Name defer wg.Done() defer func() { r.ready <- copied }() - defer errors.Recover(&copied.error) - site.error = site.Fetch(r.crawler) + defer errors.Recover(&copied.Error) + site.Error = site.Fetch(r.crawler) { copied = *site pages := make([]*Page, 0, len(site.Pages)) @@ -76,32 +76,28 @@ func (r *Report) Sites() <-chan Site { func NewSite(rawURL string) *Site { u, err := url.Parse(rawURL) return &Site{ - name: hostOrRawURL(u, rawURL), url: u, - error: errors.Wrapf(err, "parse rawURL %q for report", rawURL), + Name: hostOrRawURL(u, rawURL), + Error: errors.Wrapf(err, "parse rawURL %q for report", rawURL), } } type Site struct { - name string - url *url.URL - error error + url *url.URL + Name string + Error error Pages []*Page Problems []ProblemEvent } -func (s *Site) Name() string { return s.name } - -func (s *Site) Error() error { return s.error } - func (s *Site) Fetch(crawler Crawler) error { - if s.error != nil { - return s.error + if s.Error != nil { + return s.Error } if crawler == nil { - s.error = errors.Simple("crawler is not provided") - return s.error + s.Error = errors.Simple("crawler is not provided") + return s.Error } var unexpected error wg, events := &sync.WaitGroup{}, make(chan event, 512) @@ -111,12 +107,12 @@ func (s *Site) Fetch(crawler Crawler) error { defer errors.Recover(&unexpected) s.listen(events) }() - s.error = crawler.Visit(s.url.String(), events) + s.Error = crawler.Visit(s.url.String(), events) wg.Wait() if unexpected != nil { panic(unexpected) } - return s.error + return s.Error } func (s *Site) listen(events <-chan event) { diff --git a/http/availability/report_test.go b/http/availability/report_test.go index 42cd957..845a7f0 100644 --- a/http/availability/report_test.go +++ b/http/availability/report_test.go @@ -1,10 +1,13 @@ package availability_test import ( + "net/http" "testing" + "github.com/kamilsk/check/errors" "github.com/kamilsk/check/http/availability" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" ) func TestReporter(t *testing.T) { @@ -24,6 +27,58 @@ func TestReporter(t *testing.T) { return ch }, }, + { + "bad site", + []string{":bad"}, + func() *availability.Report { return availability.NewReport() }, + func() <-chan availability.Site { + ch := make(chan availability.Site, 1) + ch <- *availability.NewSite(":bad") + close(ch) + return ch + }, + }, + { + "without crawler", + []string{"http://test.dev/"}, + func() *availability.Report { return availability.NewReport() }, + func() <-chan availability.Site { + ch := make(chan availability.Site, 1) + site := *availability.NewSite("http://test.dev/") + site.Error = errors.Simple("crawler is not provided") + ch <- site + close(ch) + return ch + }, + }, + { + "normal case", + []string{"http://test.dev/"}, + func() *availability.Report { + crawler := &CrawlerMock{shift: func(to availability.EventBus) { + to <- availability.ResponseEvent{StatusCode: http.StatusOK, Location: "http://test.dev/"} + to <- availability.WalkEvent{Page: "http://test.dev/", Href: "http://accepted.dev/"} + to <- availability.WalkEvent{Page: "http://test.dev/", Href: "http://redirect.dev/"} + to <- availability.WalkEvent{Page: "http://test.dev/", Href: "http://noaccess.dev/"} + to <- availability.ProblemEvent{Message: "bad url", Context: ":bad"} + to <- availability.ResponseEvent{StatusCode: http.StatusAccepted, Location: "http://accepted.dev/"} + to <- availability.ErrorEvent{StatusCode: http.StatusFound, + Location: "http://redirect.dev/", Redirect: "https://redirect.dev/"} + to <- availability.ErrorEvent{StatusCode: http.StatusForbidden, Location: "http://noaccess.dev/"} + close(to) + }} + crawler.On("Visit", "http://test.dev/", mock.Anything).Return(nil) + report := availability.NewReport(availability.CrawlerForSites(crawler)) + return report + }, + func() <-chan availability.Site { + ch := make(chan availability.Site, 1) + ch <- *availability.NewSite("http://test.dev/") + close(ch) + return ch + }, + }, + // TODO check panics } for _, test := range tests { tc := test @@ -39,7 +94,15 @@ func TestReporter(t *testing.T) { for site := range expectedPipe { expected = append(expected, site) } - assert.Equal(t, expected, obtained) + for i := range expected { + assert.Equal(t, expected[i].Name, obtained[i].Name) + if expected[i].Error != nil { + assert.EqualError(t, obtained[i].Error, expected[i].Error.Error()) + } else { + assert.NoError(t, obtained[i].Error) + } + // TODO check site tree + } }) } }