Skip to content

Commit

Permalink
Unit tests/inject test clientset (#6874)
Browse files Browse the repository at this point in the history
* Inject testClientset

* Test analyze CLI as unit test

* Replace odo analyze integration tests with unit tests
  • Loading branch information
feloy authored Jun 13, 2023
1 parent 57da760 commit aabbded
Show file tree
Hide file tree
Showing 50 changed files with 404 additions and 191 deletions.
6 changes: 4 additions & 2 deletions cmd/cli-doc/cli-doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"

"github.com/redhat-developer/odo/pkg/odo/cli"
"github.com/redhat-developer/odo/pkg/odo/genericclioptions/clientset"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
Expand Down Expand Up @@ -173,11 +174,12 @@ func main() {
fmt.Print(command.Usage())
} else {
ctx := context.Background()
testClientset := clientset.Clientset{}
switch args[0] {
case "reference":
fmt.Print(referencePrinter(cli.NewCmdOdo(ctx, cli.OdoRecommendedName, cli.OdoRecommendedName), 0))
fmt.Print(referencePrinter(cli.NewCmdOdo(ctx, cli.OdoRecommendedName, cli.OdoRecommendedName, testClientset), 0))
case "structure":
fmt.Print(commandPrinter(cli.NewCmdOdo(ctx, cli.OdoRecommendedName, cli.OdoRecommendedName), 0))
fmt.Print(commandPrinter(cli.NewCmdOdo(ctx, cli.OdoRecommendedName, cli.OdoRecommendedName, testClientset), 0))
default:
fmt.Print(command.Usage())
}
Expand Down
118 changes: 118 additions & 0 deletions cmd/odo/alizer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package main

import (
"encoding/json"
"strings"
"testing"

"github.com/golang/mock/gomock"
"github.com/redhat-developer/alizer/go/pkg/apis/model"
"github.com/redhat-developer/odo/pkg/alizer"
"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/odo/genericclioptions/clientset"
"github.com/redhat-developer/odo/pkg/testingutil/filesystem"
)

func TestOdoAlizer(t *testing.T) {

for _, tt := range []struct {
name string
clientset func() clientset.Clientset
args []string
wantErr string
wantStdout string
wantStderr string
checkJsonOutput func(t *testing.T, b []byte)
}{
{
name: "analyze without json output",
clientset: func() clientset.Clientset {
return clientset.Clientset{}
},
args: []string{"analyze"},
wantErr: "this command can be run with json output only, please use the flag: -o json",
},
{
name: "analyze with json output in an empty directory",
clientset: func() clientset.Clientset {
return clientset.Clientset{}
},
args: []string{"analyze", "-o", "json"},
wantErr: "No valid devfile found for project in",
},
{
name: "analyze with json output",
clientset: func() clientset.Clientset {
ctrl := gomock.NewController(t)
fs := filesystem.NewFakeFs()
alizerClient := alizer.NewMockClient(ctrl)
path := "."
alizerClient.EXPECT().DetectFramework(gomock.Any(), path).
Return(
model.DevFileType{
Name: "framework-name",
},
"1.1.1",
api.Registry{
Name: "TheRegistryName",
},
nil,
)
alizerClient.EXPECT().DetectPorts(path).Return([]int{8080, 3000}, nil)
alizerClient.EXPECT().DetectName(path).Return("aName", nil)
return clientset.Clientset{
FS: fs,
AlizerClient: alizerClient,
}
},
args: []string{"analyze", "-o", "json"},
checkJsonOutput: func(t *testing.T, b []byte) {
var output []api.DetectionResult
err := json.Unmarshal(b, &output)
if err != nil {
t.Error(err)
}
checkEqual(t, output[0].Devfile, "framework-name")
checkEqual(t, output[0].DevfileRegistry, "TheRegistryName")
checkEqual(t, output[0].Name, "aName")
checkEqual(t, output[0].DevfileVersion, "1.1.1")
checkEqual(t, output[0].ApplicationPorts[0], 8080)
checkEqual(t, output[0].ApplicationPorts[1], 3000)
},
},
} {
t.Run(tt.name, func(t *testing.T) {
clientset := clientset.Clientset{}
if tt.clientset != nil {
clientset = tt.clientset()
}
runCommand(t, tt.args, clientset, func(err error, stdout, stderr string) {
if (err != nil) != (tt.wantErr != "") {
t.Fatalf("errWanted: %v\nGot: %v", tt.wantErr != "", err != nil)
}

if tt.wantErr != "" {
if !strings.Contains(err.Error(), tt.wantErr) {
t.Fatalf("%q\nerror does not contain:\n%q", err.Error(), tt.wantErr)
}
}

if tt.wantStdout != "" {
if !strings.Contains(stdout, tt.wantStdout) {
t.Fatalf("%q\nstdout does not contain:\n%q", stdout, tt.wantStdout)
}
}

if tt.wantStderr != "" {
if !strings.Contains(stderr, tt.wantStderr) {
t.Fatalf("%q\nstderr does not contain:\n%q", stderr, tt.wantStderr)
}
}

if tt.checkJsonOutput != nil {
tt.checkJsonOutput(t, []byte(stdout))
}
})
})
}
}
77 changes: 77 additions & 0 deletions cmd/odo/common_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package main

import (
"bytes"
"context"
"flag"
"os"
"testing"

"github.com/redhat-developer/odo/pkg/config"
envcontext "github.com/redhat-developer/odo/pkg/config/context"
"github.com/redhat-developer/odo/pkg/odo/cli"
"github.com/redhat-developer/odo/pkg/odo/genericclioptions/clientset"
"github.com/spf13/pflag"
"k8s.io/klog"
)

func resetGlobalFlags() {
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
pflag.CommandLine = pflag.NewFlagSet(os.Args[0], pflag.ExitOnError)
klog.InitFlags(nil)
}

func runCommand(
t *testing.T,
args []string,
clientset clientset.Clientset,
f func(err error, stdout, stderr string),
) {

// We are running the test on a new and empty directory (on real filesystem)
originWd, err := os.Getwd()
if err != nil {
t.Error(err)
}
defer func() {
_ = os.Chdir(originWd)
}()
cwd := t.TempDir()
err = os.Chdir(cwd)
if err != nil {
t.Error(err)
}

ctx := context.Background()
envConfig, err := config.GetConfiguration()
if err != nil {
t.Fatal(err)
}
ctx = envcontext.WithEnvConfig(ctx, *envConfig)

resetGlobalFlags()

var stdoutB, stderrB bytes.Buffer

clientset.Stdout = &stdoutB
clientset.Stderr = &stderrB
root := cli.NewCmdOdo(ctx, cli.OdoRecommendedName, cli.OdoRecommendedName, clientset)

root.SetOut(&stdoutB)
root.SetErr(&stderrB)

root.SetArgs(args)

err = root.ExecuteContext(ctx)

stdout := stdoutB.String()
stderr := stderrB.String()

f(err, stdout, stderr)
}

func checkEqual[T comparable](t *testing.T, a, b T) {
if a != b {
t.Errorf("Name should be \"%v\" but is \"%v\"", b, a)
}
}
7 changes: 4 additions & 3 deletions cmd/odo/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/redhat-developer/odo/pkg/config"
envcontext "github.com/redhat-developer/odo/pkg/config/context"
"github.com/redhat-developer/odo/pkg/odo/cli"
"k8s.io/klog"
"github.com/redhat-developer/odo/pkg/odo/genericclioptions/clientset"
)

var (
Expand Down Expand Up @@ -69,9 +69,10 @@ func TestOdoHelp(t *testing.T) {
t.Fatal(err)
}
ctx = envcontext.WithEnvConfig(ctx, *envConfig)
klog.InitFlags(nil)

root := cli.NewCmdOdo(ctx, cli.OdoRecommendedName, cli.OdoRecommendedName)
resetGlobalFlags()

root := cli.NewCmdOdo(ctx, cli.OdoRecommendedName, cli.OdoRecommendedName, clientset.Clientset{})

var stdoutB, stderrB bytes.Buffer
root.SetOut(&stdoutB)
Expand Down
3 changes: 2 additions & 1 deletion cmd/odo/odo.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/redhat-developer/odo/pkg/odo/cli"
"github.com/redhat-developer/odo/pkg/odo/cli/version"
odocontext "github.com/redhat-developer/odo/pkg/odo/context"
"github.com/redhat-developer/odo/pkg/odo/genericclioptions/clientset"
"github.com/redhat-developer/odo/pkg/odo/util"
"github.com/redhat-developer/odo/pkg/odo/util/completion"
"github.com/redhat-developer/odo/pkg/preference"
Expand All @@ -37,7 +38,7 @@ func main() {
// create the complete command
klog.InitFlags(nil)

root := cli.NewCmdOdo(ctx, cli.OdoRecommendedName, cli.OdoRecommendedName)
root := cli.NewCmdOdo(ctx, cli.OdoRecommendedName, cli.OdoRecommendedName, clientset.Clientset{})
rootCmp := createCompletion(root)
cmp := complete.New("odo", rootCmp)

Expand Down
42 changes: 41 additions & 1 deletion pkg/alizer/alizer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package alizer
import (
"context"
"path/filepath"
"reflect"
"runtime"
"testing"

"github.com/golang/mock/gomock"

"github.com/redhat-developer/odo/pkg/api"
"github.com/redhat-developer/odo/pkg/registry"
)
Expand Down Expand Up @@ -200,3 +200,43 @@ func TestDetectName(t *testing.T) {
})
}
}

