github.com/argoproj/argo-cd/v3@v3.2.1/commitserver/commit/hydratorhelper_test.go (about) 1 package commit 2 3 import ( 4 "crypto/rand" 5 "crypto/sha256" 6 "encoding/hex" 7 "encoding/json" 8 "fmt" 9 "os" 10 "path" 11 "path/filepath" 12 "testing" 13 "time" 14 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 19 "github.com/argoproj/argo-cd/v3/commitserver/apiclient" 20 appsv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" 21 "github.com/argoproj/argo-cd/v3/util/hydrator" 22 ) 23 24 // tempRoot creates a temporary directory and returns an os.Root object for it. 25 // We use this instead of t.TempDir() because OSX does weird things with temp directories, and it triggers 26 // the os.Root protections. 27 func tempRoot(t *testing.T) *os.Root { 28 t.Helper() 29 30 dir, err := os.MkdirTemp(".", "") 31 require.NoError(t, err) 32 t.Cleanup(func() { 33 err := os.RemoveAll(dir) 34 require.NoError(t, err) 35 }) 36 root, err := os.OpenRoot(dir) 37 require.NoError(t, err) 38 t.Cleanup(func() { 39 err := root.Close() 40 require.NoError(t, err) 41 }) 42 return root 43 } 44 45 func TestWriteForPaths(t *testing.T) { 46 root := tempRoot(t) 47 48 repoURL := "https://github.com/example/repo" 49 drySha := "abc123" 50 paths := []*apiclient.PathDetails{ 51 { 52 Path: "path1", 53 Manifests: []*apiclient.HydratedManifestDetails{ 54 {ManifestJSON: `{"kind":"Pod","apiVersion":"v1"}`}, 55 }, 56 Commands: []string{"command1", "command2"}, 57 }, 58 { 59 Path: "path2", 60 Manifests: []*apiclient.HydratedManifestDetails{ 61 {ManifestJSON: `{"kind":"Service","apiVersion":"v1"}`}, 62 }, 63 Commands: []string{"command3"}, 64 }, 65 { 66 Path: "path3/nested", 67 Manifests: []*apiclient.HydratedManifestDetails{ 68 {ManifestJSON: `{"kind":"Deployment","apiVersion":"apps/v1"}`}, 69 }, 70 Commands: []string{"command4"}, 71 }, 72 } 73 74 now := metav1.NewTime(time.Now()) 75 metadata := &appsv1.RevisionMetadata{ 76 Author: "test-author", 77 Date: &now, 78 Message: `test-message 79 80 Signed-off-by: Test User <test@example.com> 81 Argocd-reference-commit-sha: abc123 82 `, 83 References: []appsv1.RevisionReference{ 84 { 85 Commit: &appsv1.CommitMetadata{ 86 Author: "test-code-author <test-email-author@example.com>", 87 Date: now.Format(time.RFC3339), 88 Subject: "test-code-subject", 89 SHA: "test-code-sha", 90 RepoURL: "https://example.com/test/repo.git", 91 }, 92 }, 93 }, 94 } 95 96 err := WriteForPaths(root, repoURL, drySha, metadata, paths) 97 require.NoError(t, err) 98 99 // Check if the top-level hydrator.metadata exists and contains the repo URL and dry SHA 100 topMetadataPath := filepath.Join(root.Name(), "hydrator.metadata") 101 topMetadataBytes, err := os.ReadFile(topMetadataPath) 102 require.NoError(t, err) 103 104 var topMetadata hydratorMetadataFile 105 err = json.Unmarshal(topMetadataBytes, &topMetadata) 106 require.NoError(t, err) 107 assert.Equal(t, repoURL, topMetadata.RepoURL) 108 assert.Equal(t, drySha, topMetadata.DrySHA) 109 assert.Equal(t, metadata.Author, topMetadata.Author) 110 assert.Equal(t, "test-message", topMetadata.Subject) 111 // The body should exclude the Argocd- trailers. 112 assert.Equal(t, "Signed-off-by: Test User <test@example.com>\n", topMetadata.Body) 113 assert.Equal(t, metadata.Date.Format(time.RFC3339), topMetadata.Date) 114 assert.Equal(t, metadata.References, topMetadata.References) 115 116 for _, p := range paths { 117 fullHydratePath := filepath.Join(root.Name(), p.Path) 118 119 // Check if each path directory exists 120 assert.DirExists(t, fullHydratePath) 121 122 // Check if each path contains a hydrator.metadata file and contains the repo URL 123 metadataPath := path.Join(fullHydratePath, "hydrator.metadata") 124 metadataBytes, err := os.ReadFile(metadataPath) 125 require.NoError(t, err) 126 127 var readMetadata hydratorMetadataFile 128 err = json.Unmarshal(metadataBytes, &readMetadata) 129 require.NoError(t, err) 130 assert.Equal(t, repoURL, readMetadata.RepoURL) 131 // Check if each path contains a README.md file and contains the repo URL 132 readmePath := path.Join(fullHydratePath, "README.md") 133 readmeBytes, err := os.ReadFile(readmePath) 134 require.NoError(t, err) 135 assert.Contains(t, string(readmeBytes), repoURL) 136 137 // Check if each path contains a manifest.yaml file and contains the word kind 138 manifestPath := path.Join(fullHydratePath, "manifest.yaml") 139 manifestBytes, err := os.ReadFile(manifestPath) 140 require.NoError(t, err) 141 assert.Contains(t, string(manifestBytes), "kind") 142 } 143 } 144 145 func TestWriteMetadata(t *testing.T) { 146 root := tempRoot(t) 147 148 metadata := hydrator.HydratorCommitMetadata{ 149 RepoURL: "https://github.com/example/repo", 150 DrySHA: "abc123", 151 } 152 153 err := writeMetadata(root, "", metadata) 154 require.NoError(t, err) 155 156 metadataPath := filepath.Join(root.Name(), "hydrator.metadata") 157 metadataBytes, err := os.ReadFile(metadataPath) 158 require.NoError(t, err) 159 160 var readMetadata hydrator.HydratorCommitMetadata 161 err = json.Unmarshal(metadataBytes, &readMetadata) 162 require.NoError(t, err) 163 assert.Equal(t, metadata, readMetadata) 164 } 165 166 func TestWriteReadme(t *testing.T) { 167 root := tempRoot(t) 168 169 randomData := make([]byte, 32) 170 _, err := rand.Read(randomData) 171 require.NoError(t, err) 172 hash := sha256.Sum256(randomData) 173 sha := hex.EncodeToString(hash[:]) 174 175 metadata := hydrator.HydratorCommitMetadata{ 176 RepoURL: "https://github.com/example/repo", 177 DrySHA: "abc123", 178 References: []appsv1.RevisionReference{ 179 { 180 Commit: &appsv1.CommitMetadata{ 181 Author: "test-code-author <test@example.com>", 182 Date: time.Now().Format(time.RFC3339), 183 Subject: "test-code-subject", 184 SHA: sha, 185 RepoURL: "https://example.com/test/repo.git", 186 }, 187 }, 188 }, 189 } 190 191 err = writeReadme(root, "", metadata) 192 require.NoError(t, err) 193 194 readmePath := filepath.Join(root.Name(), "README.md") 195 readmeBytes, err := os.ReadFile(readmePath) 196 require.NoError(t, err) 197 assert.Equal(t, `# Manifest Hydration 198 199 To hydrate the manifests in this repository, run the following commands: 200 201 `+"```shell"+` 202 git clone https://github.com/example/repo 203 # cd into the cloned directory 204 git checkout abc123 205 `+"```"+fmt.Sprintf(` 206 ## References 207 208 * [%s](https://example.com/test/repo.git): test-code-subject (test-code-author <test@example.com>) 209 `, sha[:7]), string(readmeBytes)) 210 } 211 212 func TestWriteManifests(t *testing.T) { 213 root := tempRoot(t) 214 215 manifests := []*apiclient.HydratedManifestDetails{ 216 {ManifestJSON: `{"kind":"Pod","apiVersion":"v1"}`}, 217 } 218 219 err := writeManifests(root, "", manifests) 220 require.NoError(t, err) 221 222 manifestPath := path.Join(root.Name(), "manifest.yaml") 223 manifestBytes, err := os.ReadFile(manifestPath) 224 require.NoError(t, err) 225 assert.Contains(t, string(manifestBytes), "kind") 226 } 227 228 func TestWriteGitAttributes(t *testing.T) { 229 root := tempRoot(t) 230 231 err := writeGitAttributes(root) 232 require.NoError(t, err) 233 234 gitAttributesPath := filepath.Join(root.Name(), ".gitattributes") 235 gitAttributesBytes, err := os.ReadFile(gitAttributesPath) 236 require.NoError(t, err) 237 assert.Contains(t, string(gitAttributesBytes), "*/README.md linguist-generated=true") 238 assert.Contains(t, string(gitAttributesBytes), "*/hydrator.metadata linguist-generated=true") 239 }