Documentation
¶
Overview ¶
Package pmsconform captures and compares the HTTP surface exposed by Plex Media Servers.
Index ¶
- Constants
- func Clients() map[string]Client
- func FixtureName(profile, path string, jsonMode bool) string
- func Redact(body []byte) []byte
- func SaveFixture(dir, name string, r Response) error
- func SaveFixtureTrimmed(dir, name string, r Response) (int, error)
- func TrimBody(body []byte) ([]byte, bool)
- func WriteSummary(w io.Writer, r Report, values bool)
- func WriteTable(w io.Writer, sums []EndpointSummary)
- func WriteText(w io.Writer, r Report, values bool)
- type Client
- type Difference
- type DiscoveredIDs
- type EndpointSummary
- type PathSummary
- type Report
- type Request
- type Response
Constants ¶
const ( KindMissing = "missing" KindExtra = "extra" KindType = "type" KindValue = "value" KindStatus = "status" KindHeader = "header" KindParse = "parse" KindRequestError = "request_error" )
Difference kinds. Missing, extra, type, status, header, parse and request_error differences are blocking; value differences (including child order, reported at ".../#order" paths) are informational (the two servers hold different titles, so many values legitimately differ).
Variables ¶
This section is empty.
Functions ¶
func Clients ¶
Clients returns representative Plex Web, iOS and Apple TV request profiles, with the X-Plex-Platform values the real apps send (PMS picks its client profile from them and answers 400 to a decision request from an unknown platform such as "iPhone").
func FixtureName ¶
FixtureName is the file name (without ".json") of the fixture for a request made with a client profile in XML or JSON.
func SaveFixture ¶
SaveFixture stores one redacted response as a JSON fixture.
func SaveFixtureTrimmed ¶
SaveFixtureTrimmed redacts and limits each repeated container child list to 50 items. It returns the number of response bodies whose listings were shortened.
func TrimBody ¶
TrimBody truncates XML repeated sibling elements and JSON arrays to their first 50 entries.
func WriteSummary ¶
WriteSummary prints, per endpoint, the missing and extra attributes or elements and the type mismatches (and, with values, the informational value differences), followed by a count table.
func WriteTable ¶
func WriteTable(w io.Writer, sums []EndpointSummary)
WriteTable prints a Markdown table of per-endpoint difference counts (distinct schema paths across clients).
Types ¶
type Difference ¶
type Difference struct {
// Client, Format and Endpoint identify the request (filled by the
// caller that ran it; Compare leaves them empty).
Client string `json:"client,omitempty"`
Format string `json:"format,omitempty"`
Endpoint string `json:"endpoint,omitempty"`
Path string `json:"path"`
Kind string `json:"kind"`
Reference any `json:"reference,omitempty"`
Target any `json:"target,omitempty"`
// Count is how many times the path occurs on the side that has it (the
// reference for missing/type/value, the target for extra).
Count int `json:"count,omitempty"`
// Nested is how many descendant paths of a missing or extra element
// were folded into this difference.
Nested int `json:"nested,omitempty"`
Blocking bool `json:"blocking"`
}
Difference describes one structural or protocol mismatch at one schema path. Array indices are collapsed, so a path stands for every element of a repeated list ("/MediaContainer/Video/@title", "$/MediaContainer/Metadata[]/title").
type DiscoveredIDs ¶
type DiscoveredIDs struct {
Values map[string]string `json:"values"`
Warnings []string `json:"warnings,omitempty"`
}
DiscoveredIDs holds per-server identifiers used to make templated probes target real items.
func Discover ¶
func Discover(ctx context.Context, client *http.Client, base, token, profile string, align *DiscoveredIDs) DiscoveredIDs
Discover reads sections and representative items on one server. If align is non-nil, matching item GUIDs from that server are preferred; absent matches use the first item.
type EndpointSummary ¶
type EndpointSummary struct {
Endpoint string `json:"endpoint"`
Missing []PathSummary `json:"missing,omitempty"`
Extra []PathSummary `json:"extra,omitempty"`
Type []PathSummary `json:"type,omitempty"`
Value []PathSummary `json:"value,omitempty"`
// Other holds status, header, parse and request errors.
Other []PathSummary `json:"other,omitempty"`
}
EndpointSummary groups the differences of one endpoint (all clients and formats).
func Summarize ¶
func Summarize(r Report) []EndpointSummary
Summarize groups a report by endpoint, then by (format, kind, path), so a gap that every client shows is listed once.
func (EndpointSummary) Blocking ¶
func (e EndpointSummary) Blocking() int
Blocking counts the endpoint's blocking path differences.
type PathSummary ¶
type PathSummary struct {
Format string `json:"format"`
Path string `json:"path"`
Kind string `json:"kind"`
Reference string `json:"reference,omitempty"`
Target string `json:"target,omitempty"`
Clients []string `json:"clients"`
Count int `json:"count,omitempty"`
Nested int `json:"nested,omitempty"`
}
PathSummary is one schema difference aggregated across the clients that showed it.
type Report ¶
type Report struct {
Differences []Difference `json:"differences"`
Discovery []string `json:"discovery,omitempty"`
// Endpoints lists every endpoint compared, so summaries can show
// endpoints without differences too.
Endpoints []string `json:"endpoints,omitempty"`
}
Report is the result of comparing responses.
func Compare ¶
Compare checks status, selected headers and the response schema. Bodies are reduced to schemas (paths with array indices collapsed, the set of value types and distinct values seen at each path, and child element order), so two listings of different titles compare by shape: an attribute that PMS emits on some items but the target never emits is "missing", the reverse is "extra", and a JSON number where PMS sends a string is a "type" mismatch. Values that legitimately differ between servers (titles, ids, keys, timestamps, counts, versions, redacted fields) are compared by type only.
func (Report) WithRequest ¶
WithRequest stamps every difference with the request it came from.
type Response ¶
type Response struct {
Status int `json:"status"`
Headers http.Header `json:"headers"`
Body []byte `json:"body"`
}
Response is a captured HTTP response.
func Fetch ¶
func Fetch(ctx context.Context, client *http.Client, base, token string, req Request, profile string, vars map[string]string, jsonMode bool) (Response, error)
Fetch issues a probe, substituting discovered IDs and token, and captures its response.
func LoadFixture ¶
LoadFixture reads a response fixture.