func TestAlizer_DetectPorts(t *testing.T) {
type fields struct {
registryClient registry.Client
}
type args struct {
path string
}
tests := []struct {
name string
fields fields
args args
want []int
wantErr bool
}{
{
name: "Detect Node.JS example",
args: args{
path: GetTestProjectPath("nodejs"),
},
want: []int{8080},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
o := &Alizer{
registryClient: tt.fields.registryClient,
}
got, err := o.DetectPorts(tt.args.path)
if (err != nil) != tt.wantErr {
t.Errorf("Alizer.DetectPorts() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Alizer.DetectPorts() = %v, want %v", got, tt.want)
}
})
}
}
14 changes: 11 additions & 3 deletions pkg/machineoutput/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package machineoutput
import (
"encoding/json"
"fmt"
"io"
"sync"

"github.com/redhat-developer/odo/pkg/log"
Expand Down Expand Up @@ -35,14 +36,21 @@ func OutputSuccessUnindented(machineOutput interface{}) {
}

// OutputSuccess outputs a "successful" machine-readable output format in json
func OutputSuccess(machineOutput interface{}) {
func OutputSuccess(stdout, stderr io.Writer, machineOutput interface{}) {
printableOutput, err := marshalJSONIndented(machineOutput)

if stdout == nil {
stdout = log.GetStdout()
}
if stderr == nil {
stderr = log.GetStderr()
}

// If we error out... there's no way to output it (since we disable logging when using -o json)
if err != nil {
fmt.Fprintf(log.GetStderr(), "Unable to unmarshal JSON: %s\n", err.Error())
fmt.Fprintf(stderr, "Unable to unmarshal JSON: %s\n", err.Error())
} else {
fmt.Fprintf(log.GetStdout(), "%s\n", string(printableOutput))
fmt.Fprintf(stdout, "%s\n", string(printableOutput))
}
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/odo/cli/add/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ import (
"github.com/spf13/cobra"

"github.com/redhat-developer/odo/pkg/odo/cli/add/binding"
"github.com/redhat-developer/odo/pkg/odo/genericclioptions/clientset"
"github.com/redhat-developer/odo/pkg/odo/util"
)

// RecommendedCommandName is the recommended add command name
const RecommendedCommandName = "add"

// NewCmdAdd implements the odo add command
func NewCmdAdd(name, fullName string) *cobra.Command {
func NewCmdAdd(name, fullName string, testClientset clientset.Clientset) *cobra.Command {
var createCmd = &cobra.Command{
Use: name,
Short: "Add resources to devfile",
}

bindingCmd := binding.NewCmdBinding(binding.BindingRecommendedCommandName, util.GetFullName(fullName, binding.BindingRecommendedCommandName))
bindingCmd := binding.NewCmdBinding(binding.BindingRecommendedCommandName, util.GetFullName(fullName, binding.BindingRecommendedCommandName), testClientset)
createCmd.AddCommand(bindingCmd)
util.SetCommandGroup(createCmd, util.ManagementGroup)
createCmd.SetUsageTemplate(util.CmdUsageTemplate)
Expand Down
4 changes: 2 additions & 2 deletions pkg/odo/cli/add/binding/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func (o *AddBindingOptions) Run(ctx context.Context) error {
}

// NewCmdBinding implements the component odo sub-command
func NewCmdBinding(name, fullName string) *cobra.Command {
func NewCmdBinding(name, fullName string, testClientset clientset.Clientset) *cobra.Command {
o := NewAddBindingOptions()

var bindingCmd = &cobra.Command{
Expand All @@ -208,7 +208,7 @@ func NewCmdBinding(name, fullName string) *cobra.Command {
Args: genericclioptions.NoArgsAndSilenceJSON,
Example: fmt.Sprintf(addBindingExample, fullName),
RunE: func(cmd *cobra.Command, args []string) error {
return genericclioptions.GenericRun(o, cmd, args)
return genericclioptions.GenericRun(o, testClientset, cmd, args)
},
}
bindingCmd.Flags().String(backend.FLAG_NAME, "", "Name of the Binding to add")
Expand Down
Loading

0 comments on commit aabbded

Please # to comment.