github.com/argoproj/argo-cd/v2@v2.10.5/test/e2e/project_management_test.go (about)

     1  package e2e
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"k8s.io/apimachinery/pkg/api/errors"
    14  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    15  	"k8s.io/apimachinery/pkg/fields"
    16  	"k8s.io/utils/pointer"
    17  
    18  	"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
    19  	"github.com/argoproj/argo-cd/v2/test/e2e/fixture"
    20  	"github.com/argoproj/argo-cd/v2/util/argo"
    21  )
    22  
    23  func assertProjHasEvent(t *testing.T, a *v1alpha1.AppProject, message string, reason string) {
    24  	list, err := fixture.KubeClientset.CoreV1().Events(fixture.TestNamespace()).List(context.Background(), metav1.ListOptions{
    25  		FieldSelector: fields.SelectorFromSet(map[string]string{
    26  			"involvedObject.name":      a.Name,
    27  			"involvedObject.uid":       string(a.UID),
    28  			"involvedObject.namespace": fixture.TestNamespace(),
    29  		}).String(),
    30  	})
    31  	assert.NoError(t, err)
    32  
    33  	for i := range list.Items {
    34  		event := list.Items[i]
    35  		if event.Reason == reason && strings.Contains(event.Message, message) {
    36  			return
    37  		}
    38  	}
    39  	t.Errorf("Unable to find event with reason=%s; message=%s", reason, message)
    40  }
    41  
    42  func TestProjectCreation(t *testing.T) {
    43  	fixture.EnsureCleanState(t)
    44  
    45  	projectName := "proj-" + fixture.Name()
    46  	_, err := fixture.RunCli("proj", "create", projectName,
    47  		"--description", "Test description",
    48  		"-d", "https://192.168.99.100:8443,default",
    49  		"-d", "https://192.168.99.100:8443,service",
    50  		"-s", "https://github.com/argoproj/argo-cd.git",
    51  		"--orphaned-resources")
    52  	assert.Nil(t, err)
    53  
    54  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
    55  	assert.NoError(t, err)
    56  	assert.Equal(t, projectName, proj.Name)
    57  	assert.Equal(t, 2, len(proj.Spec.Destinations))
    58  
    59  	assert.Equal(t, "https://192.168.99.100:8443", proj.Spec.Destinations[0].Server)
    60  	assert.Equal(t, "default", proj.Spec.Destinations[0].Namespace)
    61  
    62  	assert.Equal(t, "https://192.168.99.100:8443", proj.Spec.Destinations[1].Server)
    63  	assert.Equal(t, "service", proj.Spec.Destinations[1].Namespace)
    64  
    65  	assert.Equal(t, 1, len(proj.Spec.SourceRepos))
    66  	assert.Equal(t, "https://github.com/argoproj/argo-cd.git", proj.Spec.SourceRepos[0])
    67  
    68  	assert.NotNil(t, proj.Spec.OrphanedResources)
    69  	assert.False(t, proj.Spec.OrphanedResources.IsWarn())
    70  
    71  	assertProjHasEvent(t, proj, "create", argo.EventReasonResourceCreated)
    72  
    73  	// create a manifest with the same name to upsert
    74  	newDescription := "Upserted description"
    75  	proj.Spec.Description = newDescription
    76  	proj.ResourceVersion = ""
    77  	data, err := json.Marshal(proj)
    78  	stdinString := string(data)
    79  	assert.NoError(t, err)
    80  
    81  	// fail without upsert flag
    82  	_, err = fixture.RunCliWithStdin(stdinString, "proj", "create",
    83  		"-f", "-")
    84  	assert.Error(t, err)
    85  
    86  	// succeed with the upsert flag
    87  	_, err = fixture.RunCliWithStdin(stdinString, "proj", "create",
    88  		"-f", "-", "--upsert")
    89  	assert.NoError(t, err)
    90  	proj, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
    91  	assert.NoError(t, err)
    92  	assert.Equal(t, newDescription, proj.Spec.Description)
    93  }
    94  
    95  func TestProjectDeletion(t *testing.T) {
    96  	fixture.EnsureCleanState(t)
    97  
    98  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
    99  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(
   100  		context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{})
   101  	assert.NoError(t, err)
   102  
   103  	_, err = fixture.RunCli("proj", "delete", projectName)
   104  	assert.NoError(t, err)
   105  
   106  	_, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   107  	assert.True(t, errors.IsNotFound(err))
   108  	assertProjHasEvent(t, proj, "delete", argo.EventReasonResourceDeleted)
   109  }
   110  
   111  func TestSetProject(t *testing.T) {
   112  	fixture.EnsureCleanState(t)
   113  
   114  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
   115  	_, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(
   116  		context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{})
   117  	assert.NoError(t, err)
   118  
   119  	_, err = fixture.RunCli("proj", "set", projectName,
   120  		"--description", "updated description",
   121  		"-d", "https://192.168.99.100:8443,default",
   122  		"-d", "https://192.168.99.100:8443,service",
   123  		"--orphaned-resources-warn=false")
   124  	assert.NoError(t, err)
   125  
   126  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   127  	assert.NoError(t, err)
   128  	assert.Equal(t, projectName, proj.Name)
   129  	assert.Equal(t, 2, len(proj.Spec.Destinations))
   130  
   131  	assert.Equal(t, "https://192.168.99.100:8443", proj.Spec.Destinations[0].Server)
   132  	assert.Equal(t, "default", proj.Spec.Destinations[0].Namespace)
   133  
   134  	assert.Equal(t, "https://192.168.99.100:8443", proj.Spec.Destinations[1].Server)
   135  	assert.Equal(t, "service", proj.Spec.Destinations[1].Namespace)
   136  
   137  	assert.NotNil(t, proj.Spec.OrphanedResources)
   138  	assert.False(t, proj.Spec.OrphanedResources.IsWarn())
   139  
   140  	assertProjHasEvent(t, proj, "update", argo.EventReasonResourceUpdated)
   141  }
   142  
   143  func TestAddProjectDestination(t *testing.T) {
   144  	fixture.EnsureCleanState(t)
   145  
   146  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
   147  	_, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(
   148  		context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{})
   149  	if err != nil {
   150  		t.Fatalf("Unable to create project %v", err)
   151  	}
   152  
   153  	_, err = fixture.RunCli("proj", "add-destination", projectName,
   154  		"https://192.168.99.100:8443",
   155  		"test1",
   156  	)
   157  
   158  	if err != nil {
   159  		t.Fatalf("Unable to add project destination %v", err)
   160  	}
   161  
   162  	_, err = fixture.RunCli("proj", "add-destination", projectName,
   163  		"https://192.168.99.100:8443",
   164  		"test1",
   165  	)
   166  	assert.Error(t, err)
   167  	assert.True(t, strings.Contains(err.Error(), "already defined"))
   168  
   169  	_, err = fixture.RunCli("proj", "add-destination", projectName,
   170  		"!*",
   171  		"test1",
   172  	)
   173  	assert.Error(t, err)
   174  	assert.True(t, strings.Contains(err.Error(), "server has an invalid format, '!*'"))
   175  
   176  	_, err = fixture.RunCli("proj", "add-destination", projectName,
   177  		"https://192.168.99.100:8443",
   178  		"!*",
   179  	)
   180  	assert.Error(t, err)
   181  	assert.True(t, strings.Contains(err.Error(), "namespace has an invalid format, '!*'"))
   182  
   183  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   184  	assert.NoError(t, err)
   185  	assert.Equal(t, projectName, proj.Name)
   186  	assert.Equal(t, 1, len(proj.Spec.Destinations))
   187  
   188  	assert.Equal(t, "https://192.168.99.100:8443", proj.Spec.Destinations[0].Server)
   189  	assert.Equal(t, "test1", proj.Spec.Destinations[0].Namespace)
   190  	assertProjHasEvent(t, proj, "update", argo.EventReasonResourceUpdated)
   191  }
   192  
   193  func TestAddProjectDestinationWithName(t *testing.T) {
   194  	fixture.EnsureCleanState(t)
   195  
   196  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
   197  	_, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(
   198  		context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{})
   199  	if err != nil {
   200  		t.Fatalf("Unable to create project %v", err)
   201  	}
   202  
   203  	_, err = fixture.RunCli("proj", "add-destination", projectName,
   204  		"in-cluster",
   205  		"test1",
   206  		"--name",
   207  	)
   208  
   209  	if err != nil {
   210  		t.Fatalf("Unable to add project destination %v", err)
   211  	}
   212  
   213  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   214  	assert.NoError(t, err)
   215  	assert.Equal(t, projectName, proj.Name)
   216  	assert.Equal(t, 1, len(proj.Spec.Destinations))
   217  
   218  	assert.Equal(t, "", proj.Spec.Destinations[0].Server)
   219  	assert.Equal(t, "in-cluster", proj.Spec.Destinations[0].Name)
   220  	assert.Equal(t, "test1", proj.Spec.Destinations[0].Namespace)
   221  	assertProjHasEvent(t, proj, "update", argo.EventReasonResourceUpdated)
   222  }
   223  
   224  func TestRemoveProjectDestination(t *testing.T) {
   225  	fixture.EnsureCleanState(t)
   226  
   227  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
   228  	_, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(context.Background(), &v1alpha1.AppProject{
   229  		ObjectMeta: metav1.ObjectMeta{Name: projectName},
   230  		Spec: v1alpha1.AppProjectSpec{
   231  			Destinations: []v1alpha1.ApplicationDestination{{
   232  				Server:    "https://192.168.99.100:8443",
   233  				Namespace: "test",
   234  			}},
   235  		},
   236  	}, metav1.CreateOptions{})
   237  
   238  	if err != nil {
   239  		t.Fatalf("Unable to create project %v", err)
   240  	}
   241  
   242  	_, err = fixture.RunCli("proj", "remove-destination", projectName,
   243  		"https://192.168.99.100:8443",
   244  		"test",
   245  	)
   246  
   247  	if err != nil {
   248  		t.Fatalf("Unable to remove project destination %v", err)
   249  	}
   250  
   251  	_, err = fixture.RunCli("proj", "remove-destination", projectName,
   252  		"https://192.168.99.100:8443",
   253  		"test1",
   254  	)
   255  	assert.Error(t, err)
   256  	assert.Contains(t, err.Error(), "does not exist")
   257  
   258  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   259  	if err != nil {
   260  		t.Fatalf("Unable to get project %v", err)
   261  	}
   262  	assert.Equal(t, projectName, proj.Name)
   263  	assert.Equal(t, 0, len(proj.Spec.Destinations))
   264  	assertProjHasEvent(t, proj, "update", argo.EventReasonResourceUpdated)
   265  }
   266  
   267  func TestAddProjectSource(t *testing.T) {
   268  	fixture.EnsureCleanState(t)
   269  
   270  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
   271  	_, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(
   272  		context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{})
   273  	if err != nil {
   274  		t.Fatalf("Unable to create project %v", err)
   275  	}
   276  
   277  	_, err = fixture.RunCli("proj", "add-source", projectName, "https://github.com/argoproj/argo-cd.git")
   278  
   279  	if err != nil {
   280  		t.Fatalf("Unable to add project source %v", err)
   281  	}
   282  
   283  	_, err = fixture.RunCli("proj", "add-source", projectName, "https://github.com/argoproj/argo-cd.git")
   284  	assert.Nil(t, err)
   285  
   286  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   287  	assert.NoError(t, err)
   288  	assert.Equal(t, projectName, proj.Name)
   289  	assert.Equal(t, 1, len(proj.Spec.SourceRepos))
   290  
   291  	assert.Equal(t, "https://github.com/argoproj/argo-cd.git", proj.Spec.SourceRepos[0])
   292  }
   293  
   294  func TestRemoveProjectSource(t *testing.T) {
   295  	fixture.EnsureCleanState(t)
   296  
   297  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
   298  	_, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(context.Background(), &v1alpha1.AppProject{
   299  		ObjectMeta: metav1.ObjectMeta{Name: projectName},
   300  		Spec: v1alpha1.AppProjectSpec{
   301  			SourceRepos: []string{"https://github.com/argoproj/argo-cd.git"},
   302  		},
   303  	}, metav1.CreateOptions{})
   304  
   305  	assert.NoError(t, err)
   306  
   307  	_, err = fixture.RunCli("proj", "remove-source", projectName, "https://github.com/argoproj/argo-cd.git")
   308  
   309  	assert.NoError(t, err)
   310  
   311  	_, err = fixture.RunCli("proj", "remove-source", projectName, "https://github.com/argoproj/argo-cd.git")
   312  	assert.NoError(t, err)
   313  
   314  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   315  	assert.NoError(t, err)
   316  	assert.Equal(t, projectName, proj.Name)
   317  	assert.Equal(t, 0, len(proj.Spec.SourceRepos))
   318  	assertProjHasEvent(t, proj, "update", argo.EventReasonResourceUpdated)
   319  }
   320  
   321  func TestUseJWTToken(t *testing.T) {
   322  	fixture.EnsureCleanState(t)
   323  
   324  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
   325  	appName := "app-" + strconv.FormatInt(time.Now().Unix(), 10)
   326  	roleName := "roleTest"
   327  	testApp := &v1alpha1.Application{
   328  		ObjectMeta: metav1.ObjectMeta{
   329  			Name: appName,
   330  		},
   331  		Spec: v1alpha1.ApplicationSpec{
   332  			Source: &v1alpha1.ApplicationSource{
   333  				RepoURL: fixture.RepoURL(fixture.RepoURLTypeFile),
   334  				Path:    "guestbook",
   335  			},
   336  			Destination: v1alpha1.ApplicationDestination{
   337  				Server:    v1alpha1.KubernetesInternalAPIServerAddr,
   338  				Namespace: fixture.TestNamespace(),
   339  			},
   340  			Project: projectName,
   341  		},
   342  	}
   343  	_, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(context.Background(), &v1alpha1.AppProject{
   344  		ObjectMeta: metav1.ObjectMeta{Name: projectName},
   345  		Spec: v1alpha1.AppProjectSpec{
   346  			Destinations: []v1alpha1.ApplicationDestination{{
   347  				Server:    v1alpha1.KubernetesInternalAPIServerAddr,
   348  				Namespace: fixture.TestNamespace(),
   349  			}},
   350  			SourceRepos: []string{"*"},
   351  		},
   352  	}, metav1.CreateOptions{})
   353  	assert.Nil(t, err)
   354  
   355  	_, err = fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.TestNamespace()).Create(context.Background(), testApp, metav1.CreateOptions{})
   356  	assert.NoError(t, err)
   357  
   358  	_, err = fixture.RunCli("proj", "role", "create", projectName, roleName)
   359  	assert.NoError(t, err)
   360  
   361  	roleGetResult, err := fixture.RunCli("proj", "role", "get", projectName, roleName)
   362  	assert.NoError(t, err)
   363  	assert.True(t, strings.HasSuffix(roleGetResult, "ID  ISSUED-AT  EXPIRES-AT"))
   364  
   365  	_, err = fixture.RunCli("proj", "role", "create-token", projectName, roleName)
   366  	assert.NoError(t, err)
   367  
   368  	for _, action := range []string{"get", "update", "sync", "create", "override", "*"} {
   369  		_, err = fixture.RunCli("proj", "role", "add-policy", projectName, roleName, "-a", action, "-o", "*", "-p", "allow")
   370  		assert.NoError(t, err)
   371  	}
   372  
   373  	newProj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   374  	assert.NoError(t, err)
   375  	assert.Len(t, newProj.Status.JWTTokensByRole[roleName].Items, 1)
   376  	assert.ElementsMatch(t, newProj.Status.JWTTokensByRole[roleName].Items, newProj.Spec.Roles[0].JWTTokens)
   377  
   378  	roleGetResult, err = fixture.RunCli("proj", "role", "get", projectName, roleName)
   379  	assert.NoError(t, err)
   380  	assert.True(t, strings.Contains(roleGetResult, strconv.FormatInt(newProj.Status.JWTTokensByRole[roleName].Items[0].IssuedAt, 10)))
   381  
   382  	_, err = fixture.RunCli("proj", "role", "delete-token", projectName, roleName, strconv.FormatInt(newProj.Status.JWTTokensByRole[roleName].Items[0].IssuedAt, 10))
   383  	assert.NoError(t, err)
   384  	newProj, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   385  	assert.NoError(t, err)
   386  	assert.Nil(t, newProj.Status.JWTTokensByRole[roleName].Items)
   387  	assert.Nil(t, newProj.Spec.Roles[0].JWTTokens)
   388  
   389  }
   390  
   391  func TestAddOrphanedIgnore(t *testing.T) {
   392  	fixture.EnsureCleanState(t)
   393  
   394  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
   395  	_, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(
   396  		context.Background(), &v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}, metav1.CreateOptions{})
   397  	if err != nil {
   398  		t.Fatalf("Unable to create project %v", err)
   399  	}
   400  
   401  	_, err = fixture.RunCli("proj", "add-orphaned-ignore", projectName,
   402  		"group",
   403  		"kind",
   404  		"--name",
   405  		"name",
   406  	)
   407  
   408  	if err != nil {
   409  		t.Fatalf("Unable to add resource to orphaned ignore %v", err)
   410  	}
   411  
   412  	_, err = fixture.RunCli("proj", "add-orphaned-ignore", projectName,
   413  		"group",
   414  		"kind",
   415  		"--name",
   416  		"name",
   417  	)
   418  	assert.Error(t, err)
   419  	assert.True(t, strings.Contains(err.Error(), "already defined"))
   420  
   421  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   422  	assert.NoError(t, err)
   423  	assert.Equal(t, projectName, proj.Name)
   424  	assert.Equal(t, 1, len(proj.Spec.OrphanedResources.Ignore))
   425  
   426  	assert.Equal(t, "group", proj.Spec.OrphanedResources.Ignore[0].Group)
   427  	assert.Equal(t, "kind", proj.Spec.OrphanedResources.Ignore[0].Kind)
   428  	assert.Equal(t, "name", proj.Spec.OrphanedResources.Ignore[0].Name)
   429  	assertProjHasEvent(t, proj, "update", argo.EventReasonResourceUpdated)
   430  }
   431  
   432  func TestRemoveOrphanedIgnore(t *testing.T) {
   433  	fixture.EnsureCleanState(t)
   434  
   435  	projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10)
   436  	_, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Create(context.Background(), &v1alpha1.AppProject{
   437  		ObjectMeta: metav1.ObjectMeta{Name: projectName},
   438  		Spec: v1alpha1.AppProjectSpec{
   439  			OrphanedResources: &v1alpha1.OrphanedResourcesMonitorSettings{
   440  				Warn:   pointer.Bool(true),
   441  				Ignore: []v1alpha1.OrphanedResourceKey{{Group: "group", Kind: "kind", Name: "name"}},
   442  			},
   443  		},
   444  	}, metav1.CreateOptions{})
   445  
   446  	if err != nil {
   447  		t.Fatalf("Unable to create project %v", err)
   448  	}
   449  
   450  	_, err = fixture.RunCli("proj", "remove-orphaned-ignore", projectName,
   451  		"group",
   452  		"kind",
   453  		"--name",
   454  		"name",
   455  	)
   456  
   457  	if err != nil {
   458  		t.Fatalf("Unable to remove resource from orphaned ignore list %v", err)
   459  	}
   460  
   461  	_, err = fixture.RunCli("proj", "remove-orphaned-ignore", projectName,
   462  		"group",
   463  		"kind",
   464  		"--name",
   465  		"name",
   466  	)
   467  	assert.Error(t, err)
   468  	assert.Contains(t, err.Error(), "does not exist")
   469  
   470  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   471  	if err != nil {
   472  		t.Fatalf("Unable to get project %v", err)
   473  	}
   474  	assert.Equal(t, projectName, proj.Name)
   475  	assert.Equal(t, 0, len(proj.Spec.OrphanedResources.Ignore))
   476  	assertProjHasEvent(t, proj, "update", argo.EventReasonResourceUpdated)
   477  }
   478  
   479  func createAndConfigGlobalProject() error {
   480  	// Create global project
   481  	projectGlobalName := "proj-g-" + fixture.Name()
   482  	_, err := fixture.RunCli("proj", "create", projectGlobalName,
   483  		"--description", "Test description",
   484  		"-d", "https://192.168.99.100:8443,default",
   485  		"-d", "https://192.168.99.100:8443,service",
   486  		"-s", "https://github.com/argoproj/argo-cd.git",
   487  		"--orphaned-resources")
   488  	if err != nil {
   489  		return err
   490  	}
   491  
   492  	projGlobal, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectGlobalName, metav1.GetOptions{})
   493  	if err != nil {
   494  		return err
   495  	}
   496  
   497  	projGlobal.Spec.NamespaceResourceBlacklist = []metav1.GroupKind{
   498  		{Group: "", Kind: "Service"},
   499  	}
   500  
   501  	projGlobal.Spec.NamespaceResourceWhitelist = []metav1.GroupKind{
   502  		{Group: "", Kind: "Deployment"},
   503  	}
   504  
   505  	projGlobal.Spec.ClusterResourceWhitelist = []metav1.GroupKind{
   506  		{Group: "", Kind: "Job"},
   507  	}
   508  
   509  	projGlobal.Spec.ClusterResourceBlacklist = []metav1.GroupKind{
   510  		{Group: "", Kind: "Pod"},
   511  	}
   512  
   513  	projGlobal.Spec.SyncWindows = v1alpha1.SyncWindows{}
   514  	win := &v1alpha1.SyncWindow{Kind: "deny", Schedule: "* * * * *", Duration: "1h", Applications: []string{"*"}}
   515  	projGlobal.Spec.SyncWindows = append(projGlobal.Spec.SyncWindows, win)
   516  
   517  	_, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Update(context.Background(), projGlobal, metav1.UpdateOptions{})
   518  	if err != nil {
   519  		return err
   520  	}
   521  
   522  	// Configure global project settings
   523  	globalProjectsSettings := `data:
   524    accounts.config-service: apiKey
   525    globalProjects: |
   526      - labelSelector:
   527          matchExpressions:
   528            - key: opt
   529              operator: In
   530              values:
   531                - me
   532                - you
   533        projectName: %s`
   534  
   535  	_, err = fixture.Run("", "kubectl", "patch", "cm", "argocd-cm",
   536  		"-n", fixture.TestNamespace(),
   537  		"-p", fmt.Sprintf(globalProjectsSettings, projGlobal.Name))
   538  	if err != nil {
   539  		return err
   540  	}
   541  
   542  	return nil
   543  }
   544  
   545  func TestGetVirtualProjectNoMatch(t *testing.T) {
   546  	fixture.EnsureCleanState(t)
   547  	err := createAndConfigGlobalProject()
   548  	assert.NoError(t, err)
   549  
   550  	// Create project which does not match global project settings
   551  	projectName := "proj-" + fixture.Name()
   552  	_, err = fixture.RunCli("proj", "create", projectName,
   553  		"--description", "Test description",
   554  		"-d", fmt.Sprintf("%s,*", v1alpha1.KubernetesInternalAPIServerAddr),
   555  		"-s", "*",
   556  		"--orphaned-resources")
   557  	assert.NoError(t, err)
   558  
   559  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   560  	assert.NoError(t, err)
   561  
   562  	// Create an app belongs to proj project
   563  	_, err = fixture.RunCli("app", "create", fixture.Name(), "--repo", fixture.RepoURL(fixture.RepoURLTypeFile),
   564  		"--path", guestbookPath, "--project", proj.Name, "--dest-server", v1alpha1.KubernetesInternalAPIServerAddr, "--dest-namespace", fixture.DeploymentNamespace())
   565  	assert.NoError(t, err)
   566  
   567  	// Waiting for the app to be successfully created.
   568  	// Else the sync would fail to retrieve the app resources.
   569  	time.Sleep(time.Second * 2)
   570  
   571  	// App trying to sync a resource which is not blacked listed anywhere
   572  	_, err = fixture.RunCli("app", "sync", fixture.Name(), "--resource", "apps:Deployment:guestbook-ui", "--timeout", fmt.Sprintf("%v", 10))
   573  	assert.NoError(t, err)
   574  
   575  	// app trying to sync a resource which is black listed by global project
   576  	_, err = fixture.RunCli("app", "sync", fixture.Name(), "--resource", ":Service:guestbook-ui", "--timeout", fmt.Sprintf("%v", 10))
   577  	assert.NoError(t, err)
   578  
   579  }
   580  
   581  func TestGetVirtualProjectMatch(t *testing.T) {
   582  	fixture.EnsureCleanState(t)
   583  	err := createAndConfigGlobalProject()
   584  	assert.NoError(t, err)
   585  
   586  	// Create project which matches global project settings
   587  	projectName := "proj-" + fixture.Name()
   588  	_, err = fixture.RunCli("proj", "create", projectName,
   589  		"--description", "Test description",
   590  		"-d", fmt.Sprintf("%s,*", v1alpha1.KubernetesInternalAPIServerAddr),
   591  		"-s", "*",
   592  		"--orphaned-resources")
   593  	assert.NoError(t, err)
   594  
   595  	proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Get(context.Background(), projectName, metav1.GetOptions{})
   596  	assert.NoError(t, err)
   597  
   598  	// Add a label to this project so that this project match global project selector
   599  	proj.Labels = map[string]string{"opt": "me"}
   600  	_, err = fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.TestNamespace()).Update(context.Background(), proj, metav1.UpdateOptions{})
   601  	assert.NoError(t, err)
   602  
   603  	// Create an app belongs to proj project
   604  	_, err = fixture.RunCli("app", "create", fixture.Name(), "--repo", fixture.RepoURL(fixture.RepoURLTypeFile),
   605  		"--path", guestbookPath, "--project", proj.Name, "--dest-server", v1alpha1.KubernetesInternalAPIServerAddr, "--dest-namespace", fixture.DeploymentNamespace())
   606  	assert.NoError(t, err)
   607  
   608  	// Waiting for the app to be successfully created.
   609  	// Else the sync would fail to retrieve the app resources.
   610  	time.Sleep(time.Second * 2)
   611  
   612  	// App trying to sync a resource which is not blacked listed anywhere
   613  	_, err = fixture.RunCli("app", "sync", fixture.Name(), "--resource", "apps:Deployment:guestbook-ui", "--timeout", fmt.Sprintf("%v", 10))
   614  	assert.Error(t, err)
   615  	assert.Contains(t, err.Error(), "blocked by sync window")
   616  
   617  	// app trying to sync a resource which is black listed by global project
   618  	_, err = fixture.RunCli("app", "sync", fixture.Name(), "--resource", ":Service:guestbook-ui", "--timeout", fmt.Sprintf("%v", 10))
   619  	assert.Contains(t, err.Error(), "blocked by sync window")
   620  
   621  }