code.gitea.io/gitea@v1.22.3/models/activities/action_test.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package activities_test
     5  
     6  import (
     7  	"fmt"
     8  	"path"
     9  	"testing"
    10  
    11  	activities_model "code.gitea.io/gitea/models/activities"
    12  	"code.gitea.io/gitea/models/db"
    13  	issue_model "code.gitea.io/gitea/models/issues"
    14  	repo_model "code.gitea.io/gitea/models/repo"
    15  	"code.gitea.io/gitea/models/unittest"
    16  	user_model "code.gitea.io/gitea/models/user"
    17  	"code.gitea.io/gitea/modules/setting"
    18  
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  func TestAction_GetRepoPath(t *testing.T) {
    23  	assert.NoError(t, unittest.PrepareTestDatabase())
    24  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
    25  	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
    26  	action := &activities_model.Action{RepoID: repo.ID}
    27  	assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath(db.DefaultContext))
    28  }
    29  
    30  func TestAction_GetRepoLink(t *testing.T) {
    31  	assert.NoError(t, unittest.PrepareTestDatabase())
    32  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
    33  	owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID})
    34  	comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{ID: 2})
    35  	action := &activities_model.Action{RepoID: repo.ID, CommentID: comment.ID}
    36  	setting.AppSubURL = "/suburl"
    37  	expected := path.Join(setting.AppSubURL, owner.Name, repo.Name)
    38  	assert.Equal(t, expected, action.GetRepoLink(db.DefaultContext))
    39  	assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink(db.DefaultContext))
    40  	assert.Equal(t, comment.HTMLURL(db.DefaultContext), action.GetCommentHTMLURL(db.DefaultContext))
    41  }
    42  
    43  func TestGetFeeds(t *testing.T) {
    44  	// test with an individual user
    45  	assert.NoError(t, unittest.PrepareTestDatabase())
    46  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
    47  
    48  	actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
    49  		RequestedUser:   user,
    50  		Actor:           user,
    51  		IncludePrivate:  true,
    52  		OnlyPerformedBy: false,
    53  		IncludeDeleted:  true,
    54  	})
    55  	assert.NoError(t, err)
    56  	if assert.Len(t, actions, 1) {
    57  		assert.EqualValues(t, 1, actions[0].ID)
    58  		assert.EqualValues(t, user.ID, actions[0].UserID)
    59  	}
    60  	assert.Equal(t, int64(1), count)
    61  
    62  	actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
    63  		RequestedUser:   user,
    64  		Actor:           user,
    65  		IncludePrivate:  false,
    66  		OnlyPerformedBy: false,
    67  	})
    68  	assert.NoError(t, err)
    69  	assert.Len(t, actions, 0)
    70  	assert.Equal(t, int64(0), count)
    71  }
    72  
    73  func TestGetFeedsForRepos(t *testing.T) {
    74  	assert.NoError(t, unittest.PrepareTestDatabase())
    75  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
    76  	privRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
    77  	pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8})
    78  
    79  	// private repo & no login
    80  	actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
    81  		RequestedRepo:  privRepo,
    82  		IncludePrivate: true,
    83  	})
    84  	assert.NoError(t, err)
    85  	assert.Len(t, actions, 0)
    86  	assert.Equal(t, int64(0), count)
    87  
    88  	// public repo & no login
    89  	actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
    90  		RequestedRepo:  pubRepo,
    91  		IncludePrivate: true,
    92  	})
    93  	assert.NoError(t, err)
    94  	assert.Len(t, actions, 1)
    95  	assert.Equal(t, int64(1), count)
    96  
    97  	// private repo and login
    98  	actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
    99  		RequestedRepo:  privRepo,
   100  		IncludePrivate: true,
   101  		Actor:          user,
   102  	})
   103  	assert.NoError(t, err)
   104  	assert.Len(t, actions, 1)
   105  	assert.Equal(t, int64(1), count)
   106  
   107  	// public repo & login
   108  	actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
   109  		RequestedRepo:  pubRepo,
   110  		IncludePrivate: true,
   111  		Actor:          user,
   112  	})
   113  	assert.NoError(t, err)
   114  	assert.Len(t, actions, 1)
   115  	assert.Equal(t, int64(1), count)
   116  }
   117  
   118  func TestGetFeeds2(t *testing.T) {
   119  	// test with an organization user
   120  	assert.NoError(t, unittest.PrepareTestDatabase())
   121  	org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
   122  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
   123  
   124  	actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
   125  		RequestedUser:   org,
   126  		Actor:           user,
   127  		IncludePrivate:  true,
   128  		OnlyPerformedBy: false,
   129  		IncludeDeleted:  true,
   130  	})
   131  	assert.NoError(t, err)
   132  	assert.Len(t, actions, 1)
   133  	if assert.Len(t, actions, 1) {
   134  		assert.EqualValues(t, 2, actions[0].ID)
   135  		assert.EqualValues(t, org.ID, actions[0].UserID)
   136  	}
   137  	assert.Equal(t, int64(1), count)
   138  
   139  	actions, count, err = activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
   140  		RequestedUser:   org,
   141  		Actor:           user,
   142  		IncludePrivate:  false,
   143  		OnlyPerformedBy: false,
   144  		IncludeDeleted:  true,
   145  	})
   146  	assert.NoError(t, err)
   147  	assert.Len(t, actions, 0)
   148  	assert.Equal(t, int64(0), count)
   149  }
   150  
   151  func TestActivityReadable(t *testing.T) {
   152  	tt := []struct {
   153  		desc   string
   154  		user   *user_model.User
   155  		doer   *user_model.User
   156  		result bool
   157  	}{{
   158  		desc:   "user should see own activity",
   159  		user:   &user_model.User{ID: 1},
   160  		doer:   &user_model.User{ID: 1},
   161  		result: true,
   162  	}, {
   163  		desc:   "anon should see activity if public",
   164  		user:   &user_model.User{ID: 1},
   165  		result: true,
   166  	}, {
   167  		desc:   "anon should NOT see activity",
   168  		user:   &user_model.User{ID: 1, KeepActivityPrivate: true},
   169  		result: false,
   170  	}, {
   171  		desc:   "user should see own activity if private too",
   172  		user:   &user_model.User{ID: 1, KeepActivityPrivate: true},
   173  		doer:   &user_model.User{ID: 1},
   174  		result: true,
   175  	}, {
   176  		desc:   "other user should NOT see activity",
   177  		user:   &user_model.User{ID: 1, KeepActivityPrivate: true},
   178  		doer:   &user_model.User{ID: 2},
   179  		result: false,
   180  	}, {
   181  		desc:   "admin should see activity",
   182  		user:   &user_model.User{ID: 1, KeepActivityPrivate: true},
   183  		doer:   &user_model.User{ID: 2, IsAdmin: true},
   184  		result: true,
   185  	}}
   186  	for _, test := range tt {
   187  		assert.Equal(t, test.result, activities_model.ActivityReadable(test.user, test.doer), test.desc)
   188  	}
   189  }
   190  
   191  func TestNotifyWatchers(t *testing.T) {
   192  	assert.NoError(t, unittest.PrepareTestDatabase())
   193  
   194  	action := &activities_model.Action{
   195  		ActUserID: 8,
   196  		RepoID:    1,
   197  		OpType:    activities_model.ActionStarRepo,
   198  	}
   199  	assert.NoError(t, activities_model.NotifyWatchers(db.DefaultContext, action))
   200  
   201  	// One watchers are inactive, thus action is only created for user 8, 1, 4, 11
   202  	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
   203  		ActUserID: action.ActUserID,
   204  		UserID:    8,
   205  		RepoID:    action.RepoID,
   206  		OpType:    action.OpType,
   207  	})
   208  	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
   209  		ActUserID: action.ActUserID,
   210  		UserID:    1,
   211  		RepoID:    action.RepoID,
   212  		OpType:    action.OpType,
   213  	})
   214  	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
   215  		ActUserID: action.ActUserID,
   216  		UserID:    4,
   217  		RepoID:    action.RepoID,
   218  		OpType:    action.OpType,
   219  	})
   220  	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
   221  		ActUserID: action.ActUserID,
   222  		UserID:    11,
   223  		RepoID:    action.RepoID,
   224  		OpType:    action.OpType,
   225  	})
   226  }
   227  
   228  func TestGetFeedsCorrupted(t *testing.T) {
   229  	// Now we will not check for corrupted data in the feeds
   230  	// users should run doctor to fix their data
   231  	assert.NoError(t, unittest.PrepareTestDatabase())
   232  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
   233  	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
   234  		ID:     8,
   235  		RepoID: 1700,
   236  	})
   237  
   238  	actions, count, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
   239  		RequestedUser:  user,
   240  		Actor:          user,
   241  		IncludePrivate: true,
   242  	})
   243  	assert.NoError(t, err)
   244  	assert.Len(t, actions, 1)
   245  	assert.Equal(t, int64(1), count)
   246  }
   247  
   248  func TestConsistencyUpdateAction(t *testing.T) {
   249  	if !setting.Database.Type.IsSQLite3() {
   250  		t.Skip("Test is only for SQLite database.")
   251  	}
   252  	assert.NoError(t, unittest.PrepareTestDatabase())
   253  	id := 8
   254  	unittest.AssertExistsAndLoadBean(t, &activities_model.Action{
   255  		ID: int64(id),
   256  	})
   257  	_, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id)
   258  	assert.NoError(t, err)
   259  	actions := make([]*activities_model.Action, 0, 1)
   260  	//
   261  	// XORM returns an error when created_unix is a string
   262  	//
   263  	err = db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)
   264  	if assert.Error(t, err) {
   265  		assert.Contains(t, err.Error(), "type string to a int64: invalid syntax")
   266  	}
   267  	//
   268  	// Get rid of incorrectly set created_unix
   269  	//
   270  	count, err := activities_model.CountActionCreatedUnixString(db.DefaultContext)
   271  	assert.NoError(t, err)
   272  	assert.EqualValues(t, 1, count)
   273  	count, err = activities_model.FixActionCreatedUnixString(db.DefaultContext)
   274  	assert.NoError(t, err)
   275  	assert.EqualValues(t, 1, count)
   276  
   277  	count, err = activities_model.CountActionCreatedUnixString(db.DefaultContext)
   278  	assert.NoError(t, err)
   279  	assert.EqualValues(t, 0, count)
   280  	count, err = activities_model.FixActionCreatedUnixString(db.DefaultContext)
   281  	assert.NoError(t, err)
   282  	assert.EqualValues(t, 0, count)
   283  
   284  	//
   285  	// XORM must be happy now
   286  	//
   287  	assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions))
   288  	unittest.CheckConsistencyFor(t, &activities_model.Action{})
   289  }
   290  
   291  func TestDeleteIssueActions(t *testing.T) {
   292  	assert.NoError(t, unittest.PrepareTestDatabase())
   293  
   294  	// load an issue
   295  	issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4})
   296  	assert.NotEqualValues(t, issue.ID, issue.Index) // it needs to use different ID/Index to test the DeleteIssueActions to delete some actions by IssueIndex
   297  
   298  	// insert a comment
   299  	err := db.Insert(db.DefaultContext, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID})
   300  	assert.NoError(t, err)
   301  	comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID})
   302  
   303  	// truncate action table and insert some actions
   304  	err = db.TruncateBeans(db.DefaultContext, &activities_model.Action{})
   305  	assert.NoError(t, err)
   306  	err = db.Insert(db.DefaultContext, &activities_model.Action{
   307  		OpType:    activities_model.ActionCommentIssue,
   308  		CommentID: comment.ID,
   309  	})
   310  	assert.NoError(t, err)
   311  	err = db.Insert(db.DefaultContext, &activities_model.Action{
   312  		OpType:  activities_model.ActionCreateIssue,
   313  		RepoID:  issue.RepoID,
   314  		Content: fmt.Sprintf("%d|content...", issue.Index),
   315  	})
   316  	assert.NoError(t, err)
   317  
   318  	// assert that the actions exist, then delete them
   319  	unittest.AssertCount(t, &activities_model.Action{}, 2)
   320  	assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index))
   321  	unittest.AssertCount(t, &activities_model.Action{}, 0)
   322  }
   323  
   324  func TestRepoActions(t *testing.T) {
   325  	assert.NoError(t, unittest.PrepareTestDatabase())
   326  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
   327  	_ = db.TruncateBeans(db.DefaultContext, &activities_model.Action{})
   328  	for i := 0; i < 3; i++ {
   329  		_ = db.Insert(db.DefaultContext, &activities_model.Action{
   330  			UserID:    2 + int64(i),
   331  			ActUserID: 2,
   332  			RepoID:    repo.ID,
   333  			OpType:    activities_model.ActionCommentIssue,
   334  		})
   335  	}
   336  	count, _ := db.Count[activities_model.Action](db.DefaultContext, &db.ListOptions{})
   337  	assert.EqualValues(t, 3, count)
   338  	actions, _, err := activities_model.GetFeeds(db.DefaultContext, activities_model.GetFeedsOptions{
   339  		RequestedRepo: repo,
   340  	})
   341  	assert.NoError(t, err)
   342  	assert.Len(t, actions, 1)
   343  }