Skip to content

Commit

Permalink
Solution of chain break in move scene (#2408) (#2439)
Browse files Browse the repository at this point in the history
Co-authored-by: kakj <18579115540@163.com>
  • Loading branch information
erda-bot and kakj-go authored Oct 19, 2021
1 parent bee0684 commit 7a2e43f
Show file tree
Hide file tree
Showing 3 changed files with 265 additions and 50 deletions.
189 changes: 139 additions & 50 deletions modules/dop/dao/autotest_scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,72 +219,161 @@ func (db *DBClient) DeleteAutoTestScene(id uint64) (err error) {

// like linklist change to node index
func (db *DBClient) MoveAutoTestScene(id, newPreID, newSetID uint64, tx *gorm.DB) (err error) {
return func() error {
var scene, next, oldNext AutoTestScene
// get scene
if err := tx.Where("id = ?", id).Find(&scene).Error; err != nil {
return err
}
// get next scene
if err := tx.Where("pre_id = ?", id).Find(&oldNext).Error; err != nil {
// not have next scene jump over update next scene
if gorm.IsRecordNotFoundError(err) {
goto LABEL1
}
// a < b < c < d < e
// to
// a < d < c < b < e

// a < d
// d < b
// c < e

var changeScene, nextScene AutoTestScene
var newPreScene, newNextScene AutoTestScene

// get d and pre_id c
changeScene, err = getScene(tx, id)
if err != nil {
return err
}

// get e
nextScene, err = getSceneByPreID(tx, id, 0)
if err != nil {
return err
}

if newPreID > 0 {
// get a
newPreScene, err = getScene(tx, newPreID)
if err != nil {
return err
}
// next scene link this scene pre scene
oldNext.PreID = scene.PreID
if err := tx.Save(&oldNext).Error; err != nil {

// get b
newNextScene, err = getSceneByPreID(tx, newPreID, 0)
if err != nil {
return err
}

defer func() {
err = checkSamePreID(tx, oldNext.SetID, oldNext.PreID)
} else {
if newSetID != 0 {
// get b
newNextScene, err = getSceneByPreID(tx, newPreID, newSetID)
if err != nil {
err = fmt.Errorf("set_id %v have same pre_id %v, please refresh", oldNext.SetID, oldNext.PreID)
return err
}
}()

LABEL1:
// get new next scene pre scene
if err := tx.Where("pre_id = ?", newPreID).Where("set_id = ?", newSetID).Find(&next).Error; err != nil {
// not have new next scene jump over update new next scene
if gorm.IsRecordNotFoundError(err) {
goto LABEL2
} else {
// get b
newNextScene, err = getSceneByPreID(tx, newPreID, changeScene.SetID)
if err != nil {
return err
}
return err
}
// new next scene link this scene
next.PreID = scene.ID
if err := tx.Save(&next).Error; err != nil {
}

var a = newPreScene.ID
var b = newNextScene.ID
var c = changeScene.PreID
var d = changeScene.ID
var e = nextScene.ID

// a < d
if a == d {
return fmt.Errorf("the pre_id of the scene cannot be itself")
}

err = updateScenePreID(tx, d, c, a, newSetID)
if err != nil {
return err
}

// c < e
if e > 0 {
if c == e {
return fmt.Errorf("the pre_id of the scene cannot be itself")
}

err = updateScenePreID(tx, e, d, c, 0)
if err != nil {
return err
}
}

defer func() {
err = checkSamePreID(tx, next.SetID, next.PreID)
if err != nil {
err = fmt.Errorf("set_id %v have same pre_id %v, please refresh", next.SetID, next.PreID)
}
}()
// d < b
if b > 0 {
if d == b {
return fmt.Errorf("the pre_id of the scene cannot be itself")
}

LABEL2:
// this scene link new next scene pre scene
scene.SetID = newSetID
scene.PreID = newPreID
if err := tx.Save(&scene).Error; err != nil {
err = updateScenePreID(tx, b, a, d, 0)
if err != nil {
return err
}
}

defer func() {
err = checkSamePreID(tx, scene.SetID, scene.PreID)
if err != nil {
err = fmt.Errorf("set_id %v have same pre_id %v, please refresh", next.SetID, next.PreID)
}
}()
var setID = changeScene.SetID
if newSetID != 0 {
setID = newSetID
}

return nil
}()
err = checkSceneSetNotHaveSamePreID(tx, setID)
if err != nil {
return err
}

return nil
}

func getScene(tx *gorm.DB, id uint64) (AutoTestScene, error) {
var scene AutoTestScene
if err := tx.Where("id = ?", id).Find(&scene).Error; err != nil {
return scene, err
}
return scene, nil
}

func getSceneByPreID(tx *gorm.DB, preID uint64, setID uint64) (AutoTestScene, error) {
var scene AutoTestScene

tx = tx.Where("pre_id = ?", preID)
if setID > 0 {
tx = tx.Where("set_id = ?", setID)
}

err := tx.First(&scene).Error
if !gorm.IsRecordNotFoundError(err) {
return scene, err
}
return scene, nil
}

func updateScenePreID(tx *gorm.DB, id uint64, preID uint64, newPreID uint64, newSetID uint64) error {
tx = tx.Table(AutoTestScene{}.TableName()).Where("id = ? and pre_id = ?", id, preID)

var updateMap = map[string]interface{}{}

updateMap["pre_id"] = newPreID
if newSetID > 0 {
updateMap["set_id"] = newSetID
}

err := tx.Updates(updateMap).Error
if err != nil {
return err
}
return nil
}

func checkSceneSetNotHaveSamePreID(tx *gorm.DB, setID uint64) error {
rows, err := tx.Table(AutoTestScene{}.TableName()).Select("count(*) as num, pre_id").Where("set_id = ?", setID).Group("pre_id").Having("num > ?", 1).Rows()
if err != nil {
if !gorm.IsRecordNotFoundError(err) {
return err
}
}
if rows.Next() {
return fmt.Errorf("there is a broken link between scenes, please refresh the interface and try again\n")
}
return nil
}

// check sceneSet linked list not have same pre_id
Expand Down
114 changes: 114 additions & 0 deletions modules/dop/dao/autotest_scene_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright (c) 2021 Terminus, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dao

import (
"fmt"
"testing"

"bou.ke/monkey"
"github.com/jinzhu/gorm"

"github.com/erda-project/erda/pkg/database/dbengine"
)

func TestDBClient_MoveAutoTestScene(t *testing.T) {
type args struct {
id uint64
newPreID uint64
newSetID uint64
tx *gorm.DB
}

// a < b < c < d < e
// 1 < 2 < 3 < 4 < 5
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "change a b",
args: args{
id: 4,
newPreID: 1,
newSetID: 0,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
db := &DBClient{}
patch := monkey.Patch(getScene, func(tx *gorm.DB, id uint64) (AutoTestScene, error) {
if tt.name == "change a b" {
if id == tt.args.id {
return AutoTestScene{
BaseModel: dbengine.BaseModel{
ID: tt.args.id,
},
PreID: 3,
}, nil
}
if id == tt.args.newPreID {
return AutoTestScene{
BaseModel: dbengine.BaseModel{
ID: tt.args.newPreID,
},
}, nil
}
}
return AutoTestScene{}, fmt.Errorf("not find")
})
defer patch.Unpatch()

patch1 := monkey.Patch(getSceneByPreID, func(tx *gorm.DB, preID uint64, setID uint64) (AutoTestScene, error) {
if tt.name == "change a b" {
if preID == tt.args.id {
return AutoTestScene{
BaseModel: dbengine.BaseModel{
ID: 5,
},
PreID: tt.args.id,
}, nil
}
if preID == tt.args.newPreID {
return AutoTestScene{
BaseModel: dbengine.BaseModel{
ID: 2,
},
PreID: tt.args.newPreID,
}, nil
}
}
return AutoTestScene{}, fmt.Errorf("not find")
})
defer patch1.Unpatch()

patch2 := monkey.Patch(updateScenePreID, func(tx *gorm.DB, id uint64, preID uint64, newPreID uint64, newSetID uint64) error {
return nil
})
defer patch2.Unpatch()

patch3 := monkey.Patch(checkSceneSetNotHaveSamePreID, func(tx *gorm.DB, setID uint64) error {
return nil
})
defer patch3.Unpatch()

if err := db.MoveAutoTestScene(tt.args.id, tt.args.newPreID, tt.args.newSetID, tt.args.tx); (err != nil) != tt.wantErr {
t.Errorf("MoveAutoTestScene() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
12 changes: 12 additions & 0 deletions modules/dop/endpoints/autotests.http
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
###

GET http://localhost:3033/api/autotests/scenes/2/actions/list-input
Accept: application/json
User-ID: 2
###

PUT http://127.0.0.1:9527/api/autotests/scenes/actions/move-scene
Content-Type: application/json
User-ID: 2

{
"id": 1626,
"target": 1627
}

###
PUT http://localhost:3033/api/autotests/scenes/2/actions/update-input
Expand Down

0 comments on commit 7a2e43f

Please sign in to comment.