mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
* Combine common tag control code into hook * Combine common scraped tag row code into hook
838 lines
20 KiB
Go
838 lines
20 KiB
Go
//go:build integration
|
|
// +build integration
|
|
|
|
package sqlite_test
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stashapp/stash/pkg/models"
|
|
)
|
|
|
|
func loadMovieRelationships(ctx context.Context, expected models.Movie, actual *models.Movie) error {
|
|
if expected.URLs.Loaded() {
|
|
if err := actual.LoadURLs(ctx, db.Movie); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if expected.TagIDs.Loaded() {
|
|
if err := actual.LoadTagIDs(ctx, db.Movie); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func Test_MovieStore_Create(t *testing.T) {
|
|
var (
|
|
name = "name"
|
|
url = "url"
|
|
aliases = "alias1, alias2"
|
|
director = "director"
|
|
rating = 60
|
|
duration = 34
|
|
synopsis = "synopsis"
|
|
date, _ = models.ParseDate("2003-02-01")
|
|
createdAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
updatedAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
newObject models.Movie
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"full",
|
|
models.Movie{
|
|
Name: name,
|
|
Duration: &duration,
|
|
Date: &date,
|
|
Rating: &rating,
|
|
StudioID: &studioIDs[studioIdxWithMovie],
|
|
Director: director,
|
|
Synopsis: synopsis,
|
|
URLs: models.NewRelatedStrings([]string{url}),
|
|
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithMovie]}),
|
|
Aliases: aliases,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"invalid tag id",
|
|
models.Movie{
|
|
Name: name,
|
|
TagIDs: models.NewRelatedIDs([]int{invalidID}),
|
|
},
|
|
true,
|
|
},
|
|
}
|
|
|
|
qb := db.Movie
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
p := tt.newObject
|
|
if err := qb.Create(ctx, &p); (err != nil) != tt.wantErr {
|
|
t.Errorf("MovieStore.Create() error = %v, wantErr = %v", err, tt.wantErr)
|
|
}
|
|
|
|
if tt.wantErr {
|
|
assert.Zero(p.ID)
|
|
return
|
|
}
|
|
|
|
assert.NotZero(p.ID)
|
|
|
|
copy := tt.newObject
|
|
copy.ID = p.ID
|
|
|
|
// load relationships
|
|
if err := loadMovieRelationships(ctx, copy, &p); err != nil {
|
|
t.Errorf("loadMovieRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(copy, p)
|
|
|
|
// ensure can find the movie
|
|
found, err := qb.Find(ctx, p.ID)
|
|
if err != nil {
|
|
t.Errorf("MovieStore.Find() error = %v", err)
|
|
}
|
|
|
|
if !assert.NotNil(found) {
|
|
return
|
|
}
|
|
|
|
// load relationships
|
|
if err := loadMovieRelationships(ctx, copy, found); err != nil {
|
|
t.Errorf("loadMovieRelationships() error = %v", err)
|
|
return
|
|
}
|
|
assert.Equal(copy, *found)
|
|
|
|
return
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_movieQueryBuilder_Update(t *testing.T) {
|
|
var (
|
|
name = "name"
|
|
url = "url"
|
|
aliases = "alias1, alias2"
|
|
director = "director"
|
|
rating = 60
|
|
duration = 34
|
|
synopsis = "synopsis"
|
|
date, _ = models.ParseDate("2003-02-01")
|
|
createdAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
updatedAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
updatedObject *models.Movie
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"full",
|
|
&models.Movie{
|
|
ID: movieIDs[movieIdxWithTag],
|
|
Name: name,
|
|
Duration: &duration,
|
|
Date: &date,
|
|
Rating: &rating,
|
|
StudioID: &studioIDs[studioIdxWithMovie],
|
|
Director: director,
|
|
Synopsis: synopsis,
|
|
URLs: models.NewRelatedStrings([]string{url}),
|
|
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithMovie]}),
|
|
Aliases: aliases,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"clear tag ids",
|
|
&models.Movie{
|
|
ID: movieIDs[movieIdxWithTag],
|
|
Name: name,
|
|
TagIDs: models.NewRelatedIDs([]int{}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"invalid studio id",
|
|
&models.Movie{
|
|
ID: movieIDs[movieIdxWithScene],
|
|
Name: name,
|
|
StudioID: &invalidID,
|
|
},
|
|
true,
|
|
},
|
|
{
|
|
"invalid tag id",
|
|
&models.Movie{
|
|
ID: movieIDs[movieIdxWithScene],
|
|
Name: name,
|
|
TagIDs: models.NewRelatedIDs([]int{invalidID}),
|
|
},
|
|
true,
|
|
},
|
|
}
|
|
|
|
qb := db.Movie
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
copy := *tt.updatedObject
|
|
|
|
if err := qb.Update(ctx, tt.updatedObject); (err != nil) != tt.wantErr {
|
|
t.Errorf("movieQueryBuilder.Update() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
|
|
if tt.wantErr {
|
|
return
|
|
}
|
|
|
|
s, err := qb.Find(ctx, tt.updatedObject.ID)
|
|
if err != nil {
|
|
t.Errorf("movieQueryBuilder.Find() error = %v", err)
|
|
}
|
|
|
|
// load relationships
|
|
if err := loadMovieRelationships(ctx, copy, s); err != nil {
|
|
t.Errorf("loadMovieRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(copy, *s)
|
|
})
|
|
}
|
|
}
|
|
|
|
func clearMoviePartial() models.MoviePartial {
|
|
// leave mandatory fields
|
|
return models.MoviePartial{
|
|
Aliases: models.OptionalString{Set: true, Null: true},
|
|
Synopsis: models.OptionalString{Set: true, Null: true},
|
|
Director: models.OptionalString{Set: true, Null: true},
|
|
Duration: models.OptionalInt{Set: true, Null: true},
|
|
URLs: &models.UpdateStrings{Mode: models.RelationshipUpdateModeSet},
|
|
Date: models.OptionalDate{Set: true, Null: true},
|
|
Rating: models.OptionalInt{Set: true, Null: true},
|
|
StudioID: models.OptionalInt{Set: true, Null: true},
|
|
TagIDs: &models.UpdateIDs{Mode: models.RelationshipUpdateModeSet},
|
|
}
|
|
}
|
|
|
|
func Test_movieQueryBuilder_UpdatePartial(t *testing.T) {
|
|
var (
|
|
name = "name"
|
|
url = "url"
|
|
aliases = "alias1, alias2"
|
|
director = "director"
|
|
rating = 60
|
|
duration = 34
|
|
synopsis = "synopsis"
|
|
date, _ = models.ParseDate("2003-02-01")
|
|
createdAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
updatedAt = time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
id int
|
|
partial models.MoviePartial
|
|
want models.Movie
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"full",
|
|
movieIDs[movieIdxWithScene],
|
|
models.MoviePartial{
|
|
Name: models.NewOptionalString(name),
|
|
Director: models.NewOptionalString(director),
|
|
Synopsis: models.NewOptionalString(synopsis),
|
|
Aliases: models.NewOptionalString(aliases),
|
|
URLs: &models.UpdateStrings{
|
|
Values: []string{url},
|
|
Mode: models.RelationshipUpdateModeSet,
|
|
},
|
|
Date: models.NewOptionalDate(date),
|
|
Duration: models.NewOptionalInt(duration),
|
|
Rating: models.NewOptionalInt(rating),
|
|
StudioID: models.NewOptionalInt(studioIDs[studioIdxWithMovie]),
|
|
CreatedAt: models.NewOptionalTime(createdAt),
|
|
UpdatedAt: models.NewOptionalTime(updatedAt),
|
|
TagIDs: &models.UpdateIDs{
|
|
IDs: []int{tagIDs[tagIdx1WithMovie], tagIDs[tagIdx1WithDupName]},
|
|
Mode: models.RelationshipUpdateModeSet,
|
|
},
|
|
},
|
|
models.Movie{
|
|
ID: movieIDs[movieIdxWithScene],
|
|
Name: name,
|
|
Director: director,
|
|
Synopsis: synopsis,
|
|
Aliases: aliases,
|
|
URLs: models.NewRelatedStrings([]string{url}),
|
|
Date: &date,
|
|
Duration: &duration,
|
|
Rating: &rating,
|
|
StudioID: &studioIDs[studioIdxWithMovie],
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
TagIDs: models.NewRelatedIDs([]int{tagIDs[tagIdx1WithDupName], tagIDs[tagIdx1WithMovie]}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"clear all",
|
|
movieIDs[movieIdxWithScene],
|
|
clearMoviePartial(),
|
|
models.Movie{
|
|
ID: movieIDs[movieIdxWithScene],
|
|
Name: movieNames[movieIdxWithScene],
|
|
TagIDs: models.NewRelatedIDs([]int{}),
|
|
},
|
|
false,
|
|
},
|
|
{
|
|
"invalid id",
|
|
invalidID,
|
|
models.MoviePartial{},
|
|
models.Movie{},
|
|
true,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
qb := db.Movie
|
|
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
got, err := qb.UpdatePartial(ctx, tt.id, tt.partial)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("movieQueryBuilder.UpdatePartial() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
if tt.wantErr {
|
|
return
|
|
}
|
|
|
|
// load relationships
|
|
if err := loadMovieRelationships(ctx, tt.want, got); err != nil {
|
|
t.Errorf("loadMovieRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(tt.want, *got)
|
|
|
|
s, err := qb.Find(ctx, tt.id)
|
|
if err != nil {
|
|
t.Errorf("movieQueryBuilder.Find() error = %v", err)
|
|
}
|
|
|
|
// load relationships
|
|
if err := loadMovieRelationships(ctx, tt.want, s); err != nil {
|
|
t.Errorf("loadMovieRelationships() error = %v", err)
|
|
return
|
|
}
|
|
|
|
assert.Equal(tt.want, *s)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMovieFindByName(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
mqb := db.Movie
|
|
|
|
name := movieNames[movieIdxWithScene] // find a movie by name
|
|
|
|
movie, err := mqb.FindByName(ctx, name, false)
|
|
|
|
if err != nil {
|
|
t.Errorf("Error finding movies: %s", err.Error())
|
|
}
|
|
|
|
assert.Equal(t, movieNames[movieIdxWithScene], movie.Name)
|
|
|
|
name = movieNames[movieIdxWithDupName] // find a movie by name nocase
|
|
|
|
movie, err = mqb.FindByName(ctx, name, true)
|
|
|
|
if err != nil {
|
|
t.Errorf("Error finding movies: %s", err.Error())
|
|
}
|
|
// movieIdxWithDupName and movieIdxWithScene should have similar names ( only diff should be Name vs NaMe)
|
|
//movie.Name should match with movieIdxWithScene since its ID is before moveIdxWithDupName
|
|
assert.Equal(t, movieNames[movieIdxWithScene], movie.Name)
|
|
//movie.Name should match with movieIdxWithDupName if the check is not case sensitive
|
|
assert.Equal(t, strings.ToLower(movieNames[movieIdxWithDupName]), strings.ToLower(movie.Name))
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestMovieFindByNames(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
var names []string
|
|
|
|
mqb := db.Movie
|
|
|
|
names = append(names, movieNames[movieIdxWithScene]) // find movies by names
|
|
|
|
movies, err := mqb.FindByNames(ctx, names, false)
|
|
if err != nil {
|
|
t.Errorf("Error finding movies: %s", err.Error())
|
|
}
|
|
assert.Len(t, movies, 1)
|
|
assert.Equal(t, movieNames[movieIdxWithScene], movies[0].Name)
|
|
|
|
movies, err = mqb.FindByNames(ctx, names, true) // find movies by names nocase
|
|
if err != nil {
|
|
t.Errorf("Error finding movies: %s", err.Error())
|
|
}
|
|
assert.Len(t, movies, 2) // movieIdxWithScene and movieIdxWithDupName
|
|
assert.Equal(t, strings.ToLower(movieNames[movieIdxWithScene]), strings.ToLower(movies[0].Name))
|
|
assert.Equal(t, strings.ToLower(movieNames[movieIdxWithScene]), strings.ToLower(movies[1].Name))
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func moviesToIDs(i []*models.Movie) []int {
|
|
ret := make([]int, len(i))
|
|
for i, v := range i {
|
|
ret[i] = v.ID
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func TestMovieQuery(t *testing.T) {
|
|
var (
|
|
frontImage = "front_image"
|
|
backImage = "back_image"
|
|
)
|
|
|
|
tests := []struct {
|
|
name string
|
|
findFilter *models.FindFilterType
|
|
filter *models.MovieFilterType
|
|
includeIdxs []int
|
|
excludeIdxs []int
|
|
wantErr bool
|
|
}{
|
|
{
|
|
"is missing front image",
|
|
nil,
|
|
&models.MovieFilterType{
|
|
IsMissing: &frontImage,
|
|
},
|
|
// just ensure that it doesn't error
|
|
nil,
|
|
nil,
|
|
false,
|
|
},
|
|
{
|
|
"is missing back image",
|
|
nil,
|
|
&models.MovieFilterType{
|
|
IsMissing: &backImage,
|
|
},
|
|
// just ensure that it doesn't error
|
|
nil,
|
|
nil,
|
|
false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
runWithRollbackTxn(t, tt.name, func(t *testing.T, ctx context.Context) {
|
|
assert := assert.New(t)
|
|
|
|
results, _, err := db.Movie.Query(ctx, tt.filter, tt.findFilter)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("MovieQueryBuilder.Query() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
|
|
ids := moviesToIDs(results)
|
|
include := indexesToIDs(performerIDs, tt.includeIdxs)
|
|
exclude := indexesToIDs(performerIDs, tt.excludeIdxs)
|
|
|
|
for _, i := range include {
|
|
assert.Contains(ids, i)
|
|
}
|
|
for _, e := range exclude {
|
|
assert.NotContains(ids, e)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMovieQueryStudio(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
mqb := db.Movie
|
|
studioCriterion := models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(studioIDs[studioIdxWithMovie]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludes,
|
|
}
|
|
|
|
movieFilter := models.MovieFilterType{
|
|
Studios: &studioCriterion,
|
|
}
|
|
|
|
movies, _, err := mqb.Query(ctx, &movieFilter, nil)
|
|
if err != nil {
|
|
t.Errorf("Error querying movie: %s", err.Error())
|
|
}
|
|
|
|
assert.Len(t, movies, 1)
|
|
|
|
// ensure id is correct
|
|
assert.Equal(t, movieIDs[movieIdxWithStudio], movies[0].ID)
|
|
|
|
studioCriterion = models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(studioIDs[studioIdxWithMovie]),
|
|
},
|
|
Modifier: models.CriterionModifierExcludes,
|
|
}
|
|
|
|
q := getMovieStringValue(movieIdxWithStudio, titleField)
|
|
findFilter := models.FindFilterType{
|
|
Q: &q,
|
|
}
|
|
|
|
movies, _, err = mqb.Query(ctx, &movieFilter, &findFilter)
|
|
if err != nil {
|
|
t.Errorf("Error querying movie: %s", err.Error())
|
|
}
|
|
assert.Len(t, movies, 0)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestMovieQueryURL(t *testing.T) {
|
|
const sceneIdx = 1
|
|
movieURL := getMovieStringValue(sceneIdx, urlField)
|
|
|
|
urlCriterion := models.StringCriterionInput{
|
|
Value: movieURL,
|
|
Modifier: models.CriterionModifierEquals,
|
|
}
|
|
|
|
filter := models.MovieFilterType{
|
|
URL: &urlCriterion,
|
|
}
|
|
|
|
verifyFn := func(n *models.Movie) {
|
|
t.Helper()
|
|
|
|
urls := n.URLs.List()
|
|
var url string
|
|
if len(urls) > 0 {
|
|
url = urls[0]
|
|
}
|
|
|
|
verifyString(t, url, urlCriterion)
|
|
}
|
|
|
|
verifyMovieQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierNotEquals
|
|
verifyMovieQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierMatchesRegex
|
|
urlCriterion.Value = "movie_.*1_URL"
|
|
verifyMovieQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierNotMatchesRegex
|
|
verifyMovieQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierIsNull
|
|
urlCriterion.Value = ""
|
|
verifyMovieQuery(t, filter, verifyFn)
|
|
|
|
urlCriterion.Modifier = models.CriterionModifierNotNull
|
|
verifyMovieQuery(t, filter, verifyFn)
|
|
}
|
|
|
|
func TestMovieQueryURLExcludes(t *testing.T) {
|
|
withRollbackTxn(func(ctx context.Context) error {
|
|
mqb := db.Movie
|
|
|
|
// create movie with two URLs
|
|
movie := models.Movie{
|
|
Name: "TestMovieQueryURLExcludes",
|
|
URLs: models.NewRelatedStrings([]string{
|
|
"aaa",
|
|
"bbb",
|
|
}),
|
|
}
|
|
|
|
err := mqb.Create(ctx, &movie)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating movie: %w", err)
|
|
}
|
|
|
|
// query for movies that exclude the URL "aaa"
|
|
urlCriterion := models.StringCriterionInput{
|
|
Value: "aaa",
|
|
Modifier: models.CriterionModifierExcludes,
|
|
}
|
|
|
|
nameCriterion := models.StringCriterionInput{
|
|
Value: movie.Name,
|
|
Modifier: models.CriterionModifierEquals,
|
|
}
|
|
|
|
filter := models.MovieFilterType{
|
|
URL: &urlCriterion,
|
|
Name: &nameCriterion,
|
|
}
|
|
|
|
movies := queryMovies(ctx, t, &filter, nil)
|
|
assert.Len(t, movies, 0, "Expected no movies to be found")
|
|
|
|
// query for movies that exclude the URL "ccc"
|
|
urlCriterion.Value = "ccc"
|
|
movies = queryMovies(ctx, t, &filter, nil)
|
|
|
|
if assert.Len(t, movies, 1, "Expected one movie to be found") {
|
|
assert.Equal(t, movie.Name, movies[0].Name)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func verifyMovieQuery(t *testing.T, filter models.MovieFilterType, verifyFn func(s *models.Movie)) {
|
|
withTxn(func(ctx context.Context) error {
|
|
t.Helper()
|
|
sqb := db.Movie
|
|
|
|
movies := queryMovies(ctx, t, &filter, nil)
|
|
|
|
for _, movie := range movies {
|
|
if err := movie.LoadURLs(ctx, sqb); err != nil {
|
|
t.Errorf("Error loading movie relationships: %v", err)
|
|
}
|
|
}
|
|
|
|
// assume it should find at least one
|
|
assert.Greater(t, len(movies), 0)
|
|
|
|
for _, m := range movies {
|
|
verifyFn(m)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func queryMovies(ctx context.Context, t *testing.T, movieFilter *models.MovieFilterType, findFilter *models.FindFilterType) []*models.Movie {
|
|
sqb := db.Movie
|
|
movies, _, err := sqb.Query(ctx, movieFilter, findFilter)
|
|
if err != nil {
|
|
t.Errorf("Error querying movie: %s", err.Error())
|
|
}
|
|
|
|
return movies
|
|
}
|
|
|
|
func TestMovieQueryTags(t *testing.T) {
|
|
withTxn(func(ctx context.Context) error {
|
|
tagCriterion := models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdxWithMovie]),
|
|
strconv.Itoa(tagIDs[tagIdx1WithMovie]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludes,
|
|
}
|
|
|
|
movieFilter := models.MovieFilterType{
|
|
Tags: &tagCriterion,
|
|
}
|
|
|
|
// ensure ids are correct
|
|
movies := queryMovies(ctx, t, &movieFilter, nil)
|
|
assert.Len(t, movies, 3)
|
|
for _, movie := range movies {
|
|
assert.True(t, movie.ID == movieIDs[movieIdxWithTag] || movie.ID == movieIDs[movieIdxWithTwoTags] || movie.ID == movieIDs[movieIdxWithThreeTags])
|
|
}
|
|
|
|
tagCriterion = models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdx1WithMovie]),
|
|
strconv.Itoa(tagIDs[tagIdx2WithMovie]),
|
|
},
|
|
Modifier: models.CriterionModifierIncludesAll,
|
|
}
|
|
|
|
movies = queryMovies(ctx, t, &movieFilter, nil)
|
|
|
|
if assert.Len(t, movies, 2) {
|
|
assert.Equal(t, sceneIDs[movieIdxWithTwoTags], movies[0].ID)
|
|
assert.Equal(t, sceneIDs[movieIdxWithThreeTags], movies[1].ID)
|
|
}
|
|
|
|
tagCriterion = models.HierarchicalMultiCriterionInput{
|
|
Value: []string{
|
|
strconv.Itoa(tagIDs[tagIdx1WithMovie]),
|
|
},
|
|
Modifier: models.CriterionModifierExcludes,
|
|
}
|
|
|
|
q := getSceneStringValue(movieIdxWithTwoTags, titleField)
|
|
findFilter := models.FindFilterType{
|
|
Q: &q,
|
|
}
|
|
|
|
movies = queryMovies(ctx, t, &movieFilter, &findFilter)
|
|
assert.Len(t, movies, 0)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestMovieQueryTagCount(t *testing.T) {
|
|
const tagCount = 1
|
|
tagCountCriterion := models.IntCriterionInput{
|
|
Value: tagCount,
|
|
Modifier: models.CriterionModifierEquals,
|
|
}
|
|
|
|
verifyMoviesTagCount(t, tagCountCriterion)
|
|
|
|
tagCountCriterion.Modifier = models.CriterionModifierNotEquals
|
|
verifyMoviesTagCount(t, tagCountCriterion)
|
|
|
|
tagCountCriterion.Modifier = models.CriterionModifierGreaterThan
|
|
verifyMoviesTagCount(t, tagCountCriterion)
|
|
|
|
tagCountCriterion.Modifier = models.CriterionModifierLessThan
|
|
verifyMoviesTagCount(t, tagCountCriterion)
|
|
}
|
|
|
|
func verifyMoviesTagCount(t *testing.T, tagCountCriterion models.IntCriterionInput) {
|
|
withTxn(func(ctx context.Context) error {
|
|
sqb := db.Movie
|
|
movieFilter := models.MovieFilterType{
|
|
TagCount: &tagCountCriterion,
|
|
}
|
|
|
|
movies := queryMovies(ctx, t, &movieFilter, nil)
|
|
assert.Greater(t, len(movies), 0)
|
|
|
|
for _, movie := range movies {
|
|
ids, err := sqb.GetTagIDs(ctx, movie.ID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
verifyInt(t, len(ids), tagCountCriterion)
|
|
}
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestMovieQuerySorting(t *testing.T) {
|
|
sort := "scenes_count"
|
|
direction := models.SortDirectionEnumDesc
|
|
findFilter := models.FindFilterType{
|
|
Sort: &sort,
|
|
Direction: &direction,
|
|
}
|
|
|
|
withTxn(func(ctx context.Context) error {
|
|
movies := queryMovies(ctx, t, nil, &findFilter)
|
|
|
|
// scenes should be in same order as indexes
|
|
firstMovie := movies[0]
|
|
|
|
assert.Equal(t, movieIDs[movieIdxWithScene], firstMovie.ID)
|
|
|
|
// sort in descending order
|
|
direction = models.SortDirectionEnumAsc
|
|
|
|
movies = queryMovies(ctx, t, nil, &findFilter)
|
|
lastMovie := movies[len(movies)-1]
|
|
|
|
assert.Equal(t, movieIDs[movieIdxWithScene], lastMovie.ID)
|
|
|
|
return nil
|
|
})
|
|
}
|
|
|
|
func TestMovieUpdateFrontImage(t *testing.T) {
|
|
if err := withRollbackTxn(func(ctx context.Context) error {
|
|
qb := db.Movie
|
|
|
|
// create movie to test against
|
|
const name = "TestMovieUpdateMovieImages"
|
|
movie := models.Movie{
|
|
Name: name,
|
|
}
|
|
err := qb.Create(ctx, &movie)
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating movie: %s", err.Error())
|
|
}
|
|
|
|
return testUpdateImage(t, ctx, movie.ID, qb.UpdateFrontImage, qb.GetFrontImage)
|
|
}); err != nil {
|
|
t.Error(err.Error())
|
|
}
|
|
}
|
|
|
|
func TestMovieUpdateBackImage(t *testing.T) {
|
|
if err := withRollbackTxn(func(ctx context.Context) error {
|
|
qb := db.Movie
|
|
|
|
// create movie to test against
|
|
const name = "TestMovieUpdateMovieImages"
|
|
movie := models.Movie{
|
|
Name: name,
|
|
}
|
|
err := qb.Create(ctx, &movie)
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating movie: %s", err.Error())
|
|
}
|
|
|
|
return testUpdateImage(t, ctx, movie.ID, qb.UpdateBackImage, qb.GetBackImage)
|
|
}); err != nil {
|
|
t.Error(err.Error())
|
|
}
|
|
}
|
|
|
|
// TODO Update
|
|
// TODO Destroy - ensure image is destroyed
|
|
// TODO Find
|
|
// TODO Count
|
|
// TODO All
|
|
// TODO Query
|