all repos

rss-tools @ 2bf041f98c81d4974d119c551a63fca6d8d4c006

get rss feed from sources that(i need and) dont provide one
1 files changed, 161 insertions(+), 0 deletions(-)
add tests for moviefeed
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-05-05 14:52:52 +0300
Authored at: 2026-05-05 14:35:50 +0300
Change ID: rypslmqpwzyxxltrtlsnmmlttpqtpqxw
Parent: 63e22ef
A sources/moviefeed/moviefeed_test.go
ยทยทยท
        
        1
        +package moviefeed

      
        
        2
        +

      
        
        3
        +import (

      
        
        4
        +	"encoding/xml"

      
        
        5
        +	"fmt"

      
        
        6
        +	"net/http"

      
        
        7
        +	"net/http/httptest"

      
        
        8
        +	"net/url"

      
        
        9
        +	"strings"

      
        
        10
        +	"testing"

      
        
        11
        +	"time"

      
        
        12
        +

      
        
        13
        +	"olexsmir.xyz/rss-tools/app"

      
        
        14
        +	"olexsmir.xyz/x/is"

      
        
        15
        +)

      
        
        16
        +

      
        
        17
        +func TestHandleMoviesRendersFeedForRequestedID(t *testing.T) {

      
        
        18
        +	server, client := newTMDBStub(t)

      
        
        19
        +	defer server.Close()

      
        
        20
        +

      
        
        21
        +	mf := &moviefeed{

      
        
        22
        +		api:   NewTMDBAPI("test-key", client),

      
        
        23
        +		shows: nil,

      
        
        24
        +	}

      
        
        25
        +

      
        
        26
        +	mux := http.NewServeMux()

      
        
        27
        +	mux.HandleFunc("GET /movies/{rest...}", mf.handleMovies)

      
        
        28
        +

      
        
        29
        +	req := httptest.NewRequest(http.MethodGet, "/movies/tt123", nil)

      
        
        30
        +	rr := httptest.NewRecorder()

      
        
        31
        +	mux.ServeHTTP(rr, req)

      
        
        32
        +

      
        
        33
        +	is.Equal(t, rr.Code, http.StatusOK)

      
        
        34
        +	if got := rr.Header().Get("Content-Type"); !strings.Contains(got, "application/atom+xml") {

      
        
        35
        +		t.Fatalf("expected atom response content-type, got %q", got)

      
        
        36
        +	}

      
        
        37
        +

      
        
        38
        +	var feed app.AtomFeed

      
        
        39
        +	is.Err(t, xml.NewDecoder(rr.Body).Decode(&feed), nil)

      
        
        40
        +	is.Equal(t, feed.Title, "Episodes from tt123")

      
        
        41
        +	is.Equal(t, feed.ID, "moviefeed-tt123")

      
        
        42
        +	is.Equal(t, len(feed.Entries), 3)                                  // two episodes + one image entry

      
        
        43
        +	is.Equal(t, strings.Contains(feed.Entries[0].Title, "S1E2"), true) // newest first

      
        
        44
        +	is.Equal(t, feed.Entries[2].ID, "tmdb-101-s1e1-img")

      
        
        45
        +}

      
        
        46
        +

      
        
        47
        +func TestHandleMoviesUsesConfiguredShowsForEmptyPath(t *testing.T) {

      
        
        48
        +	server, client := newTMDBStub(t)

      
        
        49
        +	defer server.Close()

      
        
        50
        +

      
        
        51
        +	mf := &moviefeed{

      
        
        52
        +		api:   NewTMDBAPI("test-key", client),

      
        
        53
        +		shows: []string{"tt123"},

      
        
        54
        +	}

      
        
        55
        +

      
        
        56
        +	mux := http.NewServeMux()

      
        
        57
        +	mux.HandleFunc("GET /movies/{rest...}", mf.handleMovies)

      
        
        58
        +

      
        
        59
        +	req := httptest.NewRequest(http.MethodGet, "/movies/", nil)

      
        
        60
        +	rr := httptest.NewRecorder()

      
        
        61
        +	mux.ServeHTTP(rr, req)

      
        
        62
        +

      
        
        63
        +	is.Equal(t, rr.Code, http.StatusOK)

      
        
        64
        +

      
        
        65
        +	var feed app.AtomFeed

      
        
        66
        +	is.Err(t, xml.NewDecoder(rr.Body).Decode(&feed), nil)

      
        
        67
        +	is.Equal(t, feed.ID, "moviefeed-tt123")

      
        
        68
        +}

      
        
        69
        +

      
        
        70
        +func TestHandleMoviesReturnsBadRequestWhenNoIDs(t *testing.T) {

      
        
        71
        +	mf := &moviefeed{

      
        
        72
        +		api:   NewTMDBAPI("test-key", http.DefaultClient),

      
        
        73
        +		shows: nil,

      
        
        74
        +	}

      
        
        75
        +

      
        
        76
        +	mux := http.NewServeMux()

      
        
        77
        +	mux.HandleFunc("GET /movies/{rest...}", mf.handleMovies)

      
        
        78
        +

      
        
        79
        +	req := httptest.NewRequest(http.MethodGet, "/movies/", nil)

      
        
        80
        +	rr := httptest.NewRecorder()

      
        
        81
        +	mux.ServeHTTP(rr, req)

      
        
        82
        +

      
        
        83
        +	is.Equal(t, rr.Code, http.StatusBadRequest)

      
        
        84
        +	is.Equal(t, strings.Contains(rr.Body.String(), "no movie IDs provided"), true)

      
        
        85
        +}

      
        
        86
        +

      
        
        87
        +func TestFetchEpisodesForShowFiltersRecentAndMapsFields(t *testing.T) {

      
        
        88
        +	server, client := newTMDBStub(t)

      
        
        89
        +	defer server.Close()

      
        
        90
        +

      
        
        91
        +	api := NewTMDBAPI("test-key", client)

      
        
        92
        +	episodes, err := api.FetchEpisodesForShow("tt123")

      
        
        93
        +	is.Err(t, err, nil)

      
        
        94
        +

      
        
        95
        +	is.Equal(t, len(episodes), 2) // old episode is filtered out

      
        
        96
        +	is.Equal(t, episodes[0].ShowID, "101")

      
        
        97
        +	is.Equal(t, episodes[0].ShowName, "Test Show")

      
        
        98
        +}

      
        
        99
        +

      
        
        100
        +func newTMDBStub(t *testing.T) (*httptest.Server, *http.Client) {

      
        
        101
        +	t.Helper()

      
        
        102
        +

      
        
        103
        +	recentDay := time.Now().AddDate(0, 0, -7).Format(dateFormat)

      
        
        104
        +	newestDay := time.Now().AddDate(0, 0, -1).Format(dateFormat)

      
        
        105
        +	oldDay := time.Now().AddDate(0, 0, -45).Format(dateFormat)

      
        
        106
        +

      
        
        107
        +	mux := http.NewServeMux()

      
        
        108
        +	mux.HandleFunc("/3/find/tt123", func(w http.ResponseWriter, r *http.Request) {

      
        
        109
        +		if got := r.URL.Query().Get("external_source"); got != "imdb_id" {

      
        
        110
        +			t.Fatalf("unexpected external_source query: %q", got)

      
        
        111
        +		}

      
        
        112
        +		if got := r.URL.Query().Get("api_key"); got != "test-key" {

      
        
        113
        +			t.Fatalf("unexpected api_key query: %q", got)

      
        
        114
        +		}

      
        
        115
        +		_, _ = w.Write([]byte(`{"tv_results":[{"id":101}]}`))

      
        
        116
        +	})

      
        
        117
        +

      
        
        118
        +	mux.HandleFunc("/3/tv/101", func(w http.ResponseWriter, r *http.Request) {

      
        
        119
        +		if got := r.URL.Query().Get("api_key"); got != "test-key" {

      
        
        120
        +			t.Fatalf("unexpected api_key query: %q", got)

      
        
        121
        +		}

      
        
        122
        +		_, _ = w.Write([]byte(`{"id":101,"name":"Test Show","number_of_seasons":1}`))

      
        
        123
        +	})

      
        
        124
        +

      
        
        125
        +	mux.HandleFunc("/3/tv/101/season/1", func(w http.ResponseWriter, r *http.Request) {

      
        
        126
        +		if got := r.URL.Query().Get("api_key"); got != "test-key" {

      
        
        127
        +			t.Fatalf("unexpected api_key query: %q", got)

      
        
        128
        +		}

      
        
        129
        +		body := fmt.Sprintf(`{

      
        
        130
        +			"episodes": [

      
        
        131
        +				{"id": 1001, "name": "Episode 1", "overview": "E1", "air_date": %q, "episode_number": 1, "season_number": 1, "still_path": "/e1.jpg"},

      
        
        132
        +				{"id": 1002, "name": "Episode 2", "overview": "E2", "air_date": %q, "episode_number": 2, "season_number": 1, "still_path": ""},

      
        
        133
        +				{"id": 1003, "name": "Episode old", "overview": "old", "air_date": %q, "episode_number": 3, "season_number": 1, "still_path": ""}

      
        
        134
        +			]

      
        
        135
        +		}`, recentDay, newestDay, oldDay)

      
        
        136
        +		_, _ = w.Write([]byte(body))

      
        
        137
        +	})

      
        
        138
        +

      
        
        139
        +	server := httptest.NewServer(mux)

      
        
        140
        +	target, err := url.Parse(server.URL)

      
        
        141
        +	is.Err(t, err, nil)

      
        
        142
        +

      
        
        143
        +	client := &http.Client{

      
        
        144
        +		Transport: rewriteTransport{target: target},

      
        
        145
        +	}

      
        
        146
        +	return server, client

      
        
        147
        +}

      
        
        148
        +

      
        
        149
        +type rewriteTransport struct {

      
        
        150
        +	target *url.URL

      
        
        151
        +}

      
        
        152
        +

      
        
        153
        +func (t rewriteTransport) RoundTrip(req *http.Request) (*http.Response, error) {

      
        
        154
        +	clone := req.Clone(req.Context())

      
        
        155
        +	copiedURL := *clone.URL

      
        
        156
        +	copiedURL.Scheme = t.target.Scheme

      
        
        157
        +	copiedURL.Host = t.target.Host

      
        
        158
        +	clone.URL = &copiedURL

      
        
        159
        +	clone.Host = t.target.Host

      
        
        160
        +	return http.DefaultTransport.RoundTrip(clone)

      
        
        161
        +}