get.porter.sh/porter@v1.3.0/pkg/grpc/portergrpc/installation_test.go (about)

     1  package portergrpc
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"testing"
     8  
     9  	iGRPC "get.porter.sh/porter/gen/proto/go/porterapis/installation/v1alpha1"
    10  	"get.porter.sh/porter/pkg/cnab"
    11  	"get.porter.sh/porter/pkg/porter"
    12  	"get.porter.sh/porter/pkg/storage"
    13  	"get.porter.sh/porter/tests"
    14  	"github.com/google/uuid"
    15  	"github.com/stretchr/testify/assert"
    16  	"google.golang.org/protobuf/encoding/protojson"
    17  	"k8s.io/utils/ptr"
    18  )
    19  
    20  type instInfo struct {
    21  	namespace string
    22  	name      string
    23  }
    24  
    25  func TestListInstallationReturnsListOfCorrectPorterInstallations(t *testing.T) {
    26  	testNamespace := "test"
    27  	testInstallationName := "foo"
    28  	filterOpts := []struct {
    29  		name string
    30  		opts *iGRPC.ListInstallationsRequest
    31  	}{
    32  		{
    33  			name: "FilterByAllNamespaces",
    34  			opts: &iGRPC.ListInstallationsRequest{AllNamespaces: ptr.To(true)},
    35  		},
    36  		{
    37  			name: "FilterByNamespace",
    38  			opts: &iGRPC.ListInstallationsRequest{Namespace: &testNamespace},
    39  		},
    40  		{
    41  			name: "FilterByInstallationNameAndNamespace",
    42  			opts: &iGRPC.ListInstallationsRequest{Namespace: &testNamespace, Name: testInstallationName},
    43  		},
    44  	}
    45  	tests := []struct {
    46  		name     string
    47  		instInfo []instInfo
    48  		// Number of expected installations when filtering by all namespaces, all installations in a single namespace, and a single installation in a namespace
    49  		numExpInsts []int
    50  	}{
    51  		{
    52  			name:        "NoInstallations",
    53  			instInfo:    []instInfo{},
    54  			numExpInsts: []int{0, 0, 0},
    55  		},
    56  		{
    57  			name: "SingleInstallationDefaultNamespace",
    58  			instInfo: []instInfo{
    59  				{namespace: "", name: "test"},
    60  			},
    61  			numExpInsts: []int{1, 0, 0},
    62  		},
    63  		{
    64  			name: "SingleInstallationInMultipleNamespaces",
    65  			instInfo: []instInfo{
    66  				{namespace: testNamespace, name: testInstallationName},
    67  				{namespace: "bar", name: "test"},
    68  			},
    69  			numExpInsts: []int{2, 1, 1},
    70  		},
    71  		{
    72  			name: "MultipleInstallationSInMultipleNamespaces",
    73  			instInfo: []instInfo{
    74  				{namespace: "foo", name: "test1"},
    75  				{namespace: "foo", name: "test2"},
    76  				{namespace: testNamespace, name: testInstallationName},
    77  				{namespace: testNamespace, name: "test4"},
    78  			},
    79  			numExpInsts: []int{4, 2, 1},
    80  		},
    81  	}
    82  	for _, test := range tests {
    83  		ctx, insts := setupTestPorterWithInstallations(t, test.instInfo)
    84  		for i, opts := range filterOpts {
    85  			t.Run(fmt.Sprintf("%s%s", test.name, opts.name), func(t *testing.T) {
    86  				instSvc := PorterServer{}
    87  				resp, err := instSvc.ListInstallations(ctx, opts.opts)
    88  				installations := resp.GetInstallation()
    89  				assert.Nil(t, err)
    90  				assert.Len(t, installations, test.numExpInsts[i])
    91  				verifyInstallations(t, installations, insts)
    92  			})
    93  		}
    94  	}
    95  }
    96  
    97  func TestListInstallationsReturnsErrorIfUnableToGetPorterConnectionFromRequestContext(t *testing.T) {
    98  	instSvc := PorterServer{}
    99  	req := &iGRPC.ListInstallationsRequest{}
   100  	ctx := context.TODO()
   101  	resp, err := instSvc.ListInstallations(ctx, req)
   102  	assert.Error(t, err)
   103  	assert.Nil(t, resp)
   104  
   105  }
   106  
   107  func setupTestPorterWithInstallations(t *testing.T, installations []instInfo) (context.Context, map[string]porter.DisplayInstallation) {
   108  	p := porter.NewTestPorter(t)
   109  	insts := map[string]porter.DisplayInstallation{}
   110  	for _, inst := range installations {
   111  		installation := storage.NewInstallation(inst.namespace, inst.name)
   112  		storeInst := p.TestInstallations.CreateInstallation(installation, p.TestInstallations.SetMutableInstallationValues, func(i *storage.Installation) {
   113  			// Overwrite the default ID set by SetMutableInstallationValues because it is always the same
   114  			i.ID = uuid.NewString()
   115  			i.Status.BundleVersion = "v0.1.0"
   116  			i.Status.ResultStatus = cnab.StatusSucceeded
   117  			i.Bundle.Repository = "test-bundle"
   118  			i.Bundle.Version = "v0.1.0"
   119  		})
   120  		insts[storeInst.ID] = porter.NewDisplayInstallation(storeInst)
   121  	}
   122  	ctx := AddPorterConnectionToContext(p.Porter, context.TODO())
   123  	return ctx, insts
   124  }
   125  
   126  func verifyInstallations(t *testing.T, installations []*iGRPC.Installation, allInsts map[string]porter.DisplayInstallation) {
   127  	for _, inst := range installations {
   128  		i, ok := allInsts[inst.Id]
   129  		assert.True(t, ok)
   130  		bExpInst, err := json.Marshal(i)
   131  		assert.NoError(t, err)
   132  		grpcExpInst, err := tests.GRPCDisplayInstallationExpectedJSON(bExpInst)
   133  		assert.NoError(t, err)
   134  		pjm := protojson.MarshalOptions{EmitUnpopulated: true}
   135  		bActInst, err := pjm.Marshal(inst)
   136  		assert.NoError(t, err)
   137  		assert.JSONEq(t, string(grpcExpInst), string(bActInst))
   138  	}
   139  }