123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- /// <reference types="@vertx/core" />
- // @ts-check
- import { Router } from '@vertx/web';
- import { PgPool } from '@vertx/pg-client';
- import { PoolOptions } from '@vertx/sql-client/options';
- import { JteTemplateEngine } from '@vertx/web-templ-jte'
- import { PgConnectOptions } from '@vertx/pg-client/options';
- import { Tuple } from '@vertx/sql-client';
- const util = require('./util');
- const SERVER = 'es4x';
- const app = Router.router(vertx);
- const template = JteTemplateEngine.create();
- let date = new Date().toUTCString();
- vertx.setPeriodic(1000, t => date = new Date().toUTCString());
- /*
- * This test exercises the framework fundamentals including keep-alive support, request routing, request header
- * parsing, object instantiation, JSON serialization, response header generation, and request count throughput.
- */
- app.get("/json").handler(ctx => {
- ctx.response()
- .putHeader("Server", SERVER)
- .putHeader("Date", date)
- .putHeader("Content-Type", "application/json")
- .end(JSON.stringify({ message: 'Hello, World!' }));
- });
- const UPDATE_WORLD = "UPDATE world SET randomnumber=$1 WHERE id=$2";
- const SELECT_WORLD = "SELECT id, randomnumber from WORLD where id=$1";
- const SELECT_FORTUNE = "SELECT id, message from FORTUNE";
- let connectOptions = new PgConnectOptions()
- .setCachePreparedStatements(true)
- .setHost('tfb-database')
- .setUser('benchmarkdbuser')
- .setPassword('benchmarkdbpass')
- .setDatabase('hello_world');
- // Pool options
- let poolOptions = new PoolOptions()
- .setMaxSize(1);
- // Create the client pool
- let client = PgPool.pool(vertx, connectOptions, poolOptions);
- /*
- * This test exercises the framework's object-relational mapper (ORM), random number generator, database driver,
- * and database connection pool.
- */
- app.get("/db").handler(ctx => {
- client.preparedQuery(SELECT_WORLD).execute(Tuple.of(util.randomWorld()), res => {
- if (res.succeeded()) {
- let resultSet = res.result().iterator();
- if (!resultSet.hasNext()) {
- ctx.fail(404);
- return;
- }
- let row = resultSet.next();
- ctx.response()
- .putHeader("Server", SERVER)
- .putHeader("Date", date)
- .putHeader("Content-Type", "application/json")
- .end(JSON.stringify({ id: row.getInteger(0), randomNumber: row.getInteger(1) }));
- } else {
- ctx.fail(res.cause());
- }
- })
- });
- /*
- * This test is a variation of Test #2 and also uses the World table. Multiple rows are fetched to more dramatically
- * punish the database driver and connection pool. At the highest queries-per-request tested (20), this test
- * demonstrates all frameworks' convergence toward zero requests-per-second as database activity increases.
- */
- app.get("/queries").handler(ctx => {
- let failed = false;
- let worlds = [];
- const queries = util.getQueries(ctx.request());
- for (let i = 0; i < queries; i++) {
- client.preparedQuery(SELECT_WORLD).execute(Tuple.of(util.randomWorld()), ar => {
- if (!failed) {
- if (ar.failed()) {
- failed = true;
- ctx.fail(ar.cause());
- return;
- }
- // we need a final reference
- const row = ar.result().iterator().next();
- worlds.push({ id: row.getInteger(0), randomNumber: row.getInteger(1) });
- // stop condition
- if (worlds.length === queries) {
- ctx.response()
- .putHeader("Server", SERVER)
- .putHeader("Date", date)
- .putHeader("Content-Type", "application/json")
- .end(JSON.stringify(worlds));
- }
- }
- });
- }
- });
- /*
- * This test exercises the ORM, database connectivity, dynamic-size collections, sorting, server-side templates,
- * XSS countermeasures, and character encoding.
- */
- app.get("/fortunes").handler(ctx => {
- client.preparedQuery(SELECT_FORTUNE).execute(ar => {
- if (ar.failed()) {
- ctx.fail(ar.cause());
- return;
- }
- let fortunes = [];
- let resultSet = ar.result().iterator();
- if (!resultSet.hasNext()) {
- ctx.fail(404);
- return;
- }
- while (resultSet.hasNext()) {
- let row = resultSet.next();
- fortunes.push({ id: row.getInteger(0), message: row.getString(1) });
- }
- fortunes.push({ id: 0, message: "Additional fortune added at request time." });
- fortunes.sort((a, b) => {
- let messageA = a.message;
- let messageB = b.message;
- if (messageA < messageB) {
- return -1;
- }
- if (messageA > messageB) {
- return 1;
- }
- return 0;
- });
- // and now delegate to the engine to render it.
- template.render({ fortunes: fortunes }, "fortunes.jte", res => {
- if (res.succeeded()) {
- ctx.response()
- .putHeader("Server", SERVER)
- .putHeader("Date", date)
- .putHeader("Content-Type", "text/html; charset=UTF-8")
- .end(res.result());
- } else {
- ctx.fail(res.cause());
- }
- });
- });
- });
- /*
- * This test is a variation of Test #3 that exercises the ORM's persistence of objects and the database driver's
- * performance at running UPDATE statements or similar. The spirit of this test is to exercise a variable number of
- * read-then-write style database operations.
- */
- app.route("/updates").handler(ctx => {
- let failed = false;
- let queryCount = 0;
- let worlds = [];
- const queries = util.getQueries(ctx.request());
- for (let i = 0; i < queries; i++) {
- const id = util.randomWorld();
- const index = i;
- client.preparedQuery(SELECT_WORLD).execute(Tuple.of(id), ar => {
- if (!failed) {
- if (ar.failed()) {
- failed = true;
- ctx.fail(ar.cause());
- return;
- }
- const row = ar.result().iterator().next();
- worlds[index] = { id: row.getInteger(0), randomNumber: row.getInteger(1) };
- worlds[index].randomNumber = util.randomWorld();
- if (++queryCount === queries) {
- worlds.sort((a, b) => {
- return a.id - b.id;
- });
- let batch = [];
- worlds.forEach(world => {
- batch.push(Tuple.of(world.randomNumber, world.id));
- });
- client.preparedQuery(UPDATE_WORLD).executeBatch(batch, ar => {
- if (ar.failed()) {
- ctx.fail(ar.cause());
- return;
- }
- let json = [];
- worlds.forEach(world => {
- json.push({ id: world.id, randomNumber: world.randomNumber });
- });
- ctx.response()
- .putHeader("Server", SERVER)
- .putHeader("Date", date)
- .putHeader("Content-Type", "application/json")
- .end(JSON.stringify(json));
- });
- }
- }
- });
- }
- });
- /*
- * This test is an exercise of the request-routing fundamentals only, designed to demonstrate the capacity of
- * high-performance platforms in particular. Requests will be sent using HTTP pipelining. The response payload is
- * still small, meaning good performance is still necessary in order to saturate the gigabit Ethernet of the test
- * environment.
- */
- app.get("/plaintext").handler(ctx => {
- ctx.response()
- .putHeader("Server", SERVER)
- .putHeader("Date", date)
- .putHeader("Content-Type", "text/plain")
- .end('Hello, World!');
- });
- vertx
- .createHttpServer()
- .requestHandler(app)
- .listen(8080, listen => {
- if (listen.failed()) {
- console.trace(listen.cause());
- System.exit(1);
- } else {
- console.log('Server listening at: http://0.0.0.0:8080/');
- }
- });
|