agones.dev/agones@v1.54.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 });