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  }