Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions cmpserver/plugin/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ func NewService(initConstants CMPServerInitConstants) *Service {
}
}

func (s *Service) Init() error {
workDir := common.GetCMPWorkDir()
func (s *Service) Init(workDir string) error {
err := os.RemoveAll(workDir)
if err != nil {
return fmt.Errorf("error removing workdir %q: %s", workDir, err)
Expand Down
146 changes: 138 additions & 8 deletions cmpserver/plugin/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package plugin
import (
"context"
"os"
"path"
"path/filepath"
"testing"
"time"
Expand All @@ -12,6 +13,7 @@ import (
"gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"github.com/argoproj/argo-cd/v2/cmpserver/apiclient"
repoclient "github.com/argoproj/argo-cd/v2/reposerver/apiclient"
"github.com/argoproj/argo-cd/v2/test"
)
Expand All @@ -32,6 +34,11 @@ func newService(configFilePath string) (*Service, error) {
return service, nil
}

func (s *Service) WithGenerateCommand(command Command) *Service {
s.initConstants.PluginConfig.Spec.Generate = command
return s
}

type pluginOpt func(*CMPServerInitConstants)

func withDiscover(d Discover) pluginOpt {
Expand Down Expand Up @@ -104,6 +111,19 @@ func TestMatchRepository(t *testing.T) {
assert.NoError(t, err)
assert.False(t, match)
})
t.Run("will not match a pattern with a syntax error", func(t *testing.T) {
// given
d := Discover{
FileName: "[",
}
f := setup(t, withDiscover(d))

// when
_, err := f.service.matchRepository(context.Background(), f.path)

// then
assert.ErrorContains(t, err, "syntax error")
})
t.Run("will match plugin by glob", func(t *testing.T) {
// given
d := Discover{
Expand Down Expand Up @@ -136,6 +156,21 @@ func TestMatchRepository(t *testing.T) {
assert.NoError(t, err)
assert.False(t, match)
})
t.Run("will throw an error for a bad pattern", func(t *testing.T) {
// given
d := Discover{
Find: Find{
Glob: "does-not-exist",
},
}
f := setup(t, withDiscover(d))

// when
_, err := f.service.matchRepository(context.Background(), f.path)

// then
assert.ErrorContains(t, err, "error finding glob match for pattern")
})
t.Run("will match plugin by command when returns any output", func(t *testing.T) {
// given
d := Discover{
Expand Down Expand Up @@ -201,17 +236,49 @@ func Test_Negative_ConfigFile_DoesnotExist(t *testing.T) {

func TestGenerateManifest(t *testing.T) {
configFilePath := "./testdata/kustomize/config"
service, err := newService(configFilePath)
require.NoError(t, err)

res1, err := service.generateManifest(context.Background(), "", nil)
t.Run("successful generate", func(t *testing.T) {
service, err := newService(configFilePath)
require.NoError(t, err)

res1, err := service.generateManifest(context.Background(), "", nil)
require.NoError(t, err)
require.NotNil(t, res1)

expectedOutput := "{\"apiVersion\":\"v1\",\"data\":{\"foo\":\"bar\"},\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"my-map\"}}"
if res1 != nil {
require.Equal(t, expectedOutput, res1.Manifests[0])
}
})
t.Run("bad generate command", func(t *testing.T) {
service, err := newService(configFilePath)
require.NoError(t, err)
service.WithGenerateCommand(Command{Command: []string{"bad-command"}})

res, err := service.generateManifest(context.Background(), "", nil)
assert.ErrorContains(t, err, "executable file not found")
assert.Nil(t, res.Manifests)
})
t.Run("bad yaml output", func(t *testing.T) {
service, err := newService(configFilePath)
require.NoError(t, err)
service.WithGenerateCommand(Command{Command: []string{"echo", "invalid yaml: }"}})

res, err := service.generateManifest(context.Background(), "", nil)
assert.ErrorContains(t, err, "failed to unmarshal manifest")
assert.Nil(t, res.Manifests)
})
}

func TestGenerateManifest_deadline_exceeded(t *testing.T) {
configFilePath := "./testdata/kustomize/config"
service, err := newService(configFilePath)
require.NoError(t, err)
require.NotNil(t, res1)

expectedOutput := "{\"apiVersion\":\"v1\",\"data\":{\"foo\":\"bar\"},\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"my-map\"}}"
if res1 != nil {
require.Equal(t, expectedOutput, res1.Manifests[0])
}
expiredCtx, cancel := context.WithTimeout(context.Background(), time.Second * 0)
defer cancel()
_, err = service.generateManifest(expiredCtx, "", nil)
assert.ErrorContains(t, err, "context deadline exceeded")
}

// TestRunCommandContextTimeout makes sure the command dies at timeout rather than sleeping past the timeout.
Expand All @@ -230,6 +297,11 @@ func TestRunCommandContextTimeout(t *testing.T) {
assert.Less(t, after.Sub(before), 1*time.Second)
}

func TestRunCommandEmptyCommand(t *testing.T) {
_, err := runCommand(context.Background(), Command{}, "", nil)
assert.ErrorContains(t, err, "Command is empty")
}

func Test_getParametersAnnouncement_empty_command(t *testing.T) {
staticYAML := `
- name: static-a
Expand Down Expand Up @@ -306,6 +378,15 @@ func Test_getParametersAnnouncement_bad_command(t *testing.T) {

func Test_getTempDirMustCleanup(t *testing.T) {
tempDir := t.TempDir()

// Induce a directory create error to verify error handling.
err := os.Chmod(tempDir, 0000)
require.NoError(t, err)
_, _, err = getTempDirMustCleanup(path.Join(tempDir, "test"))
assert.ErrorContains(t, err, "error creating temp dir")

err = os.Chmod(tempDir, 0700)
require.NoError(t, err)
workDir, cleanup, err := getTempDirMustCleanup(tempDir)
require.NoError(t, err)
require.DirExists(t, workDir)
Expand All @@ -322,3 +403,52 @@ func Test_getTempDirMustCleanup(t *testing.T) {
cleanup()
assert.NoDirExists(t, workDir)
}

func TestService_Init(t *testing.T) {
// Set up a base directory containing a test directory and a test file.
tempDir := t.TempDir()
workDir := path.Join(tempDir, "workDir")
err := os.MkdirAll(workDir, 0700)
require.NoError(t, err)
testfile := path.Join(workDir, "testfile")
file, err := os.Create(testfile)
require.NoError(t, err)
err = file.Close()
require.NoError(t, err)

// Make the base directory read-only so Init's cleanup fails.
err = os.Chmod(tempDir, 0000)
require.NoError(t, err)
s := NewService(CMPServerInitConstants{PluginConfig: PluginConfig{}})
err = s.Init(workDir)
assert.ErrorContains(t, err, "error removing workdir", "Init must throw an error if it can't remove the work directory")

// Make the base directory writable so Init's cleanup succeeds.
err = os.Chmod(tempDir, 0700)
require.NoError(t, err)
err = s.Init(workDir)
assert.NoError(t, err)
assert.DirExists(t, workDir)
assert.NoFileExists(t, testfile)
}

func TestEnviron(t *testing.T) {
t.Run("empty environ", func(t *testing.T) {
env := environ([]*apiclient.EnvEntry{})
assert.Nil(t, env)
})
t.Run("env vars with empty names or values", func(t *testing.T) {
env := environ([]*apiclient.EnvEntry{
{Value: "test"},
{Name: "test"},
})
assert.Nil(t, env)
})
t.Run("proper env vars", func(t *testing.T) {
env := environ([]*apiclient.EnvEntry{
{Name: "name1", Value: "value1"},
{Name: "name2", Value: "value2"},
})
assert.Equal(t, []string{"name1=value1", "name2=value2"}, env)
})
}
5 changes: 3 additions & 2 deletions cmpserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package cmpserver

import (
"fmt"
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
"net"
"os"
"os/signal"
"syscall"

"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"

grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
Expand Down Expand Up @@ -101,7 +102,7 @@ func (a *ArgoCDCMPServer) CreateGRPC() (*grpc.Server, error) {
return true, nil
}))
pluginService := plugin.NewService(a.initConstants)
err := pluginService.Init()
err := pluginService.Init(common.GetCMPWorkDir())
if err != nil {
return nil, fmt.Errorf("error initializing plugin service: %s", err)
}
Expand Down