agones.dev/agones@v1.53.0/sdks/nodejs/spec/agonesSDK.spec.js (about)

     1  // Copyright 2019 Google LLC All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  const stream = require('stream');
    16  
    17  const grpc = require('@grpc/grpc-js');
    18  
    19  const messages = require('../lib/sdk_pb');
    20  
    21  const AgonesSDK = require('../src/agonesSDK');
    22  const Alpha = require('../src/alpha');
    23  
    24  describe('AgonesSDK', () => {
    25  	let agonesSDK;
    26  
    27  	beforeEach(() => {
    28  		agonesSDK = new AgonesSDK();
    29  	});
    30  
    31  	describe('port', () => {
    32  		it('returns the default port if $AGONES_SDK_GRPC_PORT is not defined', async () => {
    33  			let port = agonesSDK.port;
    34  			expect(port).toEqual('9357');
    35  		});
    36  
    37  		it('returns a valid port set in $AGONES_SDK_GRPC_PORT', async () => {
    38  			process.env.AGONES_SDK_GRPC_PORT = '6789';
    39  			let port = agonesSDK.port;
    40  			expect(port).toEqual('6789');
    41  			delete process.env.AGONES_SDK_GRPC_PORT;
    42  		});
    43  
    44  		it('returns an invalid port set in $AGONES_SDK_GRPC_PORT', async () => {
    45  			process.env.AGONES_SDK_GRPC_PORT = 'foo';
    46  			let port = agonesSDK.port;
    47  			expect(port).toEqual('foo');
    48  			delete process.env.AGONES_SDK_GRPC_PORT;
    49  		});
    50  	});
    51  
    52  	describe('connect', () => {
    53  		it('calls the server and handles success', async () => {
    54  			spyOn(agonesSDK.client, 'waitForReady').and.callFake((deadline, callback) => {
    55  				let result = new messages.Empty();
    56  				callback(undefined, result);
    57  			});
    58  			let result = await agonesSDK.connect();
    59  			expect(agonesSDK.client.waitForReady).toHaveBeenCalled();
    60  			expect(result).toEqual(undefined);
    61  		});
    62  
    63  		it('calls the server and handles failure', async () => {
    64  			spyOn(agonesSDK.client, 'waitForReady').and.callFake((deadline, callback) => {
    65  				callback('error', undefined);
    66  			});
    67  			try {
    68  				await agonesSDK.connect();
    69  				fail();
    70  			} catch (error) {
    71  				expect(agonesSDK.client.waitForReady).toHaveBeenCalled();
    72  				expect(error).toEqual('error');
    73  			}
    74  		});
    75  	});
    76  
    77  	describe('ready', () => {
    78  		it('calls the server and handles success', async () => {
    79  			spyOn(agonesSDK.client, 'ready').and.callFake((request, callback) => {
    80  				let result = new messages.Empty();
    81  				callback(undefined, result);
    82  			});
    83  			let result = await agonesSDK.ready();
    84  			expect(agonesSDK.client.ready).toHaveBeenCalled();
    85  			expect(result).toEqual({});
    86  		});
    87  
    88  		it('calls the server and handles failure', async () => {
    89  			spyOn(agonesSDK.client, 'ready').and.callFake((request, callback) => {
    90  				callback('error', undefined);
    91  			});
    92  			try {
    93  				await agonesSDK.ready();
    94  				fail();
    95  			} catch (error) {
    96  				expect(agonesSDK.client.ready).toHaveBeenCalled();
    97  				expect(error).toEqual('error');
    98  			}
    99  		});
   100  	});
   101  
   102  	describe('allocate', () => {
   103  		it('calls the server and handles success', async () => {
   104  			spyOn(agonesSDK.client, 'allocate').and.callFake((request, callback) => {
   105  				let result = new messages.Empty();
   106  				callback(undefined, result);
   107  			});
   108  			let result = await agonesSDK.allocate();
   109  			expect(agonesSDK.client.allocate).toHaveBeenCalled();
   110  			expect(result).toEqual({});
   111  		});
   112  
   113  		it('calls the server and handles failure', async () => {
   114  			spyOn(agonesSDK.client, 'allocate').and.callFake((request, callback) => {
   115  				callback('error', undefined);
   116  			});
   117  			try {
   118  				await agonesSDK.allocate();
   119  				fail();
   120  			} catch (error) {
   121  				expect(agonesSDK.client.allocate).toHaveBeenCalled();
   122  				expect(error).toEqual('error');
   123  			}
   124  		});
   125  	});
   126  
   127  	describe('shutdown', () => {
   128  		it('calls the server and handles success', async () => {
   129  			spyOn(agonesSDK.client, 'shutdown').and.callFake((request, callback) => {
   130  				let result = new messages.Empty();
   131  				callback(undefined, result);
   132  			});
   133  
   134  			let result = await agonesSDK.shutdown();
   135  			expect(agonesSDK.client.shutdown).toHaveBeenCalled();
   136  			expect(result).toEqual({});
   137  		});
   138  
   139  		it('calls the server and handles failure', async () => {
   140  			spyOn(agonesSDK.client, 'shutdown').and.callFake((request, callback) => {
   141  				callback('error', undefined);
   142  			});
   143  			try {
   144  				await agonesSDK.shutdown();
   145  				fail();
   146  			} catch (error) {
   147  				expect(agonesSDK.client.shutdown).toHaveBeenCalled();
   148  				expect(error).toEqual('error');
   149  			}
   150  		});
   151  	});
   152  
   153  	describe('health', () => {
   154  		it('calls the server and passes calls to stream', async () => {
   155  			let stream = jasmine.createSpyObj('stream', ['write', 'on']);
   156  			spyOn(agonesSDK.client, 'health').and.callFake(() => {
   157  				return stream;
   158  			});
   159  
   160  			agonesSDK.health();
   161  			expect(agonesSDK.client.health).toHaveBeenCalled();
   162  			expect(stream.write).toHaveBeenCalled();
   163  		});
   164  
   165  		it('uses the same stream for subsequent calls', async () => {
   166  			let stream = jasmine.createSpyObj('stream', ['write', 'on']);
   167  			spyOn(agonesSDK.client, 'health').and.callFake(() => {
   168  				return stream;
   169  			});
   170  
   171  			agonesSDK.health();
   172  			agonesSDK.health();
   173  			expect(agonesSDK.client.health.calls.count()).toEqual(1);
   174  			expect(stream.write.calls.count()).toEqual(2);
   175  		});
   176  
   177  		it('calls the server and silently handles the internal error message', async () => {
   178  			spyOn(agonesSDK.client, 'health').and.callFake((callback) => {
   179  				callback('error', undefined);
   180  			});
   181  			try {
   182  				agonesSDK.health();
   183  				fail();
   184  			} catch (error) {
   185  				expect(agonesSDK.client.health).toHaveBeenCalled();
   186  				expect(error).not.toEqual('error');
   187  			}
   188  		});
   189  
   190  		it('calls the server and handles stream write error if callback provided', async () => {
   191  			let stream = jasmine.createSpyObj('stream', ['write', 'on']);
   192  			stream.write.and.callFake((chunk, encoding, callback) => {
   193  				callback('error');
   194  			});
   195  			spyOn(agonesSDK.client, 'health').and.callFake(() => {
   196  				return stream;
   197  			});
   198  			try {
   199  				agonesSDK.health((error) => {
   200  					expect(error).toEqual('error');
   201  				});
   202  			} catch (error) {
   203  				fail();
   204  			}
   205  		});
   206  
   207  		it('calls the server and re throws stream write error if no callback', async () => {
   208  			let stream = jasmine.createSpyObj('stream', ['write', 'on']);
   209  			stream.write.and.callFake((chunk, encoding, callback) => {
   210  				callback('error');
   211  			});
   212  			spyOn(agonesSDK.client, 'health').and.callFake(() => {
   213  				return stream;
   214  			});
   215  			try {
   216  				agonesSDK.health();
   217  				fail();
   218  			} catch (error) {
   219  				expect(agonesSDK.client.health).toHaveBeenCalled();
   220  				expect(error).toEqual('error');
   221  			}
   222  		});
   223  
   224  		it('does not call error callback if there was no stream error', async () => {
   225  			let stream = jasmine.createSpyObj('stream', ['write', 'on']);
   226  			stream.write.and.callFake((chunk, encoding, callback) => {
   227  				callback();
   228  			});
   229  			spyOn(agonesSDK.client, 'health').and.callFake(() => {
   230  				return stream;
   231  			});
   232  			agonesSDK.health(() => {
   233  				fail();
   234  			});
   235  		});
   236  
   237  		it('calls the server and handles stream completing', async () => {
   238  			let stream = jasmine.createSpyObj('stream', ['write', 'on']);
   239  			spyOn(agonesSDK.client, 'health').and.callFake((callback) => {
   240  				let result = new messages.Empty();
   241  				callback(undefined, result);
   242  				return stream;
   243  			});
   244  
   245  			agonesSDK.health();
   246  			expect(agonesSDK.client.health).toHaveBeenCalled();
   247  		});
   248  	});
   249  
   250  	describe('getGameServer', () => {
   251  		it('calls the server and handles the response', async () => {
   252  			spyOn(agonesSDK.client, 'getGameServer').and.callFake((request, callback) => {
   253  				let status = new messages.GameServer.Status();
   254  				status.setState('up');
   255  				let gameServer = new messages.GameServer();
   256  				gameServer.setStatus(status);
   257  				callback(undefined, gameServer);
   258  			});
   259  
   260  			let gameServer = await agonesSDK.getGameServer();
   261  			expect(agonesSDK.client.getGameServer).toHaveBeenCalled();
   262  			expect(gameServer).toBeDefined();
   263  			expect(gameServer.status).toBeDefined();
   264  			expect(gameServer.status.state).toEqual('up');
   265  		});
   266  
   267  		it('calls the server and handles failure', async () => {
   268  			spyOn(agonesSDK.client, 'getGameServer').and.callFake((request, callback) => {
   269  				callback('error', undefined);
   270  			});
   271  			try {
   272  				await agonesSDK.getGameServer();
   273  				fail();
   274  			} catch (error) {
   275  				expect(agonesSDK.client.getGameServer).toHaveBeenCalled();
   276  				expect(error).toEqual('error');
   277  			}
   278  		});
   279  	});
   280  
   281  	describe('watchGameServer', () => {
   282  		it('calls the server and passes events to the callback', async () => {
   283  			let serverStream = stream.Readable({read: () => undefined});
   284  			spyOn(agonesSDK.client, 'watchGameServer').and.callFake(() => {
   285  				return serverStream;
   286  			});
   287  
   288  			let callback = jasmine.createSpy('callback');
   289  			agonesSDK.watchGameServer(callback);
   290  			expect(agonesSDK.client.watchGameServer).toHaveBeenCalled();
   291  
   292  			let status = new messages.GameServer.Status();
   293  			status.setState('up');
   294  			let gameServer = new messages.GameServer();
   295  			gameServer.setStatus(status);
   296  			serverStream.emit('data', gameServer);
   297  
   298  			expect(callback).toHaveBeenCalled();
   299  			let callbackArgs = callback.calls.argsFor(0)[0];
   300  			expect(callbackArgs.status).toBeDefined();
   301  			expect(callbackArgs.status.state).toEqual('up');
   302  		});
   303  		it('calls the server and passes errors to the optional error callback', async () => {
   304  			let serverStream = stream.Readable({read: () => undefined});
   305  			spyOn(agonesSDK.client, 'watchGameServer').and.callFake(() => {
   306  				return serverStream;
   307  			});
   308  
   309  			let callback = jasmine.createSpy('callback');
   310  			let errorCallback = jasmine.createSpy('errorCallback');
   311  			agonesSDK.watchGameServer(callback, errorCallback);
   312  
   313  			let error = {
   314  				code: grpc.status.CANCELLED
   315  			};
   316  			serverStream.emit('error', error);
   317  			expect(errorCallback).toHaveBeenCalled();
   318  			let errorCallbackArgs = errorCallback.calls.argsFor(0)[0];
   319  			expect(errorCallbackArgs).toEqual(error);
   320  		});
   321  	});
   322  
   323  	describe('setLabel', () => {
   324  		it('calls the server and handles success', async () => {
   325  			spyOn(agonesSDK.client, 'setLabel').and.callFake((request, callback) => {
   326  				let result = new messages.Empty();
   327  				callback(undefined, result);
   328  			});
   329  
   330  			let result = await agonesSDK.setLabel('key', 'value');
   331  			expect(agonesSDK.client.setLabel).toHaveBeenCalled();
   332  			expect(result).toEqual({});
   333  		});
   334  
   335  		it('passes arguments to the server', async () => {
   336  			spyOn(agonesSDK.client, 'setLabel').and.callFake((request, callback) => {
   337  				let result = new messages.Empty();
   338  				callback(undefined, result);
   339  			});
   340  
   341  			await agonesSDK.setLabel('key', 'value');
   342  			expect(agonesSDK.client.setLabel).toHaveBeenCalled();
   343  			let request = agonesSDK.client.setLabel.calls.argsFor(0)[0];
   344  			expect(request.getKey()).toEqual('key');
   345  			expect(request.getValue()).toEqual('value');
   346  		});
   347  
   348  		it('calls the server and handles failure', async () => {
   349  			spyOn(agonesSDK.client, 'setLabel').and.callFake((request, callback) => {
   350  				callback('error', undefined);
   351  			});
   352  			try {
   353  				await agonesSDK.setLabel('key', 'value');
   354  				fail();
   355  			} catch (error) {
   356  				expect(agonesSDK.client.setLabel).toHaveBeenCalled();
   357  				expect(error).toEqual('error');
   358  			}
   359  		});
   360  	});
   361  
   362  	describe('setAnnotation', () => {
   363  		it('calls the server and handles success', async () => {
   364  			spyOn(agonesSDK.client, 'setAnnotation').and.callFake((request, callback) => {
   365  				let result = new messages.Empty();
   366  				callback(undefined, result);
   367  			});
   368  
   369  			let result = await agonesSDK.setAnnotation('key', 'value');
   370  			expect(agonesSDK.client.setAnnotation).toHaveBeenCalled();
   371  			expect(result).toEqual({});
   372  		});
   373  
   374  		it('passes arguments to the server', async () => {
   375  			spyOn(agonesSDK.client, 'setAnnotation').and.callFake((request, callback) => {
   376  				let result = new messages.Empty();
   377  				callback(undefined, result);
   378  			});
   379  
   380  			await agonesSDK.setAnnotation('key', 'value');
   381  			expect(agonesSDK.client.setAnnotation).toHaveBeenCalled();
   382  			let request = agonesSDK.client.setAnnotation.calls.argsFor(0)[0];
   383  			expect(request.getKey()).toEqual('key');
   384  			expect(request.getValue()).toEqual('value');
   385  		});
   386  
   387  		it('calls the server and handles failure', async () => {
   388  			spyOn(agonesSDK.client, 'setAnnotation').and.callFake((request, callback) => {
   389  				callback('error', undefined);
   390  			});
   391  			try {
   392  				await agonesSDK.setAnnotation('key', 'value');
   393  				fail();
   394  			} catch (error) {
   395  				expect(agonesSDK.client.setAnnotation).toHaveBeenCalled();
   396  				expect(error).toEqual('error');
   397  			}
   398  		});
   399  	});
   400  
   401  	describe('close', () => {
   402  		it('closes the client connection when called', async () => {
   403  			spyOn(agonesSDK.client, 'close');
   404  			await agonesSDK.close();
   405  			expect(agonesSDK.client.close).toHaveBeenCalled();
   406  		});
   407  		it('ends the health stream if set', async () => {
   408  			let stream = jasmine.createSpyObj('stream', ['end', 'write', 'on']);
   409  			spyOn(agonesSDK.client, 'health').and.callFake(() => {
   410  				return stream;
   411  			});
   412  			agonesSDK.health();
   413  			spyOn(agonesSDK.client, 'close').and.callFake(() => {});
   414  			await agonesSDK.close();
   415  			expect(stream.end).toHaveBeenCalled();
   416  		});
   417  		it('cancels any watchers', async () => {
   418  			let serverStream = stream.Readable({read: () => undefined});
   419  			spyOn(serverStream, 'destroy').and.callThrough();
   420  			spyOn(agonesSDK.client, 'watchGameServer').and.callFake(() => {
   421  				return serverStream;
   422  			});
   423  
   424  			let callback = jasmine.createSpy('callback');
   425  			agonesSDK.watchGameServer(callback);
   426  
   427  			spyOn(agonesSDK.client, 'close');
   428  			await agonesSDK.close();
   429  			expect(serverStream.destroy).toHaveBeenCalled();
   430  		});
   431  	});
   432  
   433  	describe('reserve', () => {
   434  		it('calls the server with duration parameter and handles success', async () => {
   435  			spyOn(agonesSDK.client, 'reserve').and.callFake((request, callback) => {
   436  				let result = new messages.Empty();
   437  				callback(undefined, result);
   438  			});
   439  
   440  			let result = await agonesSDK.reserve(10);
   441  			expect(agonesSDK.client.reserve).toHaveBeenCalled();
   442  			expect(result).toEqual({});
   443  
   444  			let request = agonesSDK.client.reserve.calls.argsFor(0)[0];
   445  			expect(request.getSeconds()).toEqual(10);
   446  		});
   447  
   448  		it('calls the server and handles failure', async () => {
   449  			spyOn(agonesSDK.client, 'reserve').and.callFake((request, callback) => {
   450  				callback('error', undefined);
   451  			});
   452  			try {
   453  				await agonesSDK.reserve(10);
   454  				fail();
   455  			} catch (error) {
   456  				expect(agonesSDK.client.reserve).toHaveBeenCalled();
   457  				expect(error).toEqual('error');
   458  			}
   459  		});
   460  	});
   461  
   462  	describe('alpha', () => {
   463  		it('returns the alpha features class', () => {
   464  			expect(agonesSDK.alpha).toBeInstanceOf(Alpha);
   465  		});
   466  	});
   467  });