// Copyright (C) 2020 Evgeny Kuznetsov (evgeny@kuznetsov.md) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package main import ( "bytes" "flag" "fmt" "io/ioutil" "log" "net/http" "net/http/httptest" "os" "os/exec" "path/filepath" "strings" "sync" "testing" "github.com/gorilla/feeds" ) var ( update = flag.Bool("update", false, "update .golden files") fakeURL = `**localhost**` ) const pth = "testdata/brand/57083" func helperLoadBytes(t testing.TB, name string) []byte { t.Helper() path := filepath.Join("testdata", name) bytes, err := ioutil.ReadFile(path) if err != nil { t.Fatal(err) } return bytes } func TestFeed(t *testing.T) { var page []byte feed := &feeds.Feed{ Link: &feeds.Link{Href: "http://www.radiorus.ru/brand/57083/episodes"}, } err := populateFeed(feed, page) assertStringContains(t, fmt.Sprint(err), "bad programme") page = helperLoadBytes(t, "episodes") page = cleanText(page) if err := populateFeed(feed, page); err != nil { t.Fatal(err) } page = helperLoadBytes(t, "about") page = cleanText(page) feed.Description, _ = processFeedDesc(page) actual := createFeed(feed) golden := filepath.Join("testdata", t.Name()+".golden") if *update { writeFile(actual, golden) } expected, _ := ioutil.ReadFile(golden) if !bytes.Equal(actual, expected) { t.Fail() } } func TestFindEpisodes(t *testing.T) { var tests = []string{ "episodes", "episodes.59798", "episodes.63147", } for _, test := range tests { page := helperLoadBytes(t, test) page = cleanText(page) actual := bytes.Join(findEpisodes(page), []byte("\n&&&\n")) golden := filepath.Join("testdata", t.Name()+"."+test+".golden") if *update { writeFile(actual, golden) } expected, _ := ioutil.ReadFile(golden) if !bytes.Equal(actual, expected) { t.Fail() } } } func TestUpdatingFeed(t *testing.T) { var page []byte feed := &feeds.Feed{ Link: &feeds.Link{Href: "http://www.radiorus.ru/brand/59798/episodes"}, } page = helperLoadBytes(t, "episodes.59798") page = cleanText(page) if err := populateFeed(feed, page); err != nil { t.Fatal(err) } actual := createFeed(feed) golden := filepath.Join("testdata", t.Name()+".golden") if *update { writeFile(actual, golden) } expected, _ := ioutil.ReadFile(golden) if !bytes.Equal(actual, expected) { t.Fail() } } func TestVideoFeed(t *testing.T) { var page []byte feed := &feeds.Feed{ Link: &feeds.Link{Href: "http://www.radiorus.ru/brand/63147/episodes"}, } page = helperLoadBytes(t, "episodes.63147") page = cleanText(page) if err := populateFeed(feed, page); err != nil { t.Fatal(err) } actual := createFeed(feed) golden := filepath.Join("testdata", t.Name()+".golden") if *update { writeFile(actual, golden) } expected, _ := ioutil.ReadFile(golden) if !bytes.Equal(actual, expected) { t.Fail() } } func TestMissingEpisode(t *testing.T) { server := helperMockServer(t) defer helperCleanupServer(t) item := feeds.Item{ Id: "aabb", Link: &feeds.Link{Href: fmt.Sprintf("%s/brand/none", server.URL)}, } var buf bytes.Buffer log.SetOutput(&buf) defer func() { log.SetOutput(os.Stderr) }() var wg sync.WaitGroup wg.Add(1) describeEpisode(&item, &wg) assertStringContains(t, buf.String(), fmt.Sprintf("could not find episode description on page %v: %v", item.Link.Href, errCantParse)) } func assertStringContains(t *testing.T, got, want string) { if !strings.Contains(got, want) { t.Fatalf("%v does not contain %v", got, want) } } func TestMissingFeedDesc(t *testing.T) { server := helperMockServer(t) defer helperCleanupFile(t, "episodes") helperCleanupFile(t, "about") var buf bytes.Buffer log.SetOutput(&buf) defer func() { log.SetOutput(os.Stderr) }() processURL(fmt.Sprintf("%s/brand/57083/episodes", server.URL)) assertStringContains(t, buf.String(), fmt.Sprintf("could not find programme description on page %v: %v", server.URL+"/brand/57083/about", errCantParse)) } func TestMissingFeed(t *testing.T) { server := helperMockServer(t) defer helperCleanupServer(t) if os.Getenv("DO_CRASH") == "1" { processURL(fmt.Sprintf("%s/brand/57084/episodes", server.URL)) return } cmd := exec.Command(os.Args[0], "-test.run=TestMissingFeed") cmd.Env = append(os.Environ(), "DO_CRASH=1") out, err := cmd.CombinedOutput() if e, ok := err.(*exec.ExitError); !(ok && !e.Success()) { t.Fatalf("process ran with err %v, want exit status 1", err) } assertStringContains(t, string(out), fmt.Sprint("84/episodes: bad programme page")) } func TestServedFeed(t *testing.T) { server := helperMockServer(t) defer helperCleanupServer(t) feed := processURL(fmt.Sprintf("%s/brand/57083/episodes", server.URL)) actual := bytes.ReplaceAll(createFeed(feed), []byte(server.URL), []byte(fakeURL)) golden := filepath.Join("testdata", t.Name()+".golden") if *update { writeFile(actual, golden) } expected, _ := ioutil.ReadFile(golden) if !bytes.Equal(actual, expected) { t.Fail() } } func BenchmarkServedFeed(b *testing.B) { server := helperMockServer(b) defer helperCleanupServer(b) for n := 0; n < b.N; n++ { processURL(fmt.Sprintf("%s/brand/57083/episodes", server.URL)) } } func helperMockServer(t testing.TB) *httptest.Server { t.Helper() fileserver := http.FileServer(http.Dir("testdata")) server := httptest.NewServer(fileserver) episodes := helperLoadBytes(t, "episodes") writeFile(episodes, filepath.Join(pth, "episodes")) about := helperLoadBytes(t, "about") writeFile(about, filepath.Join(pth, "about")) return server } func helperCleanupServer(t testing.TB) { t.Helper() helperCleanupFile(t, "episodes") helperCleanupFile(t, "about") } func helperCleanupFile(t testing.TB, name string) { t.Helper() if err := os.Remove(filepath.Join(pth, name)); err != nil { t.Fatal(err) } } func TestEpisodeURLPrefix(t *testing.T) { url := "http://www.radiorus.ru/brand/57083/episodes" got := episodeURLPrefix(url) want := "http://www.radiorus.ru/brand/" if got != want { t.Fatalf("got %v, want %v", got, want) } } func TestEpisodeID(t *testing.T) { type testval struct { url string id string } var tests = []testval{ {"http://www.radiorus.ru/brand/57083/episode/foo", "http://www.radiorus.ru/brand/57083/episode/foo"}, {"https://www.radiorus.ru/brand/57083/episode/foo", "http://www.radiorus.ru/brand/57083/episode/foo"}, } for _, test := range tests { got := episodeID(test.url) want := test.id if got != want { t.Error("want:", want, "got:", got) } } } func TestStripLink(t *testing.T) { type testval struct { raw string ret string } var tests = []testval{ {`"Аэростат"`, `"Аэростат"`}, } for _, test := range tests { got := stripLink(test.raw) want := test.ret if got != want { t.Error("want:", want, "got:", got) } } }