code.gitea.io/gitea@v1.21.7/tests/integration/api_repo_lfs_locks_test.go (about)

     1  // Copyright 2017 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package integration
     5  
     6  import (
     7  	"fmt"
     8  	"net/http"
     9  	"testing"
    10  	"time"
    11  
    12  	repo_model "code.gitea.io/gitea/models/repo"
    13  	"code.gitea.io/gitea/models/unittest"
    14  	user_model "code.gitea.io/gitea/models/user"
    15  	"code.gitea.io/gitea/modules/lfs"
    16  	"code.gitea.io/gitea/modules/setting"
    17  	api "code.gitea.io/gitea/modules/structs"
    18  	"code.gitea.io/gitea/tests"
    19  
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  func TestAPILFSLocksNotStarted(t *testing.T) {
    24  	defer tests.PrepareTestEnv(t)()
    25  	setting.LFS.StartServer = false
    26  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
    27  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
    28  
    29  	req := NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks", user.Name, repo.Name)
    30  	MakeRequest(t, req, http.StatusNotFound)
    31  	req = NewRequestf(t, "POST", "/%s/%s.git/info/lfs/locks", user.Name, repo.Name)
    32  	MakeRequest(t, req, http.StatusNotFound)
    33  	req = NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks/verify", user.Name, repo.Name)
    34  	MakeRequest(t, req, http.StatusNotFound)
    35  	req = NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks/10/unlock", user.Name, repo.Name)
    36  	MakeRequest(t, req, http.StatusNotFound)
    37  }
    38  
    39  func TestAPILFSLocksNotLogin(t *testing.T) {
    40  	defer tests.PrepareTestEnv(t)()
    41  	setting.LFS.StartServer = true
    42  	user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
    43  	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
    44  
    45  	req := NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks", user.Name, repo.Name)
    46  	req.Header.Set("Accept", lfs.MediaType)
    47  	resp := MakeRequest(t, req, http.StatusUnauthorized)
    48  	var lfsLockError api.LFSLockError
    49  	DecodeJSON(t, resp, &lfsLockError)
    50  	assert.Equal(t, "You must have pull access to list locks", lfsLockError.Message)
    51  }
    52  
    53  func TestAPILFSLocksLogged(t *testing.T) {
    54  	defer tests.PrepareTestEnv(t)()
    55  	setting.LFS.StartServer = true
    56  	user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // in org 3
    57  	user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // in org 3
    58  
    59  	repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
    60  	repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // own by org 3
    61  
    62  	tests := []struct {
    63  		user       *user_model.User
    64  		repo       *repo_model.Repository
    65  		path       string
    66  		httpResult int
    67  		addTime    []int
    68  	}{
    69  		{user: user2, repo: repo1, path: "foo/bar.zip", httpResult: http.StatusCreated, addTime: []int{0}},
    70  		{user: user2, repo: repo1, path: "path/test", httpResult: http.StatusCreated, addTime: []int{0}},
    71  		{user: user2, repo: repo1, path: "path/test", httpResult: http.StatusConflict},
    72  		{user: user2, repo: repo1, path: "Foo/BaR.zip", httpResult: http.StatusConflict},
    73  		{user: user2, repo: repo1, path: "Foo/Test/../subFOlder/../Relative/../BaR.zip", httpResult: http.StatusConflict},
    74  		{user: user4, repo: repo1, path: "FoO/BaR.zip", httpResult: http.StatusUnauthorized},
    75  		{user: user4, repo: repo1, path: "path/test-user4", httpResult: http.StatusUnauthorized},
    76  		{user: user2, repo: repo1, path: "patH/Test-user4", httpResult: http.StatusCreated, addTime: []int{0}},
    77  		{user: user2, repo: repo1, path: "some/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/long/path", httpResult: http.StatusCreated, addTime: []int{0}},
    78  
    79  		{user: user2, repo: repo3, path: "test/foo/bar.zip", httpResult: http.StatusCreated, addTime: []int{1, 2}},
    80  		{user: user4, repo: repo3, path: "test/foo/bar.zip", httpResult: http.StatusConflict},
    81  		{user: user4, repo: repo3, path: "test/foo/bar.bin", httpResult: http.StatusCreated, addTime: []int{1, 2}},
    82  	}
    83  
    84  	resultsTests := []struct {
    85  		user        *user_model.User
    86  		repo        *repo_model.Repository
    87  		totalCount  int
    88  		oursCount   int
    89  		theirsCount int
    90  		locksOwners []*user_model.User
    91  		locksTimes  []time.Time
    92  	}{
    93  		{user: user2, repo: repo1, totalCount: 4, oursCount: 4, theirsCount: 0, locksOwners: []*user_model.User{user2, user2, user2, user2}, locksTimes: []time.Time{}},
    94  		{user: user2, repo: repo3, totalCount: 2, oursCount: 1, theirsCount: 1, locksOwners: []*user_model.User{user2, user4}, locksTimes: []time.Time{}},
    95  		{user: user4, repo: repo3, totalCount: 2, oursCount: 1, theirsCount: 1, locksOwners: []*user_model.User{user2, user4}, locksTimes: []time.Time{}},
    96  	}
    97  
    98  	deleteTests := []struct {
    99  		user   *user_model.User
   100  		repo   *repo_model.Repository
   101  		lockID string
   102  	}{}
   103  
   104  	// create locks
   105  	for _, test := range tests {
   106  		session := loginUser(t, test.user.Name)
   107  		req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks", test.repo.FullName()), map[string]string{"path": test.path})
   108  		req.Header.Set("Accept", lfs.MediaType)
   109  		req.Header.Set("Content-Type", lfs.MediaType)
   110  		resp := session.MakeRequest(t, req, test.httpResult)
   111  		if len(test.addTime) > 0 {
   112  			var lfsLock api.LFSLockResponse
   113  			DecodeJSON(t, resp, &lfsLock)
   114  			assert.Equal(t, test.user.Name, lfsLock.Lock.Owner.Name)
   115  			assert.EqualValues(t, lfsLock.Lock.LockedAt.Format(time.RFC3339), lfsLock.Lock.LockedAt.Format(time.RFC3339Nano)) // locked at should be rounded to second
   116  			for _, id := range test.addTime {
   117  				resultsTests[id].locksTimes = append(resultsTests[id].locksTimes, time.Now())
   118  			}
   119  		}
   120  	}
   121  
   122  	// check creation
   123  	for _, test := range resultsTests {
   124  		session := loginUser(t, test.user.Name)
   125  		req := NewRequestf(t, "GET", "/%s.git/info/lfs/locks", test.repo.FullName())
   126  		req.Header.Set("Accept", lfs.MediaType)
   127  		resp := session.MakeRequest(t, req, http.StatusOK)
   128  		var lfsLocks api.LFSLockList
   129  		DecodeJSON(t, resp, &lfsLocks)
   130  		assert.Len(t, lfsLocks.Locks, test.totalCount)
   131  		for i, lock := range lfsLocks.Locks {
   132  			assert.EqualValues(t, test.locksOwners[i].Name, lock.Owner.Name)
   133  			assert.WithinDuration(t, test.locksTimes[i], lock.LockedAt, 10*time.Second)
   134  			assert.EqualValues(t, lock.LockedAt.Format(time.RFC3339), lock.LockedAt.Format(time.RFC3339Nano)) // locked at should be rounded to second
   135  		}
   136  
   137  		req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/verify", test.repo.FullName()), map[string]string{})
   138  		req.Header.Set("Accept", lfs.MediaType)
   139  		req.Header.Set("Content-Type", lfs.MediaType)
   140  		resp = session.MakeRequest(t, req, http.StatusOK)
   141  		var lfsLocksVerify api.LFSLockListVerify
   142  		DecodeJSON(t, resp, &lfsLocksVerify)
   143  		assert.Len(t, lfsLocksVerify.Ours, test.oursCount)
   144  		assert.Len(t, lfsLocksVerify.Theirs, test.theirsCount)
   145  		for _, lock := range lfsLocksVerify.Ours {
   146  			assert.EqualValues(t, test.user.Name, lock.Owner.Name)
   147  			deleteTests = append(deleteTests, struct {
   148  				user   *user_model.User
   149  				repo   *repo_model.Repository
   150  				lockID string
   151  			}{test.user, test.repo, lock.ID})
   152  		}
   153  		for _, lock := range lfsLocksVerify.Theirs {
   154  			assert.NotEqual(t, test.user.DisplayName(), lock.Owner.Name)
   155  		}
   156  	}
   157  
   158  	// remove all locks
   159  	for _, test := range deleteTests {
   160  		session := loginUser(t, test.user.Name)
   161  		req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/%s.git/info/lfs/locks/%s/unlock", test.repo.FullName(), test.lockID), map[string]string{})
   162  		req.Header.Set("Accept", lfs.MediaType)
   163  		req.Header.Set("Content-Type", lfs.MediaType)
   164  		resp := session.MakeRequest(t, req, http.StatusOK)
   165  		var lfsLockRep api.LFSLockResponse
   166  		DecodeJSON(t, resp, &lfsLockRep)
   167  		assert.Equal(t, test.lockID, lfsLockRep.Lock.ID)
   168  		assert.Equal(t, test.user.Name, lfsLockRep.Lock.Owner.Name)
   169  	}
   170  
   171  	// check that we don't have any lock
   172  	for _, test := range resultsTests {
   173  		session := loginUser(t, test.user.Name)
   174  		req := NewRequestf(t, "GET", "/%s.git/info/lfs/locks", test.repo.FullName())
   175  		req.Header.Set("Accept", lfs.MediaType)
   176  		resp := session.MakeRequest(t, req, http.StatusOK)
   177  		var lfsLocks api.LFSLockList
   178  		DecodeJSON(t, resp, &lfsLocks)
   179  		assert.Len(t, lfsLocks.Locks, 0)
   180  	}
   181  }