stash-box/pkg/api/studio_edit_integration_test.go
2022-05-20 11:21:12 +02:00

522 lines
15 KiB
Go

//go:build integration
// +build integration
package api_test
import (
"reflect"
"testing"
"github.com/gofrs/uuid"
"github.com/stashapp/stash-box/pkg/models"
)
type studioEditTestRunner struct {
testRunner
}
func createStudioEditTestRunner(t *testing.T) *studioEditTestRunner {
return &studioEditTestRunner{
testRunner: *asAdmin(t),
}
}
func (s *studioEditTestRunner) testCreateStudioEdit() {
parentStudio, err := s.createTestStudio(nil)
if err != nil {
return
}
parentID := parentStudio.UUID()
name := "Name"
studioEditDetailsInput := models.StudioEditDetailsInput{
Name: &name,
ParentID: &parentID,
}
edit, err := s.createTestStudioEdit(models.OperationEnumCreate, &studioEditDetailsInput, nil)
if err == nil {
s.verifyCreatedStudioEdit(studioEditDetailsInput, edit)
}
}
func (s *studioEditTestRunner) verifyCreatedStudioEdit(input models.StudioEditDetailsInput, edit *models.Edit) {
r := s.resolver.Edit()
if edit.ID == uuid.Nil {
s.t.Errorf("Expected created edit id to be non-zero")
}
details, _ := r.Details(s.ctx, edit)
studioDetails := details.(*models.StudioEdit)
s.verifyEditOperation(models.OperationEnumCreate.String(), edit)
s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit)
s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit)
s.verifyEditApplication(false, edit)
// ensure basic attributes are set correctly
if *input.Name != *studioDetails.Name {
s.fieldMismatch(input.Name, studioDetails.Name, "Name")
}
if *input.ParentID != *studioDetails.ParentID {
s.fieldMismatch(*input.ParentID, *studioDetails.ParentID, "ParentID")
}
}
func (s *studioEditTestRunner) testFindEditById() {
createdEdit, err := s.createTestStudioEdit(models.OperationEnumCreate, nil, nil)
if err != nil {
return
}
edit, err := s.resolver.Query().FindEdit(s.ctx, createdEdit.ID)
if err != nil {
s.t.Errorf("Error finding edit: %s", err.Error())
return
}
// ensure returned studio is not nil
if edit == nil {
s.t.Error("Did not find edit by id")
return
}
}
func (s *studioEditTestRunner) testModifyStudioEdit() {
existingParentStudio, err := s.createTestStudio(nil)
if err != nil {
return
}
existingParentID := existingParentStudio.UUID()
existingName := "studioName"
studioCreateInput := models.StudioCreateInput{
Name: existingName,
ParentID: &existingParentID,
}
createdStudio, err := s.createTestStudio(&studioCreateInput)
if err != nil {
return
}
newParent, err := s.createTestStudio(nil)
if err != nil {
return
}
newParentID := newParent.UUID()
newName := "newName"
site, err := s.createTestSite(nil)
if err != nil {
return
}
url := models.URLInput{
URL: "http://example.org",
SiteID: site.ID,
}
studioEditDetailsInput := models.StudioEditDetailsInput{
Name: &newName,
ParentID: &newParentID,
Urls: []*models.URLInput{&url},
}
id := createdStudio.UUID()
editInput := models.EditInput{
Operation: models.OperationEnumModify,
ID: &id,
}
createdUpdateEdit, err := s.createTestStudioEdit(models.OperationEnumModify, &studioEditDetailsInput, &editInput)
s.verifyUpdatedStudioEdit(createdStudio, studioEditDetailsInput, createdUpdateEdit)
}
func (s *studioEditTestRunner) verifyUpdatedStudioEdit(originalStudio *studioOutput, input models.StudioEditDetailsInput, edit *models.Edit) {
studioDetails := s.getEditStudioDetails(edit)
s.verifyEditOperation(models.OperationEnumModify.String(), edit)
s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit)
s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit)
s.verifyEditApplication(false, edit)
// ensure basic attributes are set correctly
if *input.Name != *studioDetails.Name {
s.fieldMismatch(*input.Name, *studioDetails.Name, "Name")
}
if *input.ParentID != *studioDetails.ParentID {
s.fieldMismatch(*input.ParentID, *studioDetails.ParentID, "ParentID")
}
s.compareURLs(input.Urls, studioDetails.AddedUrls)
}
func (s *studioEditTestRunner) testDestroyStudioEdit() {
createdStudio, err := s.createTestStudio(nil)
if err != nil {
return
}
studioID := createdStudio.UUID()
studioEditDetailsInput := models.StudioEditDetailsInput{}
editInput := models.EditInput{
Operation: models.OperationEnumDestroy,
ID: &studioID,
}
destroyEdit, err := s.createTestStudioEdit(models.OperationEnumDestroy, &studioEditDetailsInput, &editInput)
s.verifyDestroyStudioEdit(studioID, destroyEdit)
}
func (s *studioEditTestRunner) verifyDestroyStudioEdit(studioID uuid.UUID, edit *models.Edit) {
s.verifyEditOperation(models.OperationEnumDestroy.String(), edit)
s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit)
s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit)
s.verifyEditApplication(false, edit)
editTarget := s.getEditStudioTarget(edit)
if studioID != editTarget.ID {
s.fieldMismatch(studioID, editTarget.ID.String(), "ID")
}
}
func (s *studioEditTestRunner) testMergeStudioEdit() {
existingName := "studioName2"
studioCreateInput := models.StudioCreateInput{
Name: existingName,
}
createdPrimaryStudio, err := s.createTestStudio(&studioCreateInput)
if err != nil {
return
}
createdMergeStudio, err := s.createTestStudio(nil)
newName := "newName2"
studioEditDetailsInput := models.StudioEditDetailsInput{
Name: &newName,
}
id := createdPrimaryStudio.UUID()
mergeSources := []uuid.UUID{createdMergeStudio.UUID()}
editInput := models.EditInput{
Operation: models.OperationEnumMerge,
ID: &id,
MergeSourceIds: mergeSources,
}
createdMergeEdit, err := s.createTestStudioEdit(models.OperationEnumMerge, &studioEditDetailsInput, &editInput)
s.verifyMergeStudioEdit(createdPrimaryStudio, studioEditDetailsInput, createdMergeEdit, mergeSources)
}
func (s *studioEditTestRunner) verifyMergeStudioEdit(originalStudio *studioOutput, input models.StudioEditDetailsInput, edit *models.Edit, inputMergeSources []uuid.UUID) {
studioDetails := s.getEditStudioDetails(edit)
s.verifyEditOperation(models.OperationEnumMerge.String(), edit)
s.verifyEditStatus(models.VoteStatusEnumPending.String(), edit)
s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit)
s.verifyEditApplication(false, edit)
// ensure basic attributes are set correctly
if *input.Name != *studioDetails.Name {
s.fieldMismatch(*input.Name, *studioDetails.Name, "Name")
}
var mergeSources []uuid.UUID
merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit)
for i := range merges {
merge := merges[i].(*models.Studio)
mergeSources = append(mergeSources, merge.ID)
}
if !reflect.DeepEqual(inputMergeSources, mergeSources) {
s.fieldMismatch(inputMergeSources, mergeSources, "MergeSources")
}
}
func (s *studioEditTestRunner) testApplyCreateStudioEdit() {
name := "Name"
parent, err := s.createTestStudio(nil)
if err != nil {
return
}
parentID := parent.UUID()
studioEditDetailsInput := models.StudioEditDetailsInput{
Name: &name,
ParentID: &parentID,
}
edit, err := s.createTestStudioEdit(models.OperationEnumCreate, &studioEditDetailsInput, nil)
appliedEdit, err := s.applyEdit(edit.ID)
if err == nil {
s.verifyAppliedStudioCreateEdit(studioEditDetailsInput, appliedEdit)
}
}
func (s *studioEditTestRunner) verifyAppliedStudioCreateEdit(input models.StudioEditDetailsInput, edit *models.Edit) {
if edit.ID == uuid.Nil {
s.t.Errorf("Expected created edit id to be non-zero")
}
s.verifyEditOperation(models.OperationEnumCreate.String(), edit)
s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit)
s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit)
s.verifyEditApplication(true, edit)
studio := s.getEditStudioTarget(edit)
// ensure basic attributes are set correctly
if *input.Name != studio.Name {
s.fieldMismatch(input.Name, studio.Name, "Name")
}
if *input.ParentID != studio.ParentStudioID.UUID {
s.fieldMismatch(*input.ParentID, studio.ParentStudioID.UUID.String(), "ParentID")
}
}
func (s *studioEditTestRunner) testApplyModifyStudioEdit() {
existingName := "studioName3"
site, err := s.createTestSite(nil)
if err != nil {
return
}
studioCreateInput := models.StudioCreateInput{
Name: existingName,
Urls: []*models.URLInput{{
URL: "http://example.org/old",
SiteID: site.ID,
}},
}
createdStudio, err := s.createTestStudio(&studioCreateInput)
if err != nil {
return
}
newName := "newName3"
newParent, err := s.createTestStudio(nil)
if err != nil {
return
}
newParentID := newParent.UUID()
newUrl := models.URLInput{
URL: "http://example.org/new",
SiteID: site.ID,
}
studioEditDetailsInput := models.StudioEditDetailsInput{
Name: &newName,
ParentID: &newParentID,
Urls: []*models.URLInput{&newUrl},
}
id := createdStudio.UUID()
editInput := models.EditInput{
Operation: models.OperationEnumModify,
ID: &id,
}
createdUpdateEdit, err := s.createTestStudioEdit(models.OperationEnumModify, &studioEditDetailsInput, &editInput)
if err != nil {
return
}
appliedEdit, err := s.applyEdit(createdUpdateEdit.ID)
if err != nil {
return
}
modifiedStudio, _ := s.resolver.Query().FindStudio(s.ctx, &id, nil)
s.verifyApplyModifyStudioEdit(studioEditDetailsInput, modifiedStudio, appliedEdit)
}
func (s *studioEditTestRunner) verifyApplyModifyStudioEdit(input models.StudioEditDetailsInput, updatedStudio *models.Studio, edit *models.Edit) {
s.verifyEditOperation(models.OperationEnumModify.String(), edit)
s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit)
s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit)
s.verifyEditApplication(true, edit)
// ensure basic attributes are set correctly
if *input.Name != updatedStudio.Name {
s.fieldMismatch(*input.Name, updatedStudio.Name, "Name")
}
if !updatedStudio.ParentStudioID.Valid || *input.ParentID != updatedStudio.ParentStudioID.UUID {
s.fieldMismatch(*input.ParentID, updatedStudio.ParentStudioID.UUID.String(), "ParentStudioID")
}
urls, _ := s.resolver.Studio().Urls(s.ctx, updatedStudio)
s.compareURLs(input.Urls, urls)
}
func (s *studioEditTestRunner) testApplyDestroyStudioEdit() {
createdStudio, err := s.createTestStudio(nil)
if err != nil {
return
}
studioID := createdStudio.UUID()
sceneInput := models.SceneCreateInput{
StudioID: &studioID,
Date: "2020-03-02",
}
scene, _ := s.createTestScene(&sceneInput)
studioEditDetailsInput := models.StudioEditDetailsInput{}
editInput := models.EditInput{
Operation: models.OperationEnumDestroy,
ID: &studioID,
}
destroyEdit, err := s.createTestStudioEdit(models.OperationEnumDestroy, &studioEditDetailsInput, &editInput)
if err != nil {
return
}
appliedEdit, err := s.applyEdit(destroyEdit.ID)
destroyedStudio, _ := s.resolver.Query().FindStudio(s.ctx, &studioID, nil)
scene, _ = s.client.findScene(scene.UUID())
s.verifyApplyDestroyStudioEdit(destroyedStudio, appliedEdit, scene)
}
func (s *studioEditTestRunner) verifyApplyDestroyStudioEdit(destroyedStudio *models.Studio, edit *models.Edit, scene *sceneOutput) {
s.verifyEditOperation(models.OperationEnumDestroy.String(), edit)
s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit)
s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit)
s.verifyEditApplication(true, edit)
if destroyedStudio.Deleted != true {
s.fieldMismatch(destroyedStudio.Deleted, true, "Deleted")
}
if scene.Studio != nil {
s.fieldMismatch(scene.Studio, nil, "Scene studio")
}
}
func (s *studioEditTestRunner) testApplyMergeStudioEdit() {
mergeSource1, err := s.createTestStudio(nil)
if err != nil {
return
}
mergeSource2, err := s.createTestStudio(nil)
if err != nil {
return
}
mergeTarget, err := s.createTestStudio(nil)
if err != nil {
return
}
// Scene with studio from both source and target, should not cause db unique error
mergeTargetID := mergeTarget.UUID()
sceneInput := models.SceneCreateInput{
StudioID: &mergeTargetID,
Date: "2020-03-02",
}
scene1, err := s.createTestScene(&sceneInput)
if err != nil {
return
}
mergeSource1ID := mergeSource1.UUID()
sceneInput = models.SceneCreateInput{
StudioID: &mergeSource1ID,
Date: "2020-03-02",
}
scene2, err := s.createTestScene(&sceneInput)
if err != nil {
return
}
newName := "newName4"
studioEditDetailsInput := models.StudioEditDetailsInput{
Name: &newName,
}
id := mergeTarget.UUID()
mergeSources := []uuid.UUID{mergeSource1.UUID(), mergeSource2.UUID()}
editInput := models.EditInput{
Operation: models.OperationEnumMerge,
ID: &id,
MergeSourceIds: mergeSources,
}
mergeEdit, err := s.createTestStudioEdit(models.OperationEnumMerge, &studioEditDetailsInput, &editInput)
if err != nil {
return
}
appliedMerge, err := s.applyEdit(mergeEdit.ID)
if err != nil {
return
}
scene1, _ = s.client.findScene(scene1.UUID())
scene2, _ = s.client.findScene(scene2.UUID())
s.verifyAppliedMergeStudioEdit(studioEditDetailsInput, appliedMerge, scene1, scene2)
}
func (s *studioEditTestRunner) verifyAppliedMergeStudioEdit(input models.StudioEditDetailsInput, edit *models.Edit, scene1 *sceneOutput, scene2 *sceneOutput) {
s.verifyEditOperation(models.OperationEnumMerge.String(), edit)
s.verifyEditStatus(models.VoteStatusEnumImmediateAccepted.String(), edit)
s.verifyEditTargetType(models.TargetTypeEnumStudio.String(), edit)
s.verifyEditApplication(true, edit)
studioDetails := s.getEditStudioDetails(edit)
if *input.Name != *studioDetails.Name {
s.fieldMismatch(*input.Name, *studioDetails.Name, "Name")
}
merges, _ := s.resolver.Edit().MergeSources(s.ctx, edit)
for i := range merges {
studio := merges[i].(*models.Studio)
if studio.Deleted != true {
s.fieldMismatch(studio.Deleted, true, "Deleted")
}
}
editTarget := s.getEditStudioTarget(edit)
if scene1.Studio.ID != editTarget.ID.String() {
s.fieldMismatch(scene1.Studio.ID, editTarget.ID, "Scene 1 studio ID")
}
if scene2.Studio.ID != editTarget.ID.String() {
s.fieldMismatch(scene2.Studio.ID, editTarget.ID, "Scene 2 studio ID")
}
}
func TestCreateStudioEdit(t *testing.T) {
pt := createStudioEditTestRunner(t)
pt.testCreateStudioEdit()
}
func TestModifyStudioEdit(t *testing.T) {
pt := createStudioEditTestRunner(t)
pt.testModifyStudioEdit()
}
func TestDestroyStudioEdit(t *testing.T) {
pt := createStudioEditTestRunner(t)
pt.testDestroyStudioEdit()
}
func TestMergeStudioEdit(t *testing.T) {
pt := createStudioEditTestRunner(t)
pt.testMergeStudioEdit()
}
func TestApplyCreateStudioEdit(t *testing.T) {
pt := createStudioEditTestRunner(t)
pt.testApplyCreateStudioEdit()
}
func TestApplyModifyStudioEdit(t *testing.T) {
pt := createStudioEditTestRunner(t)
pt.testApplyModifyStudioEdit()
}
func TestApplyDestroyStudioEdit(t *testing.T) {
pt := createStudioEditTestRunner(t)
pt.testApplyDestroyStudioEdit()
}
func TestApplyMergeStudioEdit(t *testing.T) {
pt := createStudioEditTestRunner(t)
pt.testApplyMergeStudioEdit()
}