github.com/Axway/agent-sdk@v1.1.101/pkg/apic/apiserviceinstance_test.go (about)

     1  package apic
     2  
     3  import (
     4  	"net/http"
     5  	"testing"
     6  
     7  	"github.com/Axway/agent-sdk/pkg/api"
     8  	apiv1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
     9  	management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1"
    10  	defs "github.com/Axway/agent-sdk/pkg/apic/definitions"
    11  	"github.com/Axway/agent-sdk/pkg/util"
    12  	"github.com/stretchr/testify/assert"
    13  )
    14  
    15  func TestServiceClient_buildAPIServiceInstance(t *testing.T) {
    16  	body := &ServiceBody{
    17  		Description:      "description",
    18  		ImageContentType: "content-type",
    19  		Image:            "image-data",
    20  		NameToPush:       "nametopush",
    21  		APIName:          "apiname",
    22  		RestAPIID:        "restapiid",
    23  		PrimaryKey:       "primarykey",
    24  		Stage:            "staging",
    25  		Version:          "v1",
    26  		Tags: map[string]interface{}{
    27  			"tag1": "value1",
    28  			"tag2": "value2",
    29  		},
    30  		CreatedBy:          "createdby",
    31  		ServiceAttributes:  map[string]string{"service_attribute": "value"},
    32  		RevisionAttributes: map[string]string{"revision_attribute": "value"},
    33  		InstanceAttributes: map[string]string{"instance_attribute": "value"},
    34  		ServiceAgentDetails: map[string]interface{}{
    35  			"subresource_svc_key": "value",
    36  		},
    37  		InstanceAgentDetails: map[string]interface{}{
    38  			"subresource_instance_key": "value",
    39  		},
    40  		RevisionAgentDetails: map[string]interface{}{
    41  			"subresource_revision_key": "value",
    42  		},
    43  	}
    44  
    45  	tags := []string{"tag1_value1", "tag2_value2"}
    46  
    47  	client, _ := GetTestServiceClient()
    48  	ep := []management.ApiServiceInstanceSpecEndpoint{
    49  		{
    50  			Host:     "abc.com",
    51  			Port:     80,
    52  			Protocol: "http",
    53  			Routing: management.ApiServiceInstanceSpecRouting{
    54  				BasePath: "/base",
    55  			},
    56  		},
    57  		{
    58  			Host:     "123.com",
    59  			Port:     443,
    60  			Protocol: "https",
    61  			Routing: management.ApiServiceInstanceSpecRouting{
    62  				BasePath: "/path",
    63  			},
    64  		},
    65  	}
    66  	inst := client.buildAPIServiceInstance(body, "name", ep)
    67  
    68  	assert.Equal(t, management.APIServiceInstanceGVK(), inst.GroupVersionKind)
    69  	assert.Equal(t, "name", inst.Name)
    70  	assert.Equal(t, body.NameToPush, inst.Title)
    71  
    72  	assert.Contains(t, inst.Tags, tags[0])
    73  	assert.Contains(t, inst.Tags, tags[1])
    74  
    75  	assert.Contains(t, inst.Attributes, "instance_attribute")
    76  	assert.NotContains(t, inst.Attributes, "service_attribute")
    77  	assert.NotContains(t, inst.Attributes, "revision_attribute")
    78  	assert.NotContains(t, inst.Attributes, defs.AttrExternalAPIStage)
    79  	assert.NotContains(t, inst.Attributes, defs.AttrExternalAPIPrimaryKey)
    80  	assert.NotContains(t, inst.Attributes, defs.AttrExternalAPIID)
    81  	assert.NotContains(t, inst.Attributes, defs.AttrExternalAPIName)
    82  	assert.NotContains(t, inst.Attributes, defs.AttrCreatedBy)
    83  
    84  	assert.Equal(t, inst.Spec.Endpoint, ep)
    85  
    86  	sub := util.GetAgentDetails(inst)
    87  	assert.Equal(t, body.Stage, sub[defs.AttrExternalAPIStage])
    88  	assert.Equal(t, body.PrimaryKey, sub[defs.AttrExternalAPIPrimaryKey])
    89  	assert.Equal(t, body.RestAPIID, sub[defs.AttrExternalAPIID])
    90  	assert.Equal(t, body.APIName, sub[defs.AttrExternalAPIName])
    91  	assert.Equal(t, body.CreatedBy, sub[defs.AttrCreatedBy])
    92  	assert.Contains(t, sub, "subresource_svc_key")
    93  	assert.Contains(t, sub, "subresource_instance_key")
    94  	assert.NotContains(t, sub, "subresource_revision_key")
    95  	assert.NotContains(t, sub, "revision_attribute")
    96  }
    97  
    98  func TestServiceClient_updateAPIServiceInstance(t *testing.T) {
    99  	body := &ServiceBody{
   100  		Description:      "description",
   101  		ImageContentType: "content-type",
   102  		Image:            "image-data",
   103  		NameToPush:       "nametopush",
   104  		APIName:          "apiname",
   105  		RestAPIID:        "restapiid",
   106  		PrimaryKey:       "primarykey",
   107  		Stage:            "staging",
   108  		Version:          "v1",
   109  		Tags: map[string]interface{}{
   110  			"tag1": "value1",
   111  			"tag2": "value2",
   112  		},
   113  		CreatedBy:          "createdby",
   114  		ServiceAttributes:  map[string]string{"service_attribute": "value"},
   115  		RevisionAttributes: map[string]string{"revision_attribute": "value"},
   116  		InstanceAttributes: map[string]string{"instance_attribute": "value"},
   117  		ServiceAgentDetails: map[string]interface{}{
   118  			"subresource_svc_key": "value",
   119  		},
   120  		InstanceAgentDetails: map[string]interface{}{
   121  			"subresource_instance_key": "value",
   122  		},
   123  		RevisionAgentDetails: map[string]interface{}{
   124  			"subresource_revision_key": "value",
   125  		},
   126  	}
   127  
   128  	tags := []string{"tag1_value1", "tag2_value2"}
   129  
   130  	client, _ := GetTestServiceClient()
   131  	ep := []management.ApiServiceInstanceSpecEndpoint{
   132  		{
   133  			Host:     "abc.com",
   134  			Port:     80,
   135  			Protocol: "http",
   136  			Routing: management.ApiServiceInstanceSpecRouting{
   137  				BasePath: "/base",
   138  			},
   139  		},
   140  		{
   141  			Host:     "123.com",
   142  			Port:     443,
   143  			Protocol: "https",
   144  			Routing: management.ApiServiceInstanceSpecRouting{
   145  				BasePath: "/path",
   146  			},
   147  		},
   148  	}
   149  	inst := &management.APIServiceInstance{
   150  		ResourceMeta: apiv1.ResourceMeta{
   151  			Title: "oldname",
   152  			Attributes: map[string]string{
   153  				"old_attr": "value",
   154  			},
   155  			Name:     "name",
   156  			Tags:     []string{"old_tag"},
   157  			Metadata: apiv1.Metadata{ResourceVersion: ""},
   158  		},
   159  	}
   160  	inst = client.updateAPIServiceInstance(body, inst, ep)
   161  
   162  	assert.Equal(t, management.APIServiceInstanceGVK(), inst.GroupVersionKind)
   163  	assert.Empty(t, inst.Metadata.ResourceVersion)
   164  	assert.Equal(t, "name", inst.Name)
   165  	assert.Equal(t, body.NameToPush, inst.Title)
   166  
   167  	assert.Contains(t, inst.Tags, tags[0])
   168  	assert.Contains(t, inst.Tags, tags[1])
   169  	assert.NotContains(t, inst.Tags, "old_tag")
   170  
   171  	assert.Equal(t, inst.Spec.Endpoint, ep)
   172  
   173  	assert.Contains(t, inst.Attributes, "instance_attribute")
   174  	assert.NotContains(t, inst.Attributes, "service_attribute")
   175  	assert.NotContains(t, inst.Attributes, "revision_attribute")
   176  	assert.NotContains(t, inst.Attributes, "old_attr")
   177  	assert.NotContains(t, inst.Attributes, defs.AttrExternalAPIStage)
   178  	assert.NotContains(t, inst.Attributes, defs.AttrExternalAPIPrimaryKey)
   179  	assert.NotContains(t, inst.Attributes, defs.AttrExternalAPIID)
   180  	assert.NotContains(t, inst.Attributes, defs.AttrExternalAPIName)
   181  	assert.NotContains(t, inst.Attributes, defs.AttrCreatedBy)
   182  
   183  	sub := util.GetAgentDetails(inst)
   184  	assert.Equal(t, body.Stage, sub[defs.AttrExternalAPIStage])
   185  	assert.Equal(t, body.PrimaryKey, sub[defs.AttrExternalAPIPrimaryKey])
   186  	assert.Equal(t, body.RestAPIID, sub[defs.AttrExternalAPIID])
   187  	assert.Equal(t, body.APIName, sub[defs.AttrExternalAPIName])
   188  	assert.Equal(t, body.CreatedBy, sub[defs.AttrCreatedBy])
   189  	assert.Contains(t, sub, "subresource_svc_key")
   190  	assert.Contains(t, sub, "subresource_instance_key")
   191  	assert.NotContains(t, sub, "subresource_revision_key")
   192  	assert.NotContains(t, sub, "revision_attribute")
   193  }
   194  
   195  func Test_buildAPIServiceInstanceNilAttributes(t *testing.T) {
   196  	client, _ := GetTestServiceClient()
   197  	body := &ServiceBody{}
   198  	ep := []management.ApiServiceInstanceSpecEndpoint{}
   199  	inst := client.buildAPIServiceInstance(body, "name", ep)
   200  	assert.NotNil(t, inst.Attributes)
   201  
   202  	inst.Attributes = nil
   203  
   204  	inst = client.updateAPIServiceInstance(body, inst, ep)
   205  	assert.NotNil(t, inst.Attributes)
   206  }
   207  
   208  func createAPIServiceInstance(name, id string, refInstance string, dpType string, isDesign bool) *management.APIServiceInstance {
   209  	instance := &management.APIServiceInstance{
   210  		ResourceMeta: apiv1.ResourceMeta{
   211  			Name:  name,
   212  			Title: name,
   213  			SubResources: map[string]interface{}{
   214  				defs.XAgentDetails: map[string]interface{}{
   215  					defs.AttrExternalAPIID:   id,
   216  					defs.AttrExternalAPIName: name,
   217  				},
   218  			},
   219  		},
   220  		Spec: management.ApiServiceInstanceSpec{},
   221  	}
   222  	if refInstance != "" || dpType != "" {
   223  		instance.Source = &management.ApiServiceInstanceSource{
   224  			References: &management.ApiServiceInstanceSourceReferences{
   225  				ApiServiceInstance: refInstance,
   226  			},
   227  		}
   228  		instance.Source.DataplaneType = &management.ApiServiceInstanceSourceDataplaneType{}
   229  		if isDesign {
   230  			instance.Source.DataplaneType.Design = dpType
   231  		} else {
   232  			instance.Source.DataplaneType.Managed = dpType
   233  		}
   234  	}
   235  	return instance
   236  }
   237  
   238  func TestInstanceSourceUpdates(t *testing.T) {
   239  	// case 1 - new instance, source managed dataplane, sub resource updated
   240  	// case 2 - new instance, source design dataplane, sub resource updated
   241  	// case 3 - new instance, source unmanaged dataplane with reference, sub resource updated
   242  	// case 4 - existing instance, no source, source updated
   243  	// case 5 - existing instance, existing source, different dataplane type, source updated
   244  	// case 6 - existing instance, existing source, different reference, source updated
   245  	// case 7 - existing instance, existing source, same dataplane type and same reference, no source updated
   246  	testCases := []struct {
   247  		name               string
   248  		instanceName       string
   249  		managedDataplane   DataplaneType
   250  		designDataplane    DataplaneType
   251  		existingInstance   *management.APIServiceInstance
   252  		referenceInstance  string
   253  		apiserverResponses []api.MockResponse
   254  	}{
   255  		{
   256  			name:             "new instance for managed dataplane",
   257  			instanceName:     "newInstManaged",
   258  			managedDataplane: AWS,
   259  			apiserverResponses: []api.MockResponse{
   260  				{
   261  					FileName: "./testdata/serviceinstance.json", // call to create the instance
   262  					RespCode: http.StatusCreated,
   263  				},
   264  				{
   265  					FileName: "./testdata/serviceinstance.json", // call to update source subresource
   266  					RespCode: http.StatusOK,
   267  				},
   268  				{
   269  					FileName: "./testdata/serviceinstance.json", // call to update source subresource
   270  					RespCode: http.StatusOK,
   271  				},
   272  			},
   273  		},
   274  		{
   275  			name:            "new instance for design dataplane",
   276  			instanceName:    "newInstDesign",
   277  			designDataplane: GitLab,
   278  			apiserverResponses: []api.MockResponse{
   279  				{
   280  					FileName: "./testdata/serviceinstance.json", // call to create the instance
   281  					RespCode: http.StatusCreated,
   282  				},
   283  				{
   284  					FileName: "./testdata/serviceinstance.json", // call to update x-agent-details subresource
   285  					RespCode: http.StatusOK,
   286  				},
   287  				{
   288  					FileName: "./testdata/serviceinstance.json", // call to update source subresource
   289  					RespCode: http.StatusOK,
   290  				},
   291  			},
   292  		},
   293  		{
   294  			name:              "new instance for unmanaged dataplane with referenced instance",
   295  			instanceName:      "newInstUnmanaged",
   296  			managedDataplane:  Unclassified,
   297  			referenceInstance: "refInst",
   298  			apiserverResponses: []api.MockResponse{
   299  				{
   300  					FileName: "./testdata/serviceinstance.json", // call to create the instance
   301  					RespCode: http.StatusCreated,
   302  				},
   303  				{
   304  					FileName: "./testdata/serviceinstance.json", // call to update x-agent-details subresource
   305  					RespCode: http.StatusOK,
   306  				},
   307  				{
   308  					FileName: "./testdata/serviceinstance.json", // call to update source subresource
   309  					RespCode: http.StatusOK,
   310  				},
   311  			},
   312  		},
   313  		{
   314  			name:             "existing instance with no source",
   315  			instanceName:     "daleapi",
   316  			managedDataplane: AWS,
   317  			existingInstance: createAPIServiceInstance("daleapi", "2f5f92f0-f5e4-44fb-bc84-599c27b3497a", "", "", false),
   318  			apiserverResponses: []api.MockResponse{
   319  				{
   320  					FileName: "./testdata/serviceinstance.json", // call to get the instance
   321  					RespCode: http.StatusOK,
   322  				},
   323  				{
   324  					FileName: "./testdata/serviceinstance.json", // call to update the instance
   325  					RespCode: http.StatusOK,
   326  				},
   327  				{
   328  					FileName: "./testdata/serviceinstance.json", // call to update x-agent-details subresource
   329  					RespCode: http.StatusOK,
   330  				},
   331  				{
   332  					FileName: "./testdata/serviceinstance.json", // call to update source subresource
   333  					RespCode: http.StatusOK,
   334  				},
   335  			},
   336  		},
   337  		{
   338  			name:             "existing instance with different dataplane type",
   339  			instanceName:     "existingInstance",
   340  			managedDataplane: AWS,
   341  			existingInstance: createAPIServiceInstance("existingInstance", "existingInstance", "", Unclassified.String(), false),
   342  			apiserverResponses: []api.MockResponse{
   343  				{
   344  					FileName: "./testdata/existingserviceinstances.json", // call to get the instance
   345  					RespCode: http.StatusOK,
   346  				},
   347  				{
   348  					FileName: "./testdata/serviceinstance.json", // call to update the instance
   349  					RespCode: http.StatusOK,
   350  				},
   351  				{
   352  					FileName: "./testdata/serviceinstance.json", // call to update x-agent-details subresource
   353  					RespCode: http.StatusOK,
   354  				},
   355  				{
   356  					FileName: "./testdata/serviceinstance.json", // call to update source subresource
   357  					RespCode: http.StatusOK,
   358  				},
   359  			},
   360  		},
   361  		{
   362  			name:              "existing instance with different referenced instance",
   363  			instanceName:      "existingInstance",
   364  			managedDataplane:  Unclassified,
   365  			existingInstance:  createAPIServiceInstance("existingInstance", "existingInstance", "refInstance", Unclassified.String(), false),
   366  			referenceInstance: "newRefInstance",
   367  			apiserverResponses: []api.MockResponse{
   368  				{
   369  					FileName: "./testdata/existingserviceinstances.json", // call to get the instance
   370  					RespCode: http.StatusOK,
   371  				},
   372  				{
   373  					FileName: "./testdata/serviceinstance.json", // call to update the instance
   374  					RespCode: http.StatusOK,
   375  				},
   376  				{
   377  					FileName: "./testdata/serviceinstance.json", // call to update x-agent-details subresource
   378  					RespCode: http.StatusOK,
   379  				},
   380  				{
   381  					FileName: "./testdata/serviceinstance.json", // call to update source subresource
   382  					RespCode: http.StatusOK,
   383  				},
   384  			},
   385  		},
   386  		{
   387  			name:              "existing instance with same source",
   388  			instanceName:      "existingInstance",
   389  			managedDataplane:  Unclassified,
   390  			existingInstance:  createAPIServiceInstance("existingInstance", "existingInstance", "refInstance", Unclassified.String(), false),
   391  			referenceInstance: "refInstance",
   392  			apiserverResponses: []api.MockResponse{
   393  				{
   394  					FileName: "./testdata/existingserviceinstances.json", // call to get the instance
   395  					RespCode: http.StatusOK,
   396  				},
   397  				{
   398  					FileName: "./testdata/serviceinstance.json", // call to update the instance
   399  					RespCode: http.StatusOK,
   400  				},
   401  				{
   402  					FileName: "./testdata/serviceinstance.json", // call to update x-agent-details subresource
   403  					RespCode: http.StatusOK,
   404  				},
   405  				// no source subresource update
   406  			},
   407  		},
   408  	}
   409  	for _, test := range testCases {
   410  		t.Run(test.name, func(t *testing.T) {
   411  			client, httpClient := GetTestServiceClient()
   412  			body := &ServiceBody{
   413  				RestAPIID: test.instanceName,
   414  			}
   415  
   416  			if test.existingInstance != nil {
   417  				ri, _ := test.existingInstance.AsInstance()
   418  				client.caches.AddAPIServiceInstance(ri)
   419  				body.serviceContext.serviceAction = updateAPI
   420  				body.serviceContext.revisionCount = 1
   421  			}
   422  
   423  			if test.managedDataplane != "" {
   424  				body.dataplaneType = test.managedDataplane
   425  			}
   426  			if test.designDataplane != "" {
   427  				body.dataplaneType = test.designDataplane
   428  				body.isDesignDataplane = true
   429  			}
   430  			body.referencedInstanceName = test.referenceInstance
   431  			httpClient.SetResponses(test.apiserverResponses)
   432  
   433  			err := client.processInstance(body)
   434  			assert.Nil(t, err)
   435  			assert.Equal(t, len(test.apiserverResponses), httpClient.RespCount)
   436  		})
   437  	}
   438  }