diff --git a/build/build-sdk-images/node/build-sdk-test.sh b/build/build-sdk-images/node/build-sdk-test.sh index 03dc09f346..102680224a 100644 --- a/build/build-sdk-images/node/build-sdk-test.sh +++ b/build/build-sdk-images/node/build-sdk-test.sh @@ -15,8 +15,8 @@ # limitations under the License. cd /go/src/agones.dev/agones/test/sdk/nodejs -npm install -npm rebuild +npm install --quiet +npm rebuild --quiet # If first 'npm install' attempt fails, which could occur for a variety of reasons, # do one more attempt @@ -27,6 +27,6 @@ then rm -rf /go/src/agones.dev/agones/test/sdk/nodejs/node_modules rm /go/src/agones.dev/agones/test/sdk/nodejs/package-lock.json npm cache clean - npm rebuild - npm install + npm rebuild --quiet + npm install --quiet fi diff --git a/build/build-sdk-images/restapi/Dockerfile b/build/build-sdk-images/restapi/Dockerfile index f82074a8a2..701aa2c416 100644 --- a/build/build-sdk-images/restapi/Dockerfile +++ b/build/build-sdk-images/restapi/Dockerfile @@ -26,10 +26,12 @@ ENV GOPATH /go RUN wget -q https://dl.google.com/go/go${GO_VERSION}.linux-amd64.tar.gz && \ tar -xzf go${GO_VERSION}.linux-amd64.tar.gz && rm go${GO_VERSION}.linux-amd64.tar.gz && mkdir -p ${GOPATH} +RUN echo 'ยง' && apt-get -qy update RUN curl -sL https://deb.nodesource.com/setup_12.x | bash - && \ - apt-get install -y nodejs + apt-get install -qq -y nodejs -RUN apt-get install -y openjdk-8-jre +#RUN apt-get install -qq -y openjdk-8-jre +RUN apt-get install -qq -y openjdk-8-jre > /dev/null ENV PATH /usr/local/go/bin:/go/bin:$PATH diff --git a/build/includes/sdk.mk b/build/includes/sdk.mk index ccacb30964..6a4efb552c 100644 --- a/build/includes/sdk.mk +++ b/build/includes/sdk.mk @@ -143,7 +143,7 @@ run-sdk-conformance-no-build: FEATURE_GATES ?= run-sdk-conformance-no-build: ensure-agones-sdk-image run-sdk-conformance-no-build: ensure-build-sdk-image DOCKER_RUN_ARGS="--net host -e AGONES_SDK_GRPC_PORT=$(GRPC_PORT) -e AGONES_SDK_HTTP_PORT=$(HTTP_PORT) -e FEATURE_GATES=$(FEATURE_GATES) $(DOCKER_RUN_ARGS)" COMMAND=sdktest $(MAKE) run-sdk-command & \ - docker run -p $(GRPC_PORT):$(GRPC_PORT) -p $(HTTP_PORT):$(HTTP_PORT) -e "FEATURE_GATES=$(FEATURE_GATES)" -e "ADDRESS=" -e "TEST=$(TESTS)" -e "TIMEOUT=$(TIMEOUT)" -e "DELAY=$(DELAY)" \ + docker run -p $(GRPC_PORT):$(GRPC_PORT) -p $(HTTP_PORT):$(HTTP_PORT) -e "FEATURE_GATES=$(FEATURE_GATES)" -e "ADDRESS=" -e "TEST=$(TESTS)" -e "SDK_NAME=$(SDK_FOLDER)" -e "TIMEOUT=$(TIMEOUT)" -e "DELAY=$(DELAY)" \ --net=host $(sidecar_tag) --grpc-port $(GRPC_PORT) --http-port $(HTTP_PORT) # Run SDK conformance test for a specific SDK_FOLDER diff --git a/cmd/sdk-server/main.go b/cmd/sdk-server/main.go index a482d4b920..5a4167fb03 100644 --- a/cmd/sdk-server/main.go +++ b/cmd/sdk-server/main.go @@ -51,14 +51,15 @@ const ( podNamespaceEnv = "POD_NAMESPACE" // Flags (that can also be env vars) - localFlag = "local" - fileFlag = "file" - testFlag = "test" - addressFlag = "address" - delayFlag = "delay" - timeoutFlag = "timeout" - grpcPortFlag = "grpc-port" - httpPortFlag = "http-port" + localFlag = "local" + fileFlag = "file" + testFlag = "test" + testSdkNameFlag = "sdk-name" + addressFlag = "address" + delayFlag = "delay" + timeoutFlag = "timeout" + grpcPortFlag = "grpc-port" + httpPortFlag = "http-port" ) var ( @@ -208,6 +209,7 @@ func registerTestSdkServer(grpcServer *grpc.Server, ctlConf config) (func(), err s.GenerateUID() expectedFuncs := strings.Split(ctlConf.Test, ",") s.SetExpectedSequence(expectedFuncs) + s.SetSdkName(ctlConf.TestSdkName) sdk.RegisterSDKServer(grpcServer, s) sdkalpha.RegisterSDKServer(grpcServer, s) @@ -258,6 +260,7 @@ func parseEnvFlags() config { viper.SetDefault(localFlag, false) viper.SetDefault(fileFlag, "") viper.SetDefault(testFlag, "") + viper.SetDefault(testSdkNameFlag, "") viper.SetDefault(addressFlag, "localhost") viper.SetDefault(delayFlag, 0) viper.SetDefault(timeoutFlag, 0) @@ -272,6 +275,7 @@ func parseEnvFlags() config { pflag.Int(delayFlag, viper.GetInt(delayFlag), "Time to delay (in seconds) before starting to execute main. Useful for tests") pflag.Int(timeoutFlag, viper.GetInt(timeoutFlag), "Time of execution (in seconds) before close. Useful for tests") pflag.String(testFlag, viper.GetString(testFlag), "List functions which should be called during the SDK Conformance test run.") + pflag.String(testSdkNameFlag, viper.GetString(testSdkNameFlag), "SDK name which is tested by this SDK Conformance test.") runtime.FeaturesBindFlags() pflag.Parse() @@ -279,6 +283,7 @@ func parseEnvFlags() config { runtime.Must(viper.BindEnv(localFlag)) runtime.Must(viper.BindEnv(addressFlag)) runtime.Must(viper.BindEnv(testFlag)) + runtime.Must(viper.BindEnv(testSdkNameFlag)) runtime.Must(viper.BindEnv(gameServerNameEnv)) runtime.Must(viper.BindEnv(podNamespaceEnv)) runtime.Must(viper.BindEnv(delayFlag)) @@ -291,25 +296,27 @@ func parseEnvFlags() config { runtime.Must(runtime.ParseFeaturesFromEnv()) return config{ - IsLocal: viper.GetBool(localFlag), - Address: viper.GetString(addressFlag), - LocalFile: viper.GetString(fileFlag), - Delay: viper.GetInt(delayFlag), - Timeout: viper.GetInt(timeoutFlag), - Test: viper.GetString(testFlag), - GRPCPort: viper.GetInt(grpcPortFlag), - HTTPPort: viper.GetInt(httpPortFlag), + IsLocal: viper.GetBool(localFlag), + Address: viper.GetString(addressFlag), + LocalFile: viper.GetString(fileFlag), + Delay: viper.GetInt(delayFlag), + Timeout: viper.GetInt(timeoutFlag), + Test: viper.GetString(testFlag), + TestSdkName: viper.GetString(testSdkNameFlag), + GRPCPort: viper.GetInt(grpcPortFlag), + HTTPPort: viper.GetInt(httpPortFlag), } } // config is all the configuration for this program type config struct { - Address string - IsLocal bool - LocalFile string - Delay int - Timeout int - Test string - GRPCPort int - HTTPPort int + Address string + IsLocal bool + LocalFile string + Delay int + Timeout int + Test string + TestSdkName string + GRPCPort int + HTTPPort int } diff --git a/cmd/sdk-server/main_test.go b/cmd/sdk-server/main_test.go new file mode 100644 index 0000000000..4a3d1418de --- /dev/null +++ b/cmd/sdk-server/main_test.go @@ -0,0 +1,38 @@ +// Copyright 2020 Google LLC All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" + "google.golang.org/grpc" +) + +// TestRegisterTestSdkServer - test to verify +func TestRegisterTestSdkServer(t *testing.T) { + t.Parallel() + ctlConf := parseEnvFlags() + grpcServer := grpc.NewServer() + _, err := registerTestSdkServer(grpcServer, ctlConf) + assert.NoError(t, err) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + ctx.Done() + ctlConf.LocalFile = "@@" + _, err = registerLocal(grpcServer, ctlConf) + assert.Error(t, err, "Wrong file name should produce an error") +} diff --git a/pkg/sdkserver/localsdk.go b/pkg/sdkserver/localsdk.go index 9c6a8f6304..71476e0a51 100644 --- a/pkg/sdkserver/localsdk.go +++ b/pkg/sdkserver/localsdk.go @@ -73,6 +73,7 @@ var ( type LocalSDKServer struct { gsMutex sync.RWMutex gs *sdk.GameServer + logger *logrus.Entry update chan struct{} updateObservers sync.Map testMutex sync.Mutex @@ -82,6 +83,7 @@ type LocalSDKServer struct { gsReserveDuration *time.Duration reserveTimer *time.Timer testMode bool + testSdkName string } // NewLocalSDKServer returns the default LocalSDKServer @@ -94,8 +96,10 @@ func NewLocalSDKServer(filePath string) (*LocalSDKServer, error) { testMutex: sync.Mutex{}, requestSequence: make([]string, 0), testMode: false, + testSdkName: "", gsState: agonesv1.GameServerStateScheduled, } + l.logger = runtime.NewLoggerWithType(l) if filePath != "" { err := l.setGameServerFromFilePath(filePath) @@ -113,26 +117,26 @@ func NewLocalSDKServer(filePath string) (*LocalSDKServer, error) { if event.Op != fsnotify.Write { continue } - logrus.WithField("event", event).Info("File has been changed!") + l.logger.WithField("event", event).Info("File has been changed!") err := l.setGameServerFromFilePath(filePath) if err != nil { - logrus.WithError(err).Error("error setting GameServer from file") + l.logger.WithError(err).Error("error setting GameServer from file") continue } - logrus.Info("Sending watched GameServer!") + l.logger.Info("Sending watched GameServer!") l.update <- struct{}{} } }() err = watcher.Add(filePath) if err != nil { - logrus.WithError(err).WithField("filePath", filePath).Error("error adding watcher") + l.logger.WithError(err).WithField("filePath", filePath).Error("error adding watcher") } } go func() { for value := range l.update { - logrus.Info("Gameserver update received") + l.logger.Info("Gameserver update received") l.updateObservers.Range(func(observer, _ interface{}) bool { observer.(chan struct{}) <- value return true @@ -163,6 +167,12 @@ func (l *LocalSDKServer) SetExpectedSequence(sequence []string) { l.expectedSequence = sequence } +// SetSdkName set SDK name to be added to the logs +func (l *LocalSDKServer) SetSdkName(sdkName string) { + l.testSdkName = sdkName + l.logger = l.logger.WithField("sdkName", l.testSdkName) +} + // recordRequest append request name to slice func (l *LocalSDKServer) recordRequest(request string) { if l.testMode { @@ -170,6 +180,9 @@ func (l *LocalSDKServer) recordRequest(request string) { defer l.testMutex.Unlock() l.requestSequence = append(l.requestSequence, request) } + if l.testSdkName != "" { + l.logger.Debugf("Received %s request", request) + } } // recordRequestWithValue append request name to slice only if @@ -185,7 +198,7 @@ func (l *LocalSDKServer) recordRequestWithValue(request string, value string, ob case "PlayerCapacity": fieldVal = strconv.FormatInt(l.gs.Status.Players.Capacity, 10) default: - fmt.Printf("Error: Unexpected Field to compare") + l.logger.Error("unexpected Field to compare") } if value == fieldVal { @@ -193,7 +206,7 @@ func (l *LocalSDKServer) recordRequestWithValue(request string, value string, ob defer l.testMutex.Unlock() l.requestSequence = append(l.requestSequence, request) } else { - fmt.Printf("Error: we expected to receive '%s' as value for '%s' request but received '%s'. \n", fieldVal, request, value) + l.logger.Errorf("expected to receive '%s' as value for '%s' request but received '%s'", fieldVal, request, value) } } } @@ -205,7 +218,7 @@ func (l *LocalSDKServer) updateState(newState agonesv1.GameServerState) { // Ready logs that the Ready request has been received func (l *LocalSDKServer) Ready(context.Context, *sdk.Empty) (*sdk.Empty, error) { - logrus.Info("Ready request has been received!") + l.logger.Info("Ready request has been received!") l.recordRequest("ready") l.gsMutex.Lock() defer l.gsMutex.Unlock() @@ -219,7 +232,7 @@ func (l *LocalSDKServer) Ready(context.Context, *sdk.Empty) (*sdk.Empty, error) // Allocate logs that an allocate request has been received func (l *LocalSDKServer) Allocate(context.Context, *sdk.Empty) (*sdk.Empty, error) { - logrus.Info("Allocate request has been received!") + l.logger.Info("Allocate request has been received!") l.recordRequest("allocate") l.gsMutex.Lock() defer l.gsMutex.Unlock() @@ -232,7 +245,7 @@ func (l *LocalSDKServer) Allocate(context.Context, *sdk.Empty) (*sdk.Empty, erro // Shutdown logs that the shutdown request has been received func (l *LocalSDKServer) Shutdown(context.Context, *sdk.Empty) (*sdk.Empty, error) { - logrus.Info("Shutdown request has been received!") + l.logger.Info("Shutdown request has been received!") l.recordRequest("shutdown") l.gsMutex.Lock() defer l.gsMutex.Unlock() @@ -247,20 +260,20 @@ func (l *LocalSDKServer) Health(stream sdk.SDK_HealthServer) error { for { _, err := stream.Recv() if err == io.EOF { - logrus.Info("Health stream closed.") + l.logger.Info("Health stream closed.") return stream.SendAndClose(&sdk.Empty{}) } if err != nil { return errors.Wrap(err, "Error with Health check") } l.recordRequest("health") - logrus.Info("Health Ping Received!") + l.logger.Info("Health Ping Received!") } } // SetLabel applies a Label to the backing GameServer metadata func (l *LocalSDKServer) SetLabel(_ context.Context, kv *sdk.KeyValue) (*sdk.Empty, error) { - logrus.WithField("values", kv).Info("Setting label") + l.logger.WithField("values", kv).Info("Setting label") l.gsMutex.Lock() defer l.gsMutex.Unlock() @@ -279,7 +292,7 @@ func (l *LocalSDKServer) SetLabel(_ context.Context, kv *sdk.KeyValue) (*sdk.Emp // SetAnnotation applies a Annotation to the backing GameServer metadata func (l *LocalSDKServer) SetAnnotation(_ context.Context, kv *sdk.KeyValue) (*sdk.Empty, error) { - logrus.WithField("values", kv).Info("Setting annotation") + l.logger.WithField("values", kv).Info("Setting annotation") l.gsMutex.Lock() defer l.gsMutex.Unlock() @@ -298,7 +311,7 @@ func (l *LocalSDKServer) SetAnnotation(_ context.Context, kv *sdk.KeyValue) (*sd // GetGameServer returns current GameServer configuration. func (l *LocalSDKServer) GetGameServer(context.Context, *sdk.Empty) (*sdk.GameServer, error) { - logrus.Info("Getting GameServer details") + l.logger.Info("Getting GameServer details") l.recordRequest("gameserver") l.gsMutex.RLock() defer l.gsMutex.RUnlock() @@ -307,7 +320,7 @@ func (l *LocalSDKServer) GetGameServer(context.Context, *sdk.Empty) (*sdk.GameSe // WatchGameServer will return current GameServer configuration, 3 times, every 5 seconds func (l *LocalSDKServer) WatchGameServer(_ *sdk.Empty, stream sdk.SDK_WatchGameServerServer) error { - logrus.Info("Connected to watch GameServer...") + l.logger.Info("Connected to watch GameServer...") observer := make(chan struct{}) defer func() { @@ -322,7 +335,7 @@ func (l *LocalSDKServer) WatchGameServer(_ *sdk.Empty, stream sdk.SDK_WatchGameS err := stream.Send(l.gs) l.gsMutex.RUnlock() if err != nil { - logrus.WithError(err).Error("error sending gameserver") + l.logger.WithError(err).Error("error sending gameserver") return err } } @@ -332,7 +345,7 @@ func (l *LocalSDKServer) WatchGameServer(_ *sdk.Empty, stream sdk.SDK_WatchGameS // Reserve moves this GameServer to the Reserved state for the Duration specified func (l *LocalSDKServer) Reserve(ctx context.Context, d *sdk.Duration) (*sdk.Empty, error) { - logrus.WithField("duration", d).Info("Reserve request has been received!") + l.logger.WithField("duration", d).Info("Reserve request has been received!") l.recordRequest("reserve") l.gsMutex.Lock() defer l.gsMutex.Unlock() @@ -355,7 +368,7 @@ func (l *LocalSDKServer) resetReserveAfter(ctx context.Context, duration time.Du l.reserveTimer = time.AfterFunc(duration, func() { if _, err := l.Ready(ctx, &sdk.Empty{}); err != nil { - logrus.WithError(err).Error("error returning to Ready after reserved ") + l.logger.WithError(err).Error("error returning to Ready after reserved ") } }) } @@ -389,7 +402,7 @@ func (l *LocalSDKServer) SetPlayerCapacity(_ context.Context, count *alpha.Count return nil, errors.New(string(runtime.FeaturePlayerTracking) + " not enabled") } - logrus.WithField("capacity", count.Count).Info("Setting Player Capacity") + l.logger.WithField("capacity", count.Count).Info("Setting Player Capacity") l.gsMutex.Lock() defer l.gsMutex.Unlock() @@ -411,7 +424,7 @@ func (l *LocalSDKServer) GetPlayerCapacity(_ context.Context, _ *alpha.Empty) (* if !runtime.FeatureEnabled(runtime.FeaturePlayerTracking) { return nil, errors.New(string(runtime.FeaturePlayerTracking) + " not enabled") } - logrus.Info("Getting Player Capacity") + l.logger.Info("Getting Player Capacity") l.recordRequest("getplayercapacity") l.gsMutex.RLock() defer l.gsMutex.RUnlock() @@ -443,42 +456,44 @@ func (l *LocalSDKServer) Close() { l.compare() } -// EqualSets tells whether a and b contain the same elements. +// EqualSets tells whether expected and received slices contain the same elements. // A nil argument is equivalent to an empty slice. -func EqualSets(a, b []string) bool { +func (l *LocalSDKServer) EqualSets(expected, received []string) bool { aSet := make(map[string]bool) bSet := make(map[string]bool) - for _, v := range a { + for _, v := range expected { aSet[v] = true } - for _, v := range b { + for _, v := range received { if _, ok := aSet[v]; !ok { + l.logger.WithField("request", v).Error("Found a request which was not expected") return false } bSet[v] = true } - for _, v := range a { + for _, v := range expected { if _, ok := bSet[v]; !ok { + l.logger.WithField("request", v).Error("Could not find a request which was expected") return false } } return true } -// Close tears down all the things +// compare the results of a test run func (l *LocalSDKServer) compare() { - logrus.Info("Compare") - if l.testMode { - if !EqualSets(l.expectedSequence, l.requestSequence) { - logrus.Info(fmt.Sprintf("Testing Failed %v %v", l.expectedSequence, l.requestSequence)) + if !l.EqualSets(l.expectedSequence, l.requestSequence) { + l.logger.Errorf("Testing Failed %v %v", l.expectedSequence, l.requestSequence) os.Exit(1) + } else { + l.logger.Info("Received requests match expected list. Test run was successful") } } } func (l *LocalSDKServer) setGameServerFromFilePath(filePath string) error { - logrus.WithField("filePath", filePath).Info("Reading GameServer configuration") + l.logger.WithField("filePath", filePath).Info("Reading GameServer configuration") reader, err := os.Open(filePath) // nolint: gosec defer reader.Close() // nolint: megacheck,errcheck diff --git a/pkg/sdkserver/localsdk_test.go b/pkg/sdkserver/localsdk_test.go index ba4b32a83f..b802926b16 100644 --- a/pkg/sdkserver/localsdk_test.go +++ b/pkg/sdkserver/localsdk_test.go @@ -67,19 +67,21 @@ func TestLocal(t *testing.T) { } func TestLocalSDKWithTestMode(t *testing.T) { + l, err := NewLocalSDKServer("") + assert.NoError(t, err, "Should be able to create local SDK server") a := []string{"ready", "allocate", "setlabel", "setannotation", "gameserver", "health", "shutdown", "watch"} b := []string{"ready", "health", "ready", "watch", "allocate", "gameserver", "setlabel", "setannotation", "health", "health", "shutdown"} - assert.True(t, EqualSets(a, a)) - assert.True(t, EqualSets(a, b)) - assert.True(t, EqualSets(b, a)) - assert.True(t, EqualSets(b, b)) + assert.True(t, l.EqualSets(a, a)) + assert.True(t, l.EqualSets(a, b)) + assert.True(t, l.EqualSets(b, a)) + assert.True(t, l.EqualSets(b, b)) a[0] = "rady" - assert.False(t, EqualSets(a, b)) - assert.False(t, EqualSets(b, a)) + assert.False(t, l.EqualSets(a, b)) + assert.False(t, l.EqualSets(b, a)) a[0] = "ready" b[1] = "halth" - assert.False(t, EqualSets(a, b)) - assert.False(t, EqualSets(b, a)) + assert.False(t, l.EqualSets(a, b)) + assert.False(t, l.EqualSets(b, a)) } func TestLocalSDKWithGameServer(t *testing.T) { @@ -414,6 +416,6 @@ func TestSDKConformanceFunctionality(t *testing.T) { wg.Wait() l.SetExpectedSequence(expected) - b := EqualSets(l.expectedSequence, l.requestSequence) + b := l.EqualSets(l.expectedSequence, l.requestSequence) assert.True(t, b, "we should receive strings from all go routines %v %v", l.expectedSequence, l.requestSequence) }