github.com/argoproj/argo-cd/v3@v3.2.1/test/e2e/app_multiple_sources_test.go (about)

     1  package e2e
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  
    10  	. "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
    11  	. "github.com/argoproj/argo-cd/v3/test/e2e/fixture"
    12  	. "github.com/argoproj/argo-cd/v3/test/e2e/fixture/app"
    13  	. "github.com/argoproj/argo-cd/v3/util/argo"
    14  )
    15  
    16  func TestMultiSourceAppCreation(t *testing.T) {
    17  	sources := []ApplicationSource{{
    18  		RepoURL: RepoURL(RepoURLTypeFile),
    19  		Path:    guestbookPath,
    20  	}, {
    21  		RepoURL: RepoURL(RepoURLTypeFile),
    22  		Path:    "two-nice-pods",
    23  	}}
    24  	ctx := Given(t)
    25  	ctx.
    26  		Sources(sources).
    27  		When().
    28  		CreateMultiSourceAppFromFile().
    29  		Then().
    30  		And(func(app *Application) {
    31  			assert.Equal(t, Name(), app.Name)
    32  			for i, source := range app.Spec.GetSources() {
    33  				assert.Equal(t, sources[i].RepoURL, source.RepoURL)
    34  				assert.Equal(t, sources[i].Path, source.Path)
    35  			}
    36  			assert.Equal(t, DeploymentNamespace(), app.Spec.Destination.Namespace)
    37  			assert.Equal(t, KubernetesInternalAPIServerAddr, app.Spec.Destination.Server)
    38  		}).
    39  		Expect(Event(EventReasonResourceCreated, "create")).
    40  		And(func(_ *Application) {
    41  			// app should be listed
    42  			output, err := RunCli("app", "list")
    43  			require.NoError(t, err)
    44  			assert.Contains(t, output, Name())
    45  		}).
    46  		Expect(Success("")).
    47  		Given().Timeout(60).
    48  		When().Wait().Then().
    49  		Expect(Success("")).
    50  		And(func(app *Application) {
    51  			statusByName := map[string]SyncStatusCode{}
    52  			for _, r := range app.Status.Resources {
    53  				statusByName[r.Name] = r.Status
    54  			}
    55  			// check if the app has 3 resources, guestbook and 2 pods
    56  			assert.Len(t, statusByName, 3)
    57  			assert.Equal(t, SyncStatusCodeSynced, statusByName["pod-1"])
    58  			assert.Equal(t, SyncStatusCodeSynced, statusByName["pod-2"])
    59  			assert.Equal(t, SyncStatusCodeSynced, statusByName["guestbook-ui"])
    60  		})
    61  }
    62  
    63  func TestMultiSourceAppWithHelmExternalValueFiles(t *testing.T) {
    64  	sources := []ApplicationSource{{
    65  		RepoURL: RepoURL(RepoURLTypeFile),
    66  		Ref:     "values",
    67  	}, {
    68  		RepoURL:        RepoURL(RepoURLTypeFile),
    69  		TargetRevision: "HEAD",
    70  		Path:           "helm-guestbook",
    71  		Helm: &ApplicationSourceHelm{
    72  			ReleaseName: "helm-guestbook",
    73  			ValueFiles: []string{
    74  				"$values/multiple-source-values/values.yaml",
    75  			},
    76  		},
    77  	}}
    78  	fmt.Printf("sources: %v\n", sources)
    79  	ctx := Given(t)
    80  	ctx.
    81  		Sources(sources).
    82  		When().
    83  		CreateMultiSourceAppFromFile().
    84  		Then().
    85  		And(func(app *Application) {
    86  			assert.Equal(t, Name(), app.Name)
    87  			for i, source := range app.Spec.GetSources() {
    88  				assert.Equal(t, sources[i].RepoURL, source.RepoURL)
    89  				assert.Equal(t, sources[i].Path, source.Path)
    90  			}
    91  			assert.Equal(t, DeploymentNamespace(), app.Spec.Destination.Namespace)
    92  			assert.Equal(t, KubernetesInternalAPIServerAddr, app.Spec.Destination.Server)
    93  		}).
    94  		Expect(Event(EventReasonResourceCreated, "create")).
    95  		And(func(_ *Application) {
    96  			// app should be listed
    97  			output, err := RunCli("app", "list")
    98  			require.NoError(t, err)
    99  			assert.Contains(t, output, Name())
   100  		}).
   101  		Expect(Success("")).
   102  		Given().Timeout(60).
   103  		When().Wait().Then().
   104  		Expect(Success("")).
   105  		And(func(app *Application) {
   106  			statusByName := map[string]SyncStatusCode{}
   107  			for _, r := range app.Status.Resources {
   108  				statusByName[r.Name] = r.Status
   109  			}
   110  			assert.Len(t, statusByName, 1)
   111  			assert.Equal(t, SyncStatusCodeSynced, statusByName["guestbook-ui"])
   112  
   113  			// Confirm that the deployment has 3 replicas.
   114  			output, err := Run("", "kubectl", "get", "deployment", "guestbook-ui", "-n", DeploymentNamespace(), "-o", "jsonpath={.spec.replicas}")
   115  			require.NoError(t, err)
   116  			assert.Equal(t, "3", output, "Expected 3 replicas for the helm-guestbook deployment")
   117  		})
   118  }
   119  
   120  func TestMultiSourceAppWithSourceOverride(t *testing.T) {
   121  	sources := []ApplicationSource{{
   122  		RepoURL: RepoURL(RepoURLTypeFile),
   123  		Path:    guestbookPath,
   124  	}, {
   125  		RepoURL: RepoURL(RepoURLTypeFile),
   126  		Path:    "two-nice-pods",
   127  	}, {
   128  		RepoURL: RepoURL(RepoURLTypeFile),
   129  		Path:    "multiple-source-values",
   130  	}}
   131  	ctx := Given(t)
   132  	ctx.
   133  		Sources(sources).
   134  		When().
   135  		CreateMultiSourceAppFromFile().
   136  		Then().
   137  		And(func(app *Application) {
   138  			assert.Equal(t, Name(), app.Name)
   139  			for i, source := range app.Spec.GetSources() {
   140  				assert.Equal(t, sources[i].RepoURL, source.RepoURL)
   141  				assert.Equal(t, sources[i].Path, source.Path)
   142  			}
   143  			assert.Equal(t, DeploymentNamespace(), app.Spec.Destination.Namespace)
   144  			assert.Equal(t, KubernetesInternalAPIServerAddr, app.Spec.Destination.Server)
   145  		}).
   146  		Expect(Event(EventReasonResourceCreated, "create")).
   147  		And(func(_ *Application) {
   148  			// app should be listed
   149  			output, err := RunCli("app", "list")
   150  			require.NoError(t, err)
   151  			assert.Contains(t, output, Name())
   152  		}).
   153  		Expect(Success("")).
   154  		Given().Timeout(60).
   155  		When().Wait().Then().
   156  		Expect(Success("")).
   157  		And(func(app *Application) {
   158  			statusByName := map[string]SyncStatusCode{}
   159  			for _, r := range app.Status.Resources {
   160  				statusByName[r.Name] = r.Status
   161  			}
   162  			// check if the app has 3 resources, guestbook and 2 pods
   163  			assert.Len(t, statusByName, 3)
   164  			assert.Equal(t, SyncStatusCodeSynced, statusByName["pod-1"])
   165  			assert.Equal(t, SyncStatusCodeSynced, statusByName["pod-2"])
   166  			assert.Equal(t, SyncStatusCodeSynced, statusByName["guestbook-ui"])
   167  
   168  			// check if label was added to the pod to make sure resource was taken from the later source
   169  			output, err := Run("", "kubectl", "describe", "pods", "pod-1", "-n", DeploymentNamespace())
   170  			require.NoError(t, err)
   171  			assert.Contains(t, output, "foo=bar")
   172  		})
   173  }
   174  
   175  func TestMultiSourceAppWithSourceName(t *testing.T) {
   176  	sources := []ApplicationSource{{
   177  		RepoURL: RepoURL(RepoURLTypeFile),
   178  		Path:    guestbookPath,
   179  		Name:    "guestbook",
   180  	}, {
   181  		RepoURL: RepoURL(RepoURLTypeFile),
   182  		Path:    "two-nice-pods",
   183  		Name:    "dynamic duo",
   184  	}}
   185  	ctx := Given(t)
   186  	ctx.
   187  		Sources(sources).
   188  		When().
   189  		CreateMultiSourceAppFromFile().
   190  		Then().
   191  		And(func(app *Application) {
   192  			assert.Equal(t, Name(), app.Name)
   193  			for i, source := range app.Spec.GetSources() {
   194  				assert.Equal(t, sources[i].RepoURL, source.RepoURL)
   195  				assert.Equal(t, sources[i].Path, source.Path)
   196  				assert.Equal(t, sources[i].Name, source.Name)
   197  			}
   198  			assert.Equal(t, DeploymentNamespace(), app.Spec.Destination.Namespace)
   199  			assert.Equal(t, KubernetesInternalAPIServerAddr, app.Spec.Destination.Server)
   200  		}).
   201  		Expect(Event(EventReasonResourceCreated, "create")).
   202  		And(func(_ *Application) {
   203  			// we remove the first source
   204  			output, err := RunCli("app", "remove-source", Name(), "--source-name", sources[0].Name)
   205  			require.NoError(t, err)
   206  			assert.Contains(t, output, "updated successfully")
   207  		}).
   208  		Expect(Success("")).
   209  		And(func(app *Application) {
   210  			assert.Len(t, app.Spec.GetSources(), 1)
   211  			// we add a source
   212  			output, err := RunCli("app", "add-source", Name(), "--source-name", sources[0].Name, "--repo", RepoURL(RepoURLTypeFile), "--path", guestbookPath)
   213  			require.NoError(t, err)
   214  			assert.Contains(t, output, "updated successfully")
   215  		}).
   216  		Expect(Success("")).
   217  		Given().Timeout(60).
   218  		When().Wait().Then().
   219  		Expect(Success("")).
   220  		And(func(app *Application) {
   221  			assert.Len(t, app.Spec.GetSources(), 2)
   222  			// sources order has been inverted
   223  			assert.Equal(t, sources[1].Name, app.Spec.GetSources()[0].Name)
   224  			assert.Equal(t, sources[0].Name, app.Spec.GetSources()[1].Name)
   225  			statusByName := map[string]SyncStatusCode{}
   226  			for _, r := range app.Status.Resources {
   227  				statusByName[r.Name] = r.Status
   228  			}
   229  			// check if the app has 3 resources, guestbook and 2 pods
   230  			assert.Len(t, statusByName, 3)
   231  			assert.Equal(t, SyncStatusCodeSynced, statusByName["pod-1"])
   232  			assert.Equal(t, SyncStatusCodeSynced, statusByName["pod-2"])
   233  			assert.Equal(t, SyncStatusCodeSynced, statusByName["guestbook-ui"])
   234  		})
   235  }
   236  
   237  func TestMultiSourceAppSetWithSourceName(t *testing.T) {
   238  	sources := []ApplicationSource{{
   239  		RepoURL: RepoURL(RepoURLTypeFile),
   240  		Path:    guestbookPath,
   241  		Name:    "guestbook",
   242  	}, {
   243  		RepoURL: RepoURL(RepoURLTypeFile),
   244  		Path:    "two-nice-pods",
   245  		Name:    "dynamic duo",
   246  	}}
   247  	ctx := Given(t)
   248  	ctx.
   249  		Sources(sources).
   250  		When().
   251  		CreateMultiSourceAppFromFile().
   252  		Then().
   253  		And(func(app *Application) {
   254  			assert.Equal(t, Name(), app.Name)
   255  			for i, source := range app.Spec.GetSources() {
   256  				assert.Equal(t, sources[i].RepoURL, source.RepoURL)
   257  				assert.Equal(t, sources[i].Path, source.Path)
   258  				assert.Equal(t, sources[i].Name, source.Name)
   259  			}
   260  			assert.Equal(t, DeploymentNamespace(), app.Spec.Destination.Namespace)
   261  			assert.Equal(t, KubernetesInternalAPIServerAddr, app.Spec.Destination.Server)
   262  		}).
   263  		Expect(Event(EventReasonResourceCreated, "create")).
   264  		And(func(_ *Application) {
   265  			_, err := RunCli("app", "set", Name(), "--source-name", sources[1].Name, "--path", "deployment")
   266  			require.NoError(t, err)
   267  		}).
   268  		Expect(Success("")).
   269  		And(func(app *Application) {
   270  			assert.Equal(t, "deployment", app.Spec.GetSources()[1].Path)
   271  		})
   272  }
   273  
   274  func TestMultiSourceApptErrorWhenSourceNameAndSourcePosition(t *testing.T) {
   275  	sources := []ApplicationSource{{
   276  		RepoURL: RepoURL(RepoURLTypeFile),
   277  		Path:    guestbookPath,
   278  		Name:    "guestbook",
   279  	}, {
   280  		RepoURL: RepoURL(RepoURLTypeFile),
   281  		Path:    "two-nice-pods",
   282  		Name:    "dynamic duo",
   283  	}}
   284  	ctx := Given(t)
   285  	ctx.
   286  		Sources(sources).
   287  		When().
   288  		CreateMultiSourceAppFromFile().
   289  		Then().
   290  		Expect(Event(EventReasonResourceCreated, "create")).
   291  		And(func(_ *Application) {
   292  			_, err := RunCli("app", "get", Name(), "--source-name", sources[1].Name, "--source-position", "1")
   293  			assert.ErrorContains(t, err, "Only one of source-position and source-name can be specified.")
   294  		}).
   295  		And(func(_ *Application) {
   296  			_, err := RunCli("app", "manifests", Name(), "--revisions", "0.0.2", "--source-names", sources[0].Name, "--revisions", "0.0.2", "--source-positions", "1")
   297  			assert.ErrorContains(t, err, "Only one of source-positions and source-names can be specified.")
   298  		})
   299  }