github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/env/actions/commitwalk/commitwalk_test.go (about) 1 // Copyright 2019 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package commitwalk 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 25 "github.com/dolthub/dolt/go/libraries/doltcore/doltdb" 26 "github.com/dolthub/dolt/go/libraries/doltcore/env" 27 "github.com/dolthub/dolt/go/libraries/doltcore/merge" 28 "github.com/dolthub/dolt/go/libraries/doltcore/ref" 29 "github.com/dolthub/dolt/go/libraries/utils/filesys" 30 "github.com/dolthub/dolt/go/store/datas" 31 "github.com/dolthub/dolt/go/store/datas/pull" 32 "github.com/dolthub/dolt/go/store/hash" 33 "github.com/dolthub/dolt/go/store/types" 34 ) 35 36 const ( 37 testHomeDir = "/doesnotexist/home" 38 workingDir = "/doesnotexist/work" 39 ) 40 41 var lastUserTSMillis int64 42 43 func MonotonicNow() time.Time { 44 now := time.Now() 45 millis := now.UnixMilli() 46 if millis <= lastUserTSMillis { 47 now = time.UnixMilli(lastUserTSMillis).Add(time.Millisecond) 48 } 49 lastUserTSMillis = now.UnixMilli() 50 return now 51 } 52 53 func testHomeDirFunc() (string, error) { 54 return testHomeDir, nil 55 } 56 57 func createUninitializedEnv() *env.DoltEnv { 58 initialDirs := []string{testHomeDir, workingDir} 59 fs := filesys.NewInMemFS(initialDirs, nil, workingDir) 60 dEnv := env.Load(context.Background(), testHomeDirFunc, fs, doltdb.InMemDoltDB, "test") 61 return dEnv 62 } 63 64 func TestGetDotDotRevisions(t *testing.T) { 65 dEnv := createUninitializedEnv() 66 err := dEnv.InitRepo(context.Background(), types.Format_Default, "Bill Billerson", "bill@billerson.com", env.DefaultInitBranch) 67 require.NoError(t, err) 68 69 cs, err := doltdb.NewCommitSpec(env.DefaultInitBranch) 70 require.NoError(t, err) 71 opt, err := dEnv.DoltDB.Resolve(context.Background(), cs, nil) 72 require.NoError(t, err) 73 commit, ok := opt.ToCommit() 74 require.True(t, ok) 75 76 rv, err := commit.GetRootValue(context.Background()) 77 require.NoError(t, err) 78 r, rvh, err := dEnv.DoltDB.WriteRootValue(context.Background(), rv) 79 require.NoError(t, err) 80 rv = r 81 82 // Create 5 commits on main. 83 mainCommits := make([]*doltdb.Commit, 6) 84 mainCommits[0] = commit 85 for i := 1; i < 6; i++ { 86 mainCommits[i] = mustCreateCommit(t, dEnv.DoltDB, env.DefaultInitBranch, rvh, mainCommits[i-1]) 87 } 88 89 // Create a feature branch. 90 bref := ref.NewBranchRef("feature") 91 err = dEnv.DoltDB.NewBranchAtCommit(context.Background(), bref, mainCommits[5], nil) 92 require.NoError(t, err) 93 94 // Create 3 commits on feature branch. 95 featureCommits := []*doltdb.Commit{} 96 featureCommits = append(featureCommits, mainCommits[5]) 97 for i := 1; i < 4; i++ { 98 featureCommits = append(featureCommits, mustCreateCommit(t, dEnv.DoltDB, "feature", rvh, featureCommits[i-1])) 99 } 100 101 // Create 1 commit on main. 102 mainCommits = append(mainCommits, mustCreateCommit(t, dEnv.DoltDB, env.DefaultInitBranch, rvh, mainCommits[5])) 103 104 // Merge main to feature branch. 105 featureCommits = append(featureCommits, mustCreateCommit(t, dEnv.DoltDB, "feature", rvh, featureCommits[3], mainCommits[6])) 106 107 // Create 3 commits on feature branch. 108 for i := 5; i < 8; i++ { 109 featureCommits = append(featureCommits, mustCreateCommit(t, dEnv.DoltDB, "feature", rvh, featureCommits[i-1])) 110 } 111 112 // Create 3 commits on main. 113 for i := 7; i < 10; i++ { 114 mainCommits = append(mainCommits, mustCreateCommit(t, dEnv.DoltDB, env.DefaultInitBranch, rvh, mainCommits[i-1])) 115 } 116 117 // Branches look like this: 118 // 119 // feature: F1--F2--F3--F4--F5--F6--F7 120 // / / 121 // main: M0--M1--M2--M3--M4--M5/F0------------M6--M7--M8--M9 122 123 featureHash := mustGetHash(t, featureCommits[7]) 124 mainHash := mustGetHash(t, mainCommits[6]) 125 featurePreMergeHash := mustGetHash(t, featureCommits[3]) 126 127 res, err := GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{featureHash}, dEnv.DoltDB, []hash.Hash{mainHash}, 100) 128 require.NoError(t, err) 129 130 assert.Len(t, res, 7) 131 assertEqualHashes(t, featureCommits[7], res[0]) 132 assertEqualHashes(t, featureCommits[6], res[1]) 133 assertEqualHashes(t, featureCommits[5], res[2]) 134 assertEqualHashes(t, featureCommits[4], res[3]) 135 assertEqualHashes(t, featureCommits[3], res[4]) 136 assertEqualHashes(t, featureCommits[2], res[5]) 137 assertEqualHashes(t, featureCommits[1], res[6]) 138 139 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{mainHash}, dEnv.DoltDB, []hash.Hash{featureHash}, 100) 140 require.NoError(t, err) 141 assert.Len(t, res, 0) 142 143 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{featureHash}, dEnv.DoltDB, []hash.Hash{mainHash}, 3) 144 require.NoError(t, err) 145 assert.Len(t, res, 3) 146 assertEqualHashes(t, featureCommits[7], res[0]) 147 assertEqualHashes(t, featureCommits[6], res[1]) 148 assertEqualHashes(t, featureCommits[5], res[2]) 149 150 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{featurePreMergeHash}, dEnv.DoltDB, []hash.Hash{mainHash}, 3) 151 require.NoError(t, err) 152 assert.Len(t, res, 3) 153 assertEqualHashes(t, featureCommits[3], res[0]) 154 assertEqualHashes(t, featureCommits[2], res[1]) 155 assertEqualHashes(t, featureCommits[1], res[2]) 156 157 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{featurePreMergeHash}, dEnv.DoltDB, []hash.Hash{mainHash}, 3) 158 require.NoError(t, err) 159 assert.Len(t, res, 3) 160 assertEqualHashes(t, featureCommits[3], res[0]) 161 assertEqualHashes(t, featureCommits[2], res[1]) 162 assertEqualHashes(t, featureCommits[1], res[2]) 163 164 // Three dot 165 mergeBaseHash, err := merge.MergeBase(context.Background(), mainCommits[6], featureCommits[7]) 166 require.NoError(t, err) 167 168 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{featureHash, mainHash}, dEnv.DoltDB, []hash.Hash{mergeBaseHash}, -1) 169 require.NoError(t, err) 170 assert.Len(t, res, 7) 171 assertEqualHashes(t, featureCommits[7], res[0]) 172 assertEqualHashes(t, featureCommits[6], res[1]) 173 assertEqualHashes(t, featureCommits[5], res[2]) 174 assertEqualHashes(t, featureCommits[4], res[3]) 175 assertEqualHashes(t, featureCommits[3], res[4]) 176 assertEqualHashes(t, featureCommits[2], res[5]) 177 assertEqualHashes(t, featureCommits[1], res[6]) 178 179 mergeBaseHash, err = merge.MergeBase(context.Background(), mainCommits[6], featureCommits[3]) 180 require.NoError(t, err) 181 182 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{featurePreMergeHash, mainHash}, dEnv.DoltDB, []hash.Hash{mergeBaseHash}, -1) 183 require.NoError(t, err) 184 assert.Len(t, res, 4) 185 assertEqualHashes(t, featureCommits[3], res[0]) 186 assertEqualHashes(t, featureCommits[2], res[1]) 187 assertEqualHashes(t, mainCommits[6], res[2]) 188 assertEqualHashes(t, featureCommits[1], res[3]) 189 190 // Create a similar branch to "feature" on a forked repository and GetDotDotRevisions using that as well. 191 forkEnv := mustForkDB(t, dEnv.DoltDB, "feature", featureCommits[4]) 192 193 // Create 3 commits on feature branch. 194 for i := 5; i < 8; i++ { 195 featureCommits[i] = mustCreateCommit(t, forkEnv.DoltDB, "feature", rvh, featureCommits[i-1]) 196 } 197 198 featureHash = mustGetHash(t, featureCommits[7]) 199 mainHash = mustGetHash(t, mainCommits[6]) 200 featurePreMergeHash = mustGetHash(t, featureCommits[3]) 201 202 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{featureHash}, dEnv.DoltDB, []hash.Hash{mainHash}, 100) 203 require.Error(t, err) 204 res, err = GetDotDotRevisions(context.Background(), forkEnv.DoltDB, []hash.Hash{featureHash}, dEnv.DoltDB, []hash.Hash{mainHash}, 100) 205 require.NoError(t, err) 206 assert.Len(t, res, 7) 207 assertEqualHashes(t, featureCommits[7], res[0]) 208 assertEqualHashes(t, featureCommits[6], res[1]) 209 assertEqualHashes(t, featureCommits[5], res[2]) 210 assertEqualHashes(t, featureCommits[4], res[3]) 211 assertEqualHashes(t, featureCommits[3], res[4]) 212 assertEqualHashes(t, featureCommits[2], res[5]) 213 assertEqualHashes(t, featureCommits[1], res[6]) 214 215 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{mainHash}, dEnv.DoltDB, []hash.Hash{featureHash}, 100) 216 require.Error(t, err) 217 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{mainHash}, forkEnv.DoltDB, []hash.Hash{featureHash}, 100) 218 require.NoError(t, err) 219 assert.Len(t, res, 0) 220 221 res, err = GetDotDotRevisions(context.Background(), forkEnv.DoltDB, []hash.Hash{featureHash}, dEnv.DoltDB, []hash.Hash{mainHash}, 3) 222 require.NoError(t, err) 223 assert.Len(t, res, 3) 224 assertEqualHashes(t, featureCommits[7], res[0]) 225 assertEqualHashes(t, featureCommits[6], res[1]) 226 assertEqualHashes(t, featureCommits[5], res[2]) 227 228 res, err = GetDotDotRevisions(context.Background(), dEnv.DoltDB, []hash.Hash{featurePreMergeHash}, dEnv.DoltDB, []hash.Hash{mainHash}, 3) 229 require.NoError(t, err) 230 assert.Len(t, res, 3) 231 assertEqualHashes(t, featureCommits[3], res[0]) 232 assertEqualHashes(t, featureCommits[2], res[1]) 233 assertEqualHashes(t, featureCommits[1], res[2]) 234 235 res, err = GetDotDotRevisions(context.Background(), forkEnv.DoltDB, []hash.Hash{featurePreMergeHash}, dEnv.DoltDB, []hash.Hash{mainHash}, 3) 236 require.NoError(t, err) 237 assert.Len(t, res, 3) 238 assertEqualHashes(t, featureCommits[3], res[0]) 239 assertEqualHashes(t, featureCommits[2], res[1]) 240 assertEqualHashes(t, featureCommits[1], res[2]) 241 } 242 243 func assertEqualHashes(t *testing.T, lc, rc interface{}) { 244 leftCm, ok := lc.(*doltdb.Commit) 245 if !ok { 246 opt, ok := lc.(*doltdb.OptionalCommit) 247 require.True(t, ok) 248 leftCm, ok = opt.ToCommit() 249 require.True(t, ok) 250 } 251 252 rightCm, ok := rc.(*doltdb.Commit) 253 if !ok { 254 opt, ok := rc.(*doltdb.OptionalCommit) 255 require.True(t, ok) 256 rightCm, ok = opt.ToCommit() 257 require.True(t, ok) 258 } 259 260 assert.Equal(t, mustGetHash(t, leftCm), mustGetHash(t, rightCm)) 261 } 262 263 func mustCreateCommit(t *testing.T, ddb *doltdb.DoltDB, bn string, rvh hash.Hash, parents ...*doltdb.Commit) *doltdb.Commit { 264 cm, err := datas.NewCommitMetaWithUserTS("Bill Billerson", "bill@billerson.com", "A New Commit.", MonotonicNow()) 265 require.NoError(t, err) 266 pcs := make([]*doltdb.CommitSpec, 0, len(parents)) 267 for _, parent := range parents { 268 cs, err := doltdb.NewCommitSpec(mustGetHash(t, parent).String()) 269 require.NoError(t, err) 270 pcs = append(pcs, cs) 271 } 272 bref := ref.NewBranchRef(bn) 273 commit, err := ddb.CommitWithParentSpecs(context.Background(), rvh, bref, pcs, cm) 274 require.NoError(t, err) 275 return commit 276 } 277 278 func mustForkDB(t *testing.T, fromDB *doltdb.DoltDB, bn string, cm *doltdb.Commit) *env.DoltEnv { 279 h, err := cm.HashOf() 280 require.NoError(t, err) 281 forkEnv := createUninitializedEnv() 282 err = forkEnv.InitRepo(context.Background(), types.Format_Default, "Bill Billerson", "bill@billerson.com", env.DefaultInitBranch) 283 require.NoError(t, err) 284 ps := make(chan pull.Stats) 285 go func() { 286 for range ps { 287 } 288 }() 289 err = forkEnv.DoltDB.PullChunks(context.Background(), "", fromDB, []hash.Hash{h}, ps, nil) 290 if err == pull.ErrDBUpToDate { 291 err = nil 292 } 293 require.NoError(t, err) 294 err = forkEnv.DoltDB.SetHead(context.Background(), ref.NewBranchRef(bn), h) 295 require.NoError(t, err) 296 return forkEnv 297 } 298 299 func mustGetHash(t *testing.T, c *doltdb.Commit) hash.Hash { 300 h, err := c.HashOf() 301 require.NoError(t, err) 302 return h 303 }