Unit tests for repo watching (#963)
This commit is contained in:
		
							parent
							
								
									847527fd6d
								
							
						
					
					
						commit
						be48b32e63
					
				| @ -33,6 +33,7 @@ | |||||||
|   num_closed_issues: 0 |   num_closed_issues: 0 | ||||||
|   num_pulls: 0 |   num_pulls: 0 | ||||||
|   num_closed_pulls: 0 |   num_closed_pulls: 0 | ||||||
|  |   num_watches: 0 | ||||||
| 
 | 
 | ||||||
| - | - | ||||||
|   id: 4 |   id: 4 | ||||||
|  | |||||||
							
								
								
									
										103
									
								
								models/repo.go
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								models/repo.go
									
									
									
									
									
								
							| @ -2256,109 +2256,6 @@ func (repos MirrorRepositoryList) LoadAttributes() error { | |||||||
| 	return repos.loadAttributes(x) | 	return repos.loadAttributes(x) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| //  __      __         __         .__
 |  | ||||||
| // /  \    /  \_____ _/  |_  ____ |  |__
 |  | ||||||
| // \   \/\/   /\__  \\   __\/ ___\|  |  \
 |  | ||||||
| //  \        /  / __ \|  | \  \___|   Y  \
 |  | ||||||
| //   \__/\  /  (____  /__|  \___  >___|  /
 |  | ||||||
| //        \/        \/          \/     \/
 |  | ||||||
| 
 |  | ||||||
| // Watch is connection request for receiving repository notification.
 |  | ||||||
| type Watch struct { |  | ||||||
| 	ID     int64 `xorm:"pk autoincr"` |  | ||||||
| 	UserID int64 `xorm:"UNIQUE(watch)"` |  | ||||||
| 	RepoID int64 `xorm:"UNIQUE(watch)"` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func isWatching(e Engine, userID, repoID int64) bool { |  | ||||||
| 	has, _ := e.Get(&Watch{0, userID, repoID}) |  | ||||||
| 	return has |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // IsWatching checks if user has watched given repository.
 |  | ||||||
| func IsWatching(userID, repoID int64) bool { |  | ||||||
| 	return isWatching(x, userID, repoID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func watchRepo(e Engine, userID, repoID int64, watch bool) (err error) { |  | ||||||
| 	if watch { |  | ||||||
| 		if isWatching(e, userID, repoID) { |  | ||||||
| 			return nil |  | ||||||
| 		} |  | ||||||
| 		if _, err = e.Insert(&Watch{RepoID: repoID, UserID: userID}); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches + 1 WHERE id = ?", repoID) |  | ||||||
| 	} else { |  | ||||||
| 		if !isWatching(e, userID, repoID) { |  | ||||||
| 			return nil |  | ||||||
| 		} |  | ||||||
| 		if _, err = e.Delete(&Watch{0, userID, repoID}); err != nil { |  | ||||||
| 			return err |  | ||||||
| 		} |  | ||||||
| 		_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?", repoID) |  | ||||||
| 	} |  | ||||||
| 	return err |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // WatchRepo watch or unwatch repository.
 |  | ||||||
| func WatchRepo(userID, repoID int64, watch bool) (err error) { |  | ||||||
| 	return watchRepo(x, userID, repoID, watch) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func getWatchers(e Engine, repoID int64) ([]*Watch, error) { |  | ||||||
| 	watches := make([]*Watch, 0, 10) |  | ||||||
| 	return watches, e.Find(&watches, &Watch{RepoID: repoID}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetWatchers returns all watchers of given repository.
 |  | ||||||
| func GetWatchers(repoID int64) ([]*Watch, error) { |  | ||||||
| 	return getWatchers(x, repoID) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // GetWatchers returns range of users watching given repository.
 |  | ||||||
| func (repo *Repository) GetWatchers(page int) ([]*User, error) { |  | ||||||
| 	users := make([]*User, 0, ItemsPerPage) |  | ||||||
| 	sess := x.Where("watch.repo_id=?", repo.ID). |  | ||||||
| 		Join("LEFT", "watch", "`user`.id=`watch`.user_id") |  | ||||||
| 	if page > 0 { |  | ||||||
| 		sess = sess.Limit(ItemsPerPage, (page-1)*ItemsPerPage) |  | ||||||
| 	} |  | ||||||
| 	return users, sess.Find(&users) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func notifyWatchers(e Engine, act *Action) error { |  | ||||||
| 	// Add feeds for user self and all watchers.
 |  | ||||||
| 	watches, err := getWatchers(e, act.RepoID) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return fmt.Errorf("get watchers: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Add feed for actioner.
 |  | ||||||
| 	act.UserID = act.ActUserID |  | ||||||
| 	if _, err = e.InsertOne(act); err != nil { |  | ||||||
| 		return fmt.Errorf("insert new actioner: %v", err) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	for i := range watches { |  | ||||||
| 		if act.ActUserID == watches[i].UserID { |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		act.ID = 0 |  | ||||||
| 		act.UserID = watches[i].UserID |  | ||||||
| 		if _, err = e.InsertOne(act); err != nil { |  | ||||||
| 			return fmt.Errorf("insert new action: %v", err) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // NotifyWatchers creates batch of actions for every watcher.
 |  | ||||||
| func NotifyWatchers(act *Action) error { |  | ||||||
| 	return notifyWatchers(x, act) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // ___________           __
 | // ___________           __
 | ||||||
| // \_   _____/__________|  | __
 | // \_   _____/__________|  | __
 | ||||||
| //  |    __)/  _ \_  __ \  |/ /
 | //  |    __)/  _ \_  __ \  |/ /
 | ||||||
|  | |||||||
							
								
								
									
										103
									
								
								models/repo_watch.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								models/repo_watch.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,103 @@ | |||||||
|  | // Copyright 2017 The Gitea Authors. All rights reserved.
 | ||||||
|  | // Use of this source code is governed by a MIT-style
 | ||||||
|  | // license that can be found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | package models | ||||||
|  | 
 | ||||||
|  | import "fmt" | ||||||
|  | 
 | ||||||
|  | // Watch is connection request for receiving repository notification.
 | ||||||
|  | type Watch struct { | ||||||
|  | 	ID     int64 `xorm:"pk autoincr"` | ||||||
|  | 	UserID int64 `xorm:"UNIQUE(watch)"` | ||||||
|  | 	RepoID int64 `xorm:"UNIQUE(watch)"` | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func isWatching(e Engine, userID, repoID int64) bool { | ||||||
|  | 	has, _ := e.Get(&Watch{UserID: userID, RepoID: repoID}) | ||||||
|  | 	return has | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IsWatching checks if user has watched given repository.
 | ||||||
|  | func IsWatching(userID, repoID int64) bool { | ||||||
|  | 	return isWatching(x, userID, repoID) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func watchRepo(e Engine, userID, repoID int64, watch bool) (err error) { | ||||||
|  | 	if watch { | ||||||
|  | 		if isWatching(e, userID, repoID) { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		if _, err = e.Insert(&Watch{RepoID: repoID, UserID: userID}); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches + 1 WHERE id = ?", repoID) | ||||||
|  | 	} else { | ||||||
|  | 		if !isWatching(e, userID, repoID) { | ||||||
|  | 			return nil | ||||||
|  | 		} | ||||||
|  | 		if _, err = e.Delete(&Watch{0, userID, repoID}); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		_, err = e.Exec("UPDATE `repository` SET num_watches = num_watches - 1 WHERE id = ?", repoID) | ||||||
|  | 	} | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // WatchRepo watch or unwatch repository.
 | ||||||
|  | func WatchRepo(userID, repoID int64, watch bool) (err error) { | ||||||
|  | 	return watchRepo(x, userID, repoID, watch) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func getWatchers(e Engine, repoID int64) ([]*Watch, error) { | ||||||
|  | 	watches := make([]*Watch, 0, 10) | ||||||
|  | 	return watches, e.Find(&watches, &Watch{RepoID: repoID}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetWatchers returns all watchers of given repository.
 | ||||||
|  | func GetWatchers(repoID int64) ([]*Watch, error) { | ||||||
|  | 	return getWatchers(x, repoID) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetWatchers returns range of users watching given repository.
 | ||||||
|  | func (repo *Repository) GetWatchers(page int) ([]*User, error) { | ||||||
|  | 	users := make([]*User, 0, ItemsPerPage) | ||||||
|  | 	sess := x.Where("watch.repo_id=?", repo.ID). | ||||||
|  | 		Join("LEFT", "watch", "`user`.id=`watch`.user_id") | ||||||
|  | 	if page > 0 { | ||||||
|  | 		sess = sess.Limit(ItemsPerPage, (page-1)*ItemsPerPage) | ||||||
|  | 	} | ||||||
|  | 	return users, sess.Find(&users) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func notifyWatchers(e Engine, act *Action) error { | ||||||
|  | 	// Add feeds for user self and all watchers.
 | ||||||
|  | 	watches, err := getWatchers(e, act.RepoID) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("get watchers: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// Add feed for actioner.
 | ||||||
|  | 	act.UserID = act.ActUserID | ||||||
|  | 	if _, err = e.InsertOne(act); err != nil { | ||||||
|  | 		return fmt.Errorf("insert new actioner: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for i := range watches { | ||||||
|  | 		if act.ActUserID == watches[i].UserID { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		act.ID = 0 | ||||||
|  | 		act.UserID = watches[i].UserID | ||||||
|  | 		if _, err = e.InsertOne(act); err != nil { | ||||||
|  | 			return fmt.Errorf("insert new action: %v", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NotifyWatchers creates batch of actions for every watcher.
 | ||||||
|  | func NotifyWatchers(act *Action) error { | ||||||
|  | 	return notifyWatchers(x, act) | ||||||
|  | } | ||||||
							
								
								
									
										98
									
								
								models/repo_watch_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								models/repo_watch_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | |||||||
|  | // Copyright 2017 The Gitea Authors. All rights reserved.
 | ||||||
|  | // Use of this source code is governed by a MIT-style
 | ||||||
|  | // license that can be found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | package models | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestIsWatching(t *testing.T) { | ||||||
|  | 	assert.NoError(t, PrepareTestDatabase()) | ||||||
|  | 
 | ||||||
|  | 	assert.True(t, IsWatching(1, 1)) | ||||||
|  | 	assert.True(t, IsWatching(4, 1)) | ||||||
|  | 
 | ||||||
|  | 	assert.False(t, IsWatching(1, 5)) | ||||||
|  | 	assert.False(t, IsWatching(NonexistentID, NonexistentID)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestWatchRepo(t *testing.T) { | ||||||
|  | 	assert.NoError(t, PrepareTestDatabase()) | ||||||
|  | 	const repoID = 3 | ||||||
|  | 	const userID = 2 | ||||||
|  | 
 | ||||||
|  | 	assert.NoError(t, WatchRepo(userID, repoID, true)) | ||||||
|  | 	AssertExistsAndLoadBean(t, &Watch{RepoID: repoID, UserID: userID}) | ||||||
|  | 	CheckConsistencyFor(t, &Repository{ID: repoID}) | ||||||
|  | 
 | ||||||
|  | 	assert.NoError(t, WatchRepo(userID, repoID, false)) | ||||||
|  | 	AssertNotExistsBean(t, &Watch{RepoID: repoID, UserID: userID}) | ||||||
|  | 	CheckConsistencyFor(t, &Repository{ID: repoID}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestGetWatchers(t *testing.T) { | ||||||
|  | 	assert.NoError(t, PrepareTestDatabase()) | ||||||
|  | 
 | ||||||
|  | 	repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) | ||||||
|  | 	watches, err := GetWatchers(repo.ID) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Len(t, watches, repo.NumWatches) | ||||||
|  | 	for _, watch := range watches { | ||||||
|  | 		assert.EqualValues(t, repo.ID, watch.RepoID) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	watches, err = GetWatchers(NonexistentID) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Len(t, watches, 0) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestRepository_GetWatchers(t *testing.T) { | ||||||
|  | 	assert.NoError(t, PrepareTestDatabase()) | ||||||
|  | 
 | ||||||
|  | 	repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) | ||||||
|  | 	watchers, err := repo.GetWatchers(1) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Len(t, watchers, repo.NumWatches) | ||||||
|  | 	for _, watcher := range watchers { | ||||||
|  | 		AssertExistsAndLoadBean(t, &Watch{UserID: watcher.ID, RepoID: repo.ID}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	repo = AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository) | ||||||
|  | 	watchers, err = repo.GetWatchers(1) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Len(t, watchers, 0) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestNotifyWatchers(t *testing.T) { | ||||||
|  | 	assert.NoError(t, PrepareTestDatabase()) | ||||||
|  | 
 | ||||||
|  | 	action := &Action{ | ||||||
|  | 		ActUserID: 8, | ||||||
|  | 		RepoID:    1, | ||||||
|  | 		OpType:    ActionStarRepo, | ||||||
|  | 	} | ||||||
|  | 	assert.NoError(t, NotifyWatchers(action)) | ||||||
|  | 
 | ||||||
|  | 	AssertExistsAndLoadBean(t, &Action{ | ||||||
|  | 		ActUserID: action.ActUserID, | ||||||
|  | 		UserID:    1, | ||||||
|  | 		RepoID:    action.RepoID, | ||||||
|  | 		OpType:    action.OpType, | ||||||
|  | 	}) | ||||||
|  | 	AssertExistsAndLoadBean(t, &Action{ | ||||||
|  | 		ActUserID: action.ActUserID, | ||||||
|  | 		UserID:    4, | ||||||
|  | 		RepoID:    action.RepoID, | ||||||
|  | 		OpType:    action.OpType, | ||||||
|  | 	}) | ||||||
|  | 	AssertExistsAndLoadBean(t, &Action{ | ||||||
|  | 		ActUserID: action.ActUserID, | ||||||
|  | 		UserID:    8, | ||||||
|  | 		RepoID:    action.RepoID, | ||||||
|  | 		OpType:    action.OpType, | ||||||
|  | 	}) | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user