github.com/quickfeed/quickfeed@v0.0.0-20240507093252-ed8ca812a09c/scm/fetcher_test.go (about) 1 package scm_test 2 3 import ( 4 "context" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 "time" 11 12 "github.com/quickfeed/quickfeed/kit/sh" 13 "github.com/quickfeed/quickfeed/qf" 14 "github.com/quickfeed/quickfeed/scm" 15 ) 16 17 func TestClone(t *testing.T) { 18 qfTestOrg := scm.GetTestOrganization(t) 19 s, userName := scm.GetTestSCM(t) 20 21 ctx := context.Background() 22 dstDir := t.TempDir() 23 assignmentDir, err := s.Clone(ctx, &scm.CloneOptions{ 24 Organization: qfTestOrg, 25 Repository: qf.StudentRepoName(userName), 26 DestDir: dstDir, 27 }) 28 if err != nil { 29 t.Fatal(err) 30 } 31 testsDir, err := s.Clone(ctx, &scm.CloneOptions{ 32 Organization: qfTestOrg, 33 Repository: qf.TestsRepo, 34 DestDir: dstDir, 35 }) 36 if err != nil { 37 t.Fatal(err) 38 } 39 // Note: the following depends on the actual content of 40 // the <student>-labs and tests repositories of the qfTestOrg. 41 found, err := exists(filepath.Join(assignmentDir, "lab1")) 42 if !found { 43 t.Fatalf("lab1 not found in 'assignments': %v", err) 44 } 45 found, err = exists(filepath.Join(assignmentDir, "lab2")) 46 if found { 47 t.Fatalf("lab2 found in 'assignments' unexpectedly: %v", err) 48 } 49 expectedTestsDirs := []string{ 50 "lab1", 51 "lab2", 52 "lab3", 53 "lab4", 54 "lab5", 55 "lab6", 56 "scripts", 57 } 58 for _, dir := range expectedTestsDirs { 59 found, err = exists(filepath.Join(testsDir, dir)) 60 if !found { 61 t.Errorf("%s not found in 'tests': %v", dir, err) 62 } 63 } 64 } 65 66 func appendToFile(filename, text string) (err error) { 67 f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600) 68 if err != nil { 69 return err 70 } 71 defer func() { 72 closeErr := f.Close() 73 if err == nil { 74 err = closeErr 75 } 76 }() 77 _, err = f.WriteString(text) 78 return 79 } 80 81 // Test that we can clone a repository, update it (commit and push) and clone it again twice. 82 // The two last clones are in a different directory. 83 // The third clone is actually a fast-forward pull. 84 func TestCloneTwice(t *testing.T) { 85 qfTestOrg := scm.GetTestOrganization(t) 86 s, _ := scm.GetTestSCM(t) 87 88 ctx := context.Background() 89 dstDir := t.TempDir() 90 91 testsDir, err := s.Clone(ctx, &scm.CloneOptions{ 92 Organization: qfTestOrg, 93 Repository: qf.TestsRepo, 94 DestDir: dstDir, 95 }) 96 if err != nil { 97 t.Fatal(err) 98 } 99 if found, err := exists(testsDir); !found { 100 t.Fatalf("%s not found: %v", testsDir, err) 101 } 102 twiceMsg := fmt.Sprintf("Update tests repo %s\n", time.Now().Format(time.Kitchen)) 103 if err := appendToFile(filepath.Join(testsDir, "README.md"), twiceMsg); err != nil { 104 t.Fatal(err) 105 } 106 commitMsg := fmt.Sprintf("Clone twice commit %s", time.Now().Format(time.Kitchen)) 107 if err := sh.RunA("git", "-C", testsDir, "commit", "-a", "-m", commitMsg); err != nil { 108 t.Fatal(err) 109 } 110 if err := sh.RunA("git", "-C", testsDir, "push"); err != nil { 111 t.Fatal(err) 112 } 113 114 // Clone to a new directory to ensure that we get a new clone with the change we just made. 115 dstDir = t.TempDir() 116 117 testsDir, err = s.Clone(ctx, &scm.CloneOptions{ 118 Organization: qfTestOrg, 119 Repository: qf.TestsRepo, 120 DestDir: dstDir, 121 }) 122 if err != nil { 123 t.Fatal(err) 124 } 125 b, err := os.ReadFile(filepath.Join(testsDir, "README.md")) 126 if err != nil { 127 t.Fatal(err) 128 } 129 if !strings.Contains(string(b), twiceMsg[:len(twiceMsg)-2]) { 130 t.Fatalf("README.md does not contain %q", twiceMsg) 131 } 132 133 // Clone to the same directory to test that we get a fast-forward pull. 134 testsDir, err = s.Clone(ctx, &scm.CloneOptions{ 135 Organization: qfTestOrg, 136 Repository: qf.TestsRepo, 137 DestDir: dstDir, 138 }) 139 if err != nil { 140 t.Fatal(err) 141 } 142 b, err = os.ReadFile(filepath.Join(testsDir, "README.md")) 143 if err != nil { 144 t.Fatal(err) 145 } 146 if !strings.Contains(string(b), twiceMsg[:len(twiceMsg)-2]) { 147 t.Fatalf("README.md does not contain %q", twiceMsg) 148 } 149 } 150 151 func TestCloneBranch(t *testing.T) { 152 qfTestOrg := scm.GetTestOrganization(t) 153 s, userName := scm.GetTestSCM(t) 154 155 ctx := context.Background() 156 dstDir := t.TempDir() 157 assignmentDir, err := s.Clone(ctx, &scm.CloneOptions{ 158 Organization: qfTestOrg, 159 Repository: qf.StudentRepoName(userName), 160 DestDir: dstDir, 161 Branch: "hotfix", 162 }) 163 if err != nil { 164 t.Fatal(err) 165 } 166 // Note: the following depends on the actual existence of the lab2 167 // folder in the <student>-labs repository of the qfTestOrg. 168 found, err := exists(filepath.Join(assignmentDir, "lab2")) 169 if !found { 170 t.Fatalf("lab2 not found in %s: %v", assignmentDir, err) 171 } 172 } 173 174 // exists returns whether the given file or directory exists 175 func exists(path string) (bool, error) { 176 _, err := os.Stat(path) 177 if err == nil { 178 return true, nil 179 } 180 if os.IsNotExist(err) { 181 return false, nil 182 } 183 return false, err 184 }