fix: Fix #230, Add tests for shared collectors (#231)

* fix: Fix #230, Add tests for shared collectors

Signed-off-by: Russell Troxel <russell@troxel.io>

* Fix lint: common TestServer

Signed-off-by: Russell Troxel <russell@troxel.io>

---------

Signed-off-by: Russell Troxel <russell@troxel.io>
This commit is contained in:
Russell Troxel 2023-10-18 03:47:40 -07:00 committed by GitHub
parent 3155232c1f
commit 8c51f278ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 844 additions and 26 deletions

4
go.sum
View File

@ -68,16 +68,12 @@ go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ=
go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=

View File

@ -8,26 +8,15 @@ import (
"testing"
"github.com/onedr0p/exportarr/internal/arr/config"
"github.com/onedr0p/exportarr/internal/test_util"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
)
const test_fixtures_path = "../test_fixtures/bazarr/"
const API_KEY = "abcdef0123456789abcdef0123456789"
const bazarr_test_fixtures_path = "../test_fixtures/bazarr/"
func newTestBazarrServer(t *testing.T, fn func(http.ResponseWriter, *http.Request)) (*httptest.Server, error) {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fn(w, r)
require.NotEmpty(t, r.URL.Path)
// turns /api/some/path into some_path
endpoint := strings.Replace(strings.Replace(r.URL.Path, "/api/", "", -1), "/", "_", -1)
w.WriteHeader(http.StatusOK)
// NOTE: this assumes there is a file that matches the some_path
json, err := os.ReadFile(test_fixtures_path + endpoint + ".json")
require.NoError(t, err)
_, err = w.Write(json)
require.NoError(t, err)
})), nil
return test_util.NewTestServer(t, bazarr_test_fixtures_path, fn)
}
func TestBazarrCollect(t *testing.T) {
@ -42,12 +31,12 @@ func TestBazarrCollect(t *testing.T) {
config := &config.ArrConfig{
URL: ts.URL,
App: "bazarr",
ApiKey: API_KEY,
ApiKey: test_util.API_KEY,
}
collector := NewBazarrCollector(config)
require.NoError(err)
b, err := os.ReadFile(test_fixtures_path + "expected_metrics.txt")
b, err := os.ReadFile(bazarr_test_fixtures_path + "expected_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
@ -109,7 +98,7 @@ func TestBazarrCollect_FailureDoesntPanic(t *testing.T) {
config := &config.ArrConfig{
URL: ts.URL,
ApiKey: API_KEY,
ApiKey: test_util.API_KEY,
}
collector := NewBazarrCollector(config)

View File

@ -0,0 +1,107 @@
package collector
import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/onedr0p/exportarr/internal/arr/config"
"github.com/onedr0p/exportarr/internal/test_util"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
)
func TestSystemHealthCollect(t *testing.T) {
var tests = []struct {
name string
config *config.ArrConfig
path string
}{
{
name: "radarr",
config: &config.ArrConfig{
App: "radarr",
ApiVersion: "v3",
},
path: "/api/v3/health",
},
{
name: "sonarr",
config: &config.ArrConfig{
App: "sonarr",
ApiVersion: "v3",
},
path: "/api/v3/health",
},
{
name: "lidarr",
config: &config.ArrConfig{
App: "lidarr",
ApiVersion: "v1",
},
path: "/api/v1/health",
},
{
name: "readarr",
config: &config.ArrConfig{
App: "readarr",
ApiVersion: "v1",
},
path: "/api/v1/health",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
ts, err := test_util.NewTestSharedServer(t, func(w http.ResponseWriter, r *http.Request) {
require.Contains(r.URL.Path, tt.path)
})
require.NoError(err)
defer ts.Close()
tt.config.URL = ts.URL
tt.config.ApiKey = test_util.API_KEY
collector := NewSystemHealthCollector(tt.config)
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_health_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
f := strings.NewReader(expected)
require.NotPanics(func() {
err = testutil.CollectAndCompare(collector, f)
})
require.NoError(err)
})
}
}
func TestSystemHealthCollect_FailureDoesntPanic(t *testing.T) {
require := require.New(t)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer ts.Close()
config := &config.ArrConfig{
URL: ts.URL,
ApiKey: test_util.API_KEY,
}
collector := NewSystemHealthCollector(config)
f := strings.NewReader("")
require.NotPanics(func() {
err := testutil.CollectAndCompare(collector, f)
require.Error(err)
}, "Collecting metrics should not panic on failure")
}

View File

@ -0,0 +1,107 @@
package collector
import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/onedr0p/exportarr/internal/arr/config"
"github.com/onedr0p/exportarr/internal/test_util"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
)
func TestHistoryCollect(t *testing.T) {
var tests = []struct {
name string
config *config.ArrConfig
path string
}{
{
name: "radarr",
config: &config.ArrConfig{
App: "radarr",
ApiVersion: "v3",
},
path: "/api/v3/history",
},
{
name: "sonarr",
config: &config.ArrConfig{
App: "sonarr",
ApiVersion: "v3",
},
path: "/api/v3/history",
},
{
name: "lidarr",
config: &config.ArrConfig{
App: "lidarr",
ApiVersion: "v1",
},
path: "/api/v1/history",
},
{
name: "readarr",
config: &config.ArrConfig{
App: "readarr",
ApiVersion: "v1",
},
path: "/api/v1/history",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
ts, err := test_util.NewTestSharedServer(t, func(w http.ResponseWriter, r *http.Request) {
require.Contains(r.URL.Path, tt.path)
})
require.NoError(err)
defer ts.Close()
tt.config.URL = ts.URL
tt.config.ApiKey = test_util.API_KEY
collector := NewHistoryCollector(tt.config)
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_history_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
f := strings.NewReader(expected)
require.NotPanics(func() {
err = testutil.CollectAndCompare(collector, f)
})
require.NoError(err)
})
}
}
func TestHistoryCollect_FailureDoesntPanic(t *testing.T) {
require := require.New(t)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer ts.Close()
config := &config.ArrConfig{
URL: ts.URL,
ApiKey: test_util.API_KEY,
}
collector := NewHistoryCollector(config)
f := strings.NewReader("")
require.NotPanics(func() {
err := testutil.CollectAndCompare(collector, f)
require.Error(err)
}, "Collecting metrics should not panic on failure")
}

