Skip to content

Commit 3541d64

Browse files
authored
test(e2e): add e2e test for interaction with ArgoCD API (#549)
Signed-off-by: yeonsoo <[email protected]>
1 parent bc7c4e5 commit 3541d64

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed

test/e2e/application_test.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package e2e
2+
3+
import (
4+
"testing"
5+
6+
"github.com/argoproj-labs/argocd-agent/test/e2e/fixture"
7+
"github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
8+
"github.com/stretchr/testify/assert"
9+
"github.com/stretchr/testify/suite"
10+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
)
12+
13+
// ApplicationTestSuite is a test suite for application management via the Argo CD API.
14+
type ApplicationTestSuite struct {
15+
fixture.BaseSuite
16+
argoClient *fixture.ArgoRestClient
17+
}
18+
19+
// SetupSuite runs before the tests in the suite are run.
20+
func (s *ApplicationTestSuite) SetupSuite() {
21+
// First, run the base suite setup
22+
s.BaseSuite.SetupSuite()
23+
24+
// Now, set up the Argo CD REST client
25+
requires := s.Require()
26+
endpoint, err := fixture.GetArgoCDServerEndpoint(s.PrincipalClient)
27+
requires.NoError(err)
28+
29+
password, err := fixture.GetInitialAdminSecret(s.PrincipalClient)
30+
requires.NoError(err)
31+
32+
s.argoClient = fixture.NewArgoClient(endpoint, "admin", password)
33+
err = s.argoClient.Login()
34+
requires.NoError(err)
35+
}
36+
37+
// TestApplicationManagementAPI is the core test function for this suite.
38+
func (s *ApplicationTestSuite) Test_ApplicationManagementAPI() {
39+
requires := s.Require()
40+
asserts := assert.New(s.T())
41+
42+
// Define a new application
43+
appName := "guestbook-api-test"
44+
app := &v1alpha1.Application{
45+
ObjectMeta: metav1.ObjectMeta{
46+
Name: appName,
47+
Namespace: "argocd", // Argo CD API creates applications in the argocd namespace
48+
},
49+
Spec: v1alpha1.ApplicationSpec{
50+
Project: "default",
51+
Source: &v1alpha1.ApplicationSource{
52+
RepoURL: "https://github.com/argoproj/argocd-example-apps.git",
53+
Path: "guestbook",
54+
TargetRevision: "HEAD",
55+
},
56+
Destination: v1alpha1.ApplicationDestination{
57+
Server: "https://kubernetes.default.svc",
58+
Namespace: "default",
59+
},
60+
},
61+
}
62+
63+
// 1. Create Application
64+
createdApp, err := s.argoClient.CreateApplication(app)
65+
requires.NoError(err)
66+
asserts.Equal(appName, createdApp.Name)
67+
68+
// 2. Get Application and verify
69+
gotApp, err := s.argoClient.GetApplication(appName)
70+
requires.NoError(err)
71+
asserts.Equal(appName, gotApp.Name)
72+
asserts.Equal("default", gotApp.Spec.Project)
73+
74+
// 3. List Applications and verify
75+
appList, err := s.argoClient.ListApplications()
76+
requires.NoError(err)
77+
78+
found := false
79+
for _, item := range appList.Items {
80+
if item.Name == appName {
81+
found = true
82+
break
83+
}
84+
}
85+
asserts.True(found, "application %s not found in list", appName)
86+
87+
// 4. Delete Application
88+
err = s.argoClient.DeleteApplication(appName)
89+
requires.NoError(err)
90+
91+
}
92+
93+
// TestApplicationSuite runs the entire test suite.
94+
func TestApplicationSuite(t *testing.T) {
95+
suite.Run(t, new(ApplicationTestSuite))
96+
}

test/e2e/fixture/argoclient.go

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,3 +331,124 @@ func GetArgoCDServerEndpoint(k8sClient KubeClient) (string, error) {
331331

332332
return argoEndpoint, nil
333333
}
334+
335+
// CreateApplication creates a new application in ArgoCD
336+
func (c *ArgoRestClient) CreateApplication(app *v1alpha1.Application) (*v1alpha1.Application, error) {
337+
reqURL := c.url()
338+
reqURL.Path = "/api/v1/applications"
339+
appBytes, err := json.Marshal(app)
340+
if err != nil {
341+
return nil, fmt.Errorf("failed to marshal application: %w", err)
342+
}
343+
344+
req, err := http.NewRequest(http.MethodPost, reqURL.String(), bytes.NewBuffer(appBytes))
345+
if err != nil {
346+
return nil, fmt.Errorf("failed to create request: %w", err)
347+
}
348+
req.Header.Set("Content-Type", "application/json")
349+
350+
resp, err := c.Do(req)
351+
if err != nil {
352+
return nil, fmt.Errorf("failed to create application: %w", err)
353+
}
354+
defer resp.Body.Close()
355+
356+
if resp.StatusCode != http.StatusOK {
357+
body, _ := io.ReadAll(resp.Body)
358+
return nil, fmt.Errorf("failed to create application: status %d, body: %s", resp.StatusCode, string(body))
359+
}
360+
361+
var createdApp v1alpha1.Application
362+
if err := json.NewDecoder(resp.Body).Decode(&createdApp); err != nil {
363+
return nil, fmt.Errorf("failed to unmarshal created application: %w", err)
364+
}
365+
366+
return &createdApp, nil
367+
}
368+
369+
// GetApplication retrieves an application by its name
370+
func (c *ArgoRestClient) GetApplication(name string) (*v1alpha1.Application, error) {
371+
reqURL := c.url()
372+
reqURL.Path = fmt.Sprintf("/api/v1/applications/%s", name)
373+
374+
req, err := http.NewRequest(http.MethodGet, reqURL.String(), nil)
375+
if err != nil {
376+
return nil, fmt.Errorf("failed to create request: %w", err)
377+
}
378+
379+
resp, err := c.Do(req)
380+
if err != nil {
381+
return nil, fmt.Errorf("failed to get application: %w", err)
382+
}
383+
defer resp.Body.Close()
384+
385+
if resp.StatusCode == http.StatusNotFound {
386+
return nil, fmt.Errorf("application '%s' not found", name)
387+
}
388+
389+
if resp.StatusCode != http.StatusOK {
390+
body, _ := io.ReadAll(resp.Body)
391+
return nil, fmt.Errorf("failed to get application: status %d, body: %s", resp.StatusCode, string(body))
392+
}
393+
394+
var app v1alpha1.Application
395+
if err := json.NewDecoder(resp.Body).Decode(&app); err != nil {
396+
return nil, fmt.Errorf("failed to unmarshal application: %w", err)
397+
}
398+
399+
return &app, nil
400+
}
401+
402+
// ListApplications lists all applications
403+
func (c *ArgoRestClient) ListApplications() (*v1alpha1.ApplicationList, error) {
404+
reqURL := c.url()
405+
reqURL.Path = "/api/v1/applications"
406+
407+
req, err := http.NewRequest(http.MethodGet, reqURL.String(), nil)
408+
if err != nil {
409+
return nil, fmt.Errorf("failed to create request: %w", err)
410+
}
411+
412+
resp, err := c.Do(req)
413+
if err != nil {
414+
return nil, fmt.Errorf("failed to list applications: %w", err)
415+
}
416+
defer resp.Body.Close()
417+
418+
if resp.StatusCode != http.StatusOK {
419+
body, _ := io.ReadAll(resp.Body)
420+
return nil, fmt.Errorf("failed to list applications: status %d, body: %s", resp.StatusCode, string(body))
421+
}
422+
423+
var appList v1alpha1.ApplicationList
424+
if err := json.NewDecoder(resp.Body).Decode(&appList); err != nil {
425+
return nil, fmt.Errorf("failed to unmarshal application list: %w", err)
426+
}
427+
428+
return &appList, nil
429+
}
430+
431+
// DeleteApplication deletes an application by its name
432+
func (c *ArgoRestClient) DeleteApplication(name string) error {
433+
reqURL := c.url()
434+
reqURL.Path = fmt.Sprintf("/api/v1/applications/%s", name)
435+
436+
req, err := http.NewRequest(http.MethodDelete, reqURL.String(), nil)
437+
if err != nil {
438+
return fmt.Errorf("failed to create request: %w", err)
439+
}
440+
req.Header.Set("Content-Type", "application/json") // content-type
441+
442+
resp, err := c.Do(req)
443+
if err != nil {
444+
return fmt.Errorf("failed to delete application: %w", err)
445+
}
446+
defer resp.Body.Close()
447+
448+
if resp.StatusCode != http.StatusOK {
449+
body, _ := io.ReadAll(resp.Body)
450+
return fmt.Errorf("failed to delete application: status %d, body: %s", resp.StatusCode, string(body))
451+
}
452+
453+
return nil
454+
}

0 commit comments

Comments
 (0)