github.com/kubewharf/katalyst-core@v0.5.3/pkg/agent/resourcemanager/fetcher/plugin/endpoint_test.go (about)

     1  /*
     2  Copyright 2022 The Katalyst Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package plugin
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"path"
    23  	"testing"
    24  
    25  	"github.com/stretchr/testify/require"
    26  	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  
    28  	"github.com/kubewharf/katalyst-api/pkg/plugins/skeleton"
    29  	"github.com/kubewharf/katalyst-api/pkg/protocol/reporterplugin/v1alpha1"
    30  	"github.com/kubewharf/katalyst-core/pkg/metrics"
    31  )
    32  
    33  var testGroupVersionKind = v1.GroupVersionKind{
    34  	Group:   "test-group",
    35  	Kind:    "test-kind",
    36  	Version: "test-version",
    37  }
    38  
    39  func TestNewEndpoint(t *testing.T) {
    40  	t.Parallel()
    41  
    42  	socketDir := path.Join("/tmp/TestNewEndpoint")
    43  
    44  	content := []*v1alpha1.ReportContent{
    45  		{
    46  			GroupVersionKind: &testGroupVersionKind,
    47  			Field:            []*v1alpha1.ReportField{},
    48  		},
    49  	}
    50  
    51  	_, gp, e := esetup(t, content, socketDir, "mock", func(n string, d *v1alpha1.GetReportContentResponse) {})
    52  	defer ecleanup(t, gp, e)
    53  }
    54  
    55  func TestRun(t *testing.T) {
    56  	t.Parallel()
    57  	socket := path.Join("/tmp/TestRun")
    58  
    59  	content := []*v1alpha1.ReportContent{
    60  		{
    61  			GroupVersionKind: &testGroupVersionKind,
    62  			Field: []*v1alpha1.ReportField{
    63  				{
    64  					FieldType: v1alpha1.FieldType_Spec,
    65  					FieldName: "fieldName_a",
    66  					Value:     []byte("Value_a"),
    67  				},
    68  			},
    69  		},
    70  		{
    71  			GroupVersionKind: &testGroupVersionKind,
    72  			Field: []*v1alpha1.ReportField{
    73  				{
    74  					FieldType: v1alpha1.FieldType_Status,
    75  					FieldName: "fieldName_b",
    76  					Value:     []byte("Value_b"),
    77  				},
    78  			},
    79  		},
    80  	}
    81  
    82  	updated := []*v1alpha1.ReportContent{
    83  		{
    84  			GroupVersionKind: &testGroupVersionKind,
    85  			Field: []*v1alpha1.ReportField{
    86  				{
    87  					FieldType: v1alpha1.FieldType_Spec,
    88  					FieldName: "fieldName_a",
    89  					Value:     []byte("Value_a_1"),
    90  				},
    91  			},
    92  		},
    93  		{
    94  			GroupVersionKind: &testGroupVersionKind,
    95  			Field: []*v1alpha1.ReportField{
    96  				{
    97  					FieldType: v1alpha1.FieldType_Status,
    98  					FieldName: "fieldName_b",
    99  					Value:     []byte("Value_b_1"),
   100  				},
   101  			},
   102  		},
   103  	}
   104  
   105  	callbackCount := 0
   106  	callbackChan := make(chan int)
   107  	callback := func(n string, response *v1alpha1.GetReportContentResponse) {
   108  		// Should be called twice:
   109  		// one for plugin registration, one for plugin update.
   110  		if callbackCount > 2 {
   111  			t.FailNow()
   112  		}
   113  
   114  		// Check plugin registration
   115  		if callbackCount == 0 {
   116  			require.Len(t, response.Content, 2)
   117  			reporterContentsEqual(t, response.Content, content)
   118  		}
   119  
   120  		// Check plugin update
   121  		if callbackCount == 1 {
   122  			require.Len(t, response.Content, 2)
   123  			reporterContentsEqual(t, response.Content, updated)
   124  		}
   125  
   126  		callbackCount++
   127  		callbackChan <- callbackCount
   128  	}
   129  
   130  	p, gp, e := esetup(t, content, socket, "mock", callback)
   131  	defer ecleanup(t, gp, e)
   132  
   133  	success := make(chan bool)
   134  	go e.Run(success)
   135  	<-success
   136  	// Wait for the first callback to be issued.
   137  	<-callbackChan
   138  
   139  	p.Update(updated)
   140  
   141  	// Wait for the second callback to be issued.
   142  	<-callbackChan
   143  
   144  	require.Equal(t, callbackCount, 2)
   145  }
   146  
   147  func TestGetReportContent(t *testing.T) {
   148  	t.Parallel()
   149  
   150  	socket := path.Join("/tmp/TestGetReportContent")
   151  
   152  	content := []*v1alpha1.ReportContent{
   153  		{
   154  			GroupVersionKind: &testGroupVersionKind,
   155  			Field: []*v1alpha1.ReportField{
   156  				{
   157  					FieldType: v1alpha1.FieldType_Spec,
   158  					FieldName: "fieldName_a",
   159  					Value:     []byte("Value_a"),
   160  				},
   161  			},
   162  		},
   163  		{
   164  			GroupVersionKind: &testGroupVersionKind,
   165  			Field: []*v1alpha1.ReportField{
   166  				{
   167  					FieldType: v1alpha1.FieldType_Status,
   168  					FieldName: "fieldName_b",
   169  					Value:     []byte("Value_b"),
   170  				},
   171  			},
   172  		},
   173  	}
   174  
   175  	callbackCount := 0
   176  	callbackChan := make(chan int)
   177  	_, gp, e := esetup(t, content, socket, "mock", func(n string, response *v1alpha1.GetReportContentResponse) {
   178  		callbackCount++
   179  		callbackChan <- callbackCount
   180  	})
   181  	defer ecleanup(t, gp, e)
   182  
   183  	respOut, err := e.GetReportContent(context.TODO())
   184  	require.NoError(t, err)
   185  	require.NotNil(t, respOut)
   186  	reporterContentsEqual(t, respOut.Content, content)
   187  }
   188  
   189  func esetup(t *testing.T, content []*v1alpha1.ReportContent, socket, pluginName string, callback ListAndWatchCallback) (*skeleton.ReporterPluginStub, skeleton.GenericPlugin, Endpoint) {
   190  	ps := skeleton.NewReporterPluginStub(content, pluginName)
   191  	p, _ := skeleton.NewRegistrationPluginWrapper(ps, []string{socket}, nil)
   192  	err := p.Start()
   193  	require.NoError(t, err)
   194  
   195  	e, err := NewRemoteEndpoint(path.Join(socket, fmt.Sprintf("%s.sock", p.Name())), pluginName, nil, metrics.DummyMetrics{}, callback)
   196  	require.NoError(t, err)
   197  
   198  	return ps, p, e
   199  }
   200  
   201  func ecleanup(t *testing.T, p skeleton.GenericPlugin, e Endpoint) {
   202  	err := p.Stop()
   203  	require.NoError(t, err)
   204  	e.Stop()
   205  }
   206  
   207  func reporterContentsEqual(t *testing.T, expected, actual []*v1alpha1.ReportContent) {
   208  	require.Equal(t, len(expected), len(actual))
   209  	for idx := range expected {
   210  		require.Equal(t, expected[idx].GroupVersionKind, actual[idx].GroupVersionKind)
   211  		require.Equal(t, len(expected[idx].Field), len(actual[idx].Field))
   212  		for fieldIdx := range expected[idx].Field {
   213  			require.Equal(t, expected[idx].Field[fieldIdx].FieldType, actual[idx].Field[fieldIdx].FieldType)
   214  			require.Equal(t, expected[idx].Field[fieldIdx].FieldName, actual[idx].Field[fieldIdx].FieldName)
   215  			require.Equal(t, expected[idx].Field[fieldIdx].Value, actual[idx].Field[fieldIdx].Value)
   216  		}
   217  	}
   218  }