View File

@ -169,7 +169,7 @@ func (collector *lidarrCollector) Collect(ch chan<- prometheus.Metric) {
if collector.config.EnableAdditionalMetrics {
songFile := model.SongFile{}
var params client.QueryParams
params := client.QueryParams{}
params.Add("artistid", fmt.Sprintf("%d", s.Id))
if err := c.DoRequest("trackfile", &songFile, params); err != nil {

View File

@ -318,7 +318,7 @@ func (collector *prowlarrCollector) Collect(ch chan<- prometheus.Metric) {
startDate := collector.lastStatUpdate.In(time.UTC)
endDate := time.Now().In(time.UTC)
var params client.QueryParams
params := client.QueryParams{}
params.Add("startDate", startDate.Format(time.RFC3339))
params.Add("endDate", endDate.Format(time.RFC3339))

View File

@ -48,7 +48,7 @@ func (collector *queueCollector) Collect(ch chan<- prometheus.Metric) {
return
}
var params client.QueryParams
params := client.QueryParams{}
params.Add("page", "1")
if collector.config.EnableUnknownQueueItems {
if collector.config.App == "sonarr" {

View File

@ -0,0 +1,107 @@
package collector
import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/onedr0p/exportarr/internal/arr/config"
"github.com/onedr0p/exportarr/internal/test_util"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
)
func TestQueueCollect(t *testing.T) {
var tests = []struct {
name string
config *config.ArrConfig
path string
}{
{
name: "radarr",
config: &config.ArrConfig{
App: "radarr",
ApiVersion: "v3",
},
path: "/api/v3/queue",
},
{
name: "sonarr",
config: &config.ArrConfig{
App: "sonarr",
ApiVersion: "v3",
},
path: "/api/v3/queue",
},
{
name: "lidarr",
config: &config.ArrConfig{
App: "lidarr",
ApiVersion: "v1",
},
path: "/api/v1/queue",
},
{
name: "readarr",
config: &config.ArrConfig{
App: "readarr",
ApiVersion: "v1",
},
path: "/api/v1/queue",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
ts, err := test_util.NewTestSharedServer(t, func(w http.ResponseWriter, r *http.Request) {
require.Contains(r.URL.Path, tt.path)
})
require.NoError(err)
defer ts.Close()
tt.config.URL = ts.URL
tt.config.ApiKey = test_util.API_KEY
collector := NewQueueCollector(tt.config)
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_queue_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
f := strings.NewReader(expected)
require.NotPanics(func() {
err = testutil.CollectAndCompare(collector, f)
})
require.NoError(err)
})
}
}
func TestQueueCollect_FailureDoesntPanic(t *testing.T) {
require := require.New(t)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer ts.Close()
config := &config.ArrConfig{
URL: ts.URL,
ApiKey: test_util.API_KEY,
}
collector := NewQueueCollector(config)
f := strings.NewReader("")
require.NotPanics(func() {
err := testutil.CollectAndCompare(collector, f)
require.Error(err)
}, "Collecting metrics should not panic on failure")
}

View File

@ -0,0 +1,107 @@
package collector
import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/onedr0p/exportarr/internal/arr/config"
"github.com/onedr0p/exportarr/internal/test_util"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
)
func TestRootFolderCollect(t *testing.T) {
var tests = []struct {
name string
config *config.ArrConfig
path string
}{
{
name: "radarr",
config: &config.ArrConfig{
App: "radarr",
ApiVersion: "v3",
},
path: "/api/v3/rootfolder",
},
{
name: "sonarr",
config: &config.ArrConfig{
App: "sonarr",
ApiVersion: "v3",
},
path: "/api/v3/rootfolder",
},
{
name: "lidarr",
config: &config.ArrConfig{
App: "lidarr",
ApiVersion: "v1",
},
path: "/api/v1/rootfolder",
},
{
name: "readarr",
config: &config.ArrConfig{
App: "readarr",
ApiVersion: "v1",
},
path: "/api/v1/rootfolder",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
ts, err := test_util.NewTestSharedServer(t, func(w http.ResponseWriter, r *http.Request) {
require.Contains(r.URL.Path, tt.path)
})
require.NoError(err)
defer ts.Close()
tt.config.URL = ts.URL
tt.config.ApiKey = test_util.API_KEY
collector := NewRootFolderCollector(tt.config)
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_rootfolder_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
f := strings.NewReader(expected)
require.NotPanics(func() {
err = testutil.CollectAndCompare(collector, f)
})
require.NoError(err)
})
}
}
func TestRootFolderCollect_FailureDoesntPanic(t *testing.T) {
require := require.New(t)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer ts.Close()
config := &config.ArrConfig{
URL: ts.URL,
ApiKey: test_util.API_KEY,
}
collector := NewRootFolderCollector(config)
f := strings.NewReader("")
require.NotPanics(func() {
err := testutil.CollectAndCompare(collector, f)
require.Error(err)
}, "Collecting metrics should not panic on failure")
}

View File

@ -220,7 +220,7 @@ func (collector *sonarrCollector) Collect(ch chan<- prometheus.Metric) {
textra := time.Now()
episodeFile := model.EpisodeFile{}
var params client.QueryParams
params := client.QueryParams{}
params.Add("seriesId", fmt.Sprintf("%d", s.Id))
if err := c.DoRequest("episodefile", &episodeFile, params); err != nil {
@ -261,7 +261,7 @@ func (collector *sonarrCollector) Collect(ch chan<- prometheus.Metric) {
episodesMissing := model.Missing{}
var params client.QueryParams
params := client.QueryParams{}
params.Add("sortKey", "airDateUtc")
if err := c.DoRequest("wanted/missing", &episodesMissing, params); err != nil {

View File

@ -0,0 +1,107 @@
package collector
import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"github.com/onedr0p/exportarr/internal/arr/config"
"github.com/onedr0p/exportarr/internal/test_util"
"github.com/prometheus/client_golang/prometheus/testutil"
"github.com/stretchr/testify/require"
)
func TestStatusCollect(t *testing.T) {
var tests = []struct {
name string
config *config.ArrConfig
path string
}{
{
name: "radarr",
config: &config.ArrConfig{
App: "radarr",
ApiVersion: "v3",
},
path: "/api/v3/system/status",
},
{
name: "sonarr",
config: &config.ArrConfig{
App: "sonarr",
ApiVersion: "v3",
},
path: "/api/v3/system/status",
},
{
name: "lidarr",
config: &config.ArrConfig{
App: "lidarr",
ApiVersion: "v1",
},
path: "/api/v1/system/status",
},
{
name: "readarr",
config: &config.ArrConfig{
App: "readarr",
ApiVersion: "v1",
},
path: "/api/v1/system/status",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require := require.New(t)
ts, err := test_util.NewTestSharedServer(t, func(w http.ResponseWriter, r *http.Request) {
require.Contains(r.URL.Path, tt.path)
})
require.NoError(err)
defer ts.Close()
tt.config.URL = ts.URL
tt.config.ApiKey = test_util.API_KEY
collector := NewSystemStatusCollector(tt.config)
b, err := os.ReadFile(test_util.COMMON_FIXTURES_PATH + "expected_status_metrics.txt")
require.NoError(err)
expected := strings.Replace(string(b), "SOMEURL", ts.URL, -1)
expected = strings.Replace(expected, "APP", tt.config.App, -1)
f := strings.NewReader(expected)
require.NotPanics(func() {
err = testutil.CollectAndCompare(collector, f)
})
require.NoError(err)
})
}
}
func TestStatusCollect_FailureDoesntPanic(t *testing.T) {
require := require.New(t)
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
}))
defer ts.Close()
config := &config.ArrConfig{
URL: ts.URL,
ApiKey: test_util.API_KEY,
}
collector := NewSystemStatusCollector(config)
f := strings.NewReader("")
require.NotPanics(func() {
err := testutil.CollectAndCompare(collector, f)
require.Error(err)
}, "Collecting metrics should not panic on failure")
}

View File

@ -0,0 +1,3 @@
# HELP APP_system_health_issues Total number of health issues by source, type, message and wikiurl
# TYPE APP_system_health_issues gauge
APP_system_health_issues{message="Indexers unavailable due to failures for more than 6 hours: SomeIndexer",source="IndexerLongTermStatusCheck",type="warning",url="SOMEURL",wikiurl="https://wiki.servarr.com/readarr/system#indexers-are-unavailable-due-to-failures"} 1

View File

@ -0,0 +1,3 @@
# HELP APP_history_total Total number of item in the history
# TYPE APP_history_total gauge
APP_history_total{url="SOMEURL"} 1368

View File

@ -0,0 +1,3 @@
# HELP APP_queue_total Total number of items in the queue by status, download_status, and download_state
# TYPE APP_queue_total gauge
APP_queue_total{download_state="downloading",download_status="warning",status="completed",url="SOMEURL"} 1

View File

@ -0,0 +1,3 @@
# HELP APP_rootfolder_freespace_bytes Root folder space in bytes by path
# TYPE APP_rootfolder_freespace_bytes gauge
APP_rootfolder_freespace_bytes{path="/media/books/",url="SOMEURL"} 3.2147635175424e+13

View File

@ -0,0 +1,3 @@
# HELP APP_system_status System Status
# TYPE APP_system_status gauge
APP_system_status{url="SOMEURL"} 1

View File

@ -0,0 +1,8 @@
[
{
"source": "IndexerLongTermStatusCheck",
"type": "warning",
"message": "Indexers unavailable due to failures for more than 6 hours: SomeIndexer",
"wikiUrl": "https://wiki.servarr.com/readarr/system#indexers-are-unavailable-due-to-failures"
}
]

View File

@ -0,0 +1,8 @@
{
"page": 1,
"pageSize": 10,
"sortKey": "date",
"sortDirection": "descending",
"totalRecords": 1368,
"records": []
}

View File

@ -0,0 +1,69 @@
{
"page": 1,
"pageSize": 10,
"sortKey": "timeleft",
"sortDirection": "ascending",
"totalRecords": 1,
"records": [
{
"movieId": 91,
"languages": [],
"quality": {
"quality": {
"id": 7,
"name": "Bluray-1080p",
"source": "bluray",
"resolution": 1080,
"modifier": "none"
},
"revision": {
"version": 2,
"real": 0,
"isRepack": false
}
},
"customFormats": [
{
"id": 6,
"name": "Special Edition"
},
{
"id": 8,
"name": "Repack/Proper"
},
{
"id": 27,
"name": "DTS-ES"
},
{
"id": 44,
"name": "HD Bluray Tier 02"
}
],
"customFormatScore": 1880,
"size": 24397988960,
"title": "Some.Movie.1.Has.A.Title-1080P",
"sizeleft": 0,
"timeleft": "00:00:00",
"estimatedCompletionTime": "2023-10-17T23:23:09Z",
"status": "completed",
"trackedDownloadStatus": "warning",
"trackedDownloadState": "downloading",
"statusMessages": [
{
"title": "Some.Movie.1.Has.A.Title-1080P",
"messages": [
"Found matching movie via grab history, but release was matched to movie by ID. Manual Import required."
]
}
],
"errorMessage": "",
"downloadId": "SABnzbd_nzo_asdf1234",
"protocol": "usenet",
"downloadClient": "SabNZBd",
"indexer": "Some Indexer",
"outputPath": "/media/.downloads/complete/movies/Some.Movie.1.Has.A.Title-1080P",
"id": 8537983
}
]
}

View File

@ -0,0 +1,6 @@
[
{
"path": "/media/books/",
"freeSpace": 32147635175424
}
]

View File

@ -0,0 +1,32 @@
{
"appName": "Radarr",
"instanceName": "Radarr",
"version": "5.0.3.8127",
"buildTime": "2023-10-07T22:36:20Z",
"isDebug": false,
"isProduction": true,
"isAdmin": false,
"isUserInteractive": true,
"startupPath": "/app/bin",
"appData": "/config",
"osName": "alpine",
"osVersion": "3.18.4",
"isNetCore": true,
"isLinux": true,
"isOsx": false,
"isWindows": false,
"isDocker": false,
"mode": "console",
"branch": "develop",
"databaseType": "sqLite",
"databaseVersion": "3.41.2",
"authentication": "none",
"migrationVersion": 233,
"urlBase": "",
"runtimeVersion": "6.0.21",
"runtimeName": "netcore",
"startTime": "2023-10-13T20:45:26Z",
"packageVersion": "5.0.3.8127",
"packageAuthor": "[onedr0p](https://github.com/onedr0p)",
"packageUpdateMechanism": "docker"
}

View File

@ -0,0 +1,8 @@
[
{
"source": "IndexerLongTermStatusCheck",
"type": "warning",
"message": "Indexers unavailable due to failures for more than 6 hours: SomeIndexer",
"wikiUrl": "https://wiki.servarr.com/readarr/system#indexers-are-unavailable-due-to-failures"
}
]

View File

@ -0,0 +1,8 @@
{
"page": 1,
"pageSize": 10,
"sortKey": "date",
"sortDirection": "descending",
"totalRecords": 1368,
"records": []
}

View File

@ -0,0 +1,69 @@
{
"page": 1,
"pageSize": 10,
"sortKey": "timeleft",
"sortDirection": "ascending",
"totalRecords": 1,
"records": [
{
"movieId": 91,
"languages": [],
"quality": {
"quality": {
"id": 7,
"name": "Bluray-1080p",
"source": "bluray",
"resolution": 1080,
"modifier": "none"
},
"revision": {
"version": 2,
"real": 0,
"isRepack": false
}
},
"customFormats": [
{
"id": 6,
"name": "Special Edition"
},
{
"id": 8,
"name": "Repack/Proper"
},
{
"id": 27,
"name": "DTS-ES"
},
{
"id": 44,
"name": "HD Bluray Tier 02"
}
],
"customFormatScore": 1880,
"size": 24397988960,
"title": "Some.Movie.1.Has.A.Title-1080P",
"sizeleft": 0,
"timeleft": "00:00:00",
"estimatedCompletionTime": "2023-10-17T23:23:09Z",
"status": "completed",
"trackedDownloadStatus": "warning",
"trackedDownloadState": "downloading",
"statusMessages": [
{
"title": "Some.Movie.1.Has.A.Title-1080P",
"messages": [
"Found matching movie via grab history, but release was matched to movie by ID. Manual Import required."
]
}
],
"errorMessage": "",
"downloadId": "SABnzbd_nzo_asdf1234",
"protocol": "usenet",
"downloadClient": "SabNZBd",
"indexer": "Some Indexer",
"outputPath": "/media/.downloads/complete/movies/Some.Movie.1.Has.A.Title-1080P",
"id": 8537983
}
]
}

View File

@ -0,0 +1,6 @@
[
{
"path": "/media/books/",
"freeSpace": 32147635175424
}
]

View File

@ -0,0 +1,32 @@
{
"appName": "Radarr",
"instanceName": "Radarr",
"version": "5.0.3.8127",
"buildTime": "2023-10-07T22:36:20Z",
"isDebug": false,
"isProduction": true,
"isAdmin": false,
"isUserInteractive": true,
"startupPath": "/app/bin",
"appData": "/config",
"osName": "alpine",
"osVersion": "3.18.4",
"isNetCore": true,
"isLinux": true,
"isOsx": false,
"isWindows": false,
"isDocker": false,
"mode": "console",
"branch": "develop",
"databaseType": "sqLite",
"databaseVersion": "3.41.2",
"authentication": "none",
"migrationVersion": 233,
"urlBase": "",
"runtimeVersion": "6.0.21",
"runtimeName": "netcore",
"startTime": "2023-10-13T20:45:26Z",
"packageVersion": "5.0.3.8127",
"packageAuthor": "[onedr0p](https://github.com/onedr0p)",
"packageUpdateMechanism": "docker"
}

View File

@ -0,0 +1,5 @@
package test_util
const API_KEY = "abcdef0123456789abcdef0123456789"
const FIXTURES_DIR = "../test_fixtures/"
const COMMON_FIXTURES_PATH = FIXTURES_DIR + "common/"

View File

@ -0,0 +1,32 @@
package test_util
import (
"os"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func NewTestServer(t *testing.T, fixture_dir string, fn func(http.ResponseWriter, *http.Request)) (*httptest.Server, error) {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fn(w, r)
require.NotEmpty(t, r.URL.Path)
// turns /api/some/path into some_path
endpoint := strings.Replace(strings.Replace(r.URL.Path, "/api/", "", -1), "/", "_", -1)
w.WriteHeader(http.StatusOK)
// NOTE: this assumes there is a file that matches the some_path
json, err := os.ReadFile(filepath.Join(fixture_dir, endpoint+".json"))
require.NoError(t, err)
_, err = w.Write(json)
require.NoError(t, err)
})), nil
}
func NewTestSharedServer(t *testing.T, fn func(http.ResponseWriter, *http.Request)) (*httptest.Server, error) {
return NewTestServer(t, COMMON_FIXTURES_PATH, fn)
}