UNPKG

aerospike

Version:
337 lines (251 loc) 8.68 kB
// ***************************************************************************** // Copyright 2013-2025 Aerospike, Inc. // // 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. // ***************************************************************************** 'use strict' /* eslint-env mocha */ /* global expect */ import Aerospike, { Client as Cli, Node, NodeMetrics, ConnectionStats, Cluster, MetricsPolicy, MetricsListeners} from 'aerospike'; import { expect } from 'chai'; import * as helper from './test_helper'; import * as fs from 'fs'; describe('Metrics tests', function () { this.timeout(40000) const client: Cli = helper.client const blank_policy: MetricsPolicy = new Aerospike.MetricsPolicy() let enableTriggered: boolean = false let disableTriggered: boolean = false let snapshotTriggered: boolean = false let clusterFromDisableListener: any = null let clusterFromSnapshotListener: any = null let metricsLogFolder = '.' function enableListener() { enableTriggered = true return } function snapshotListener(cluster: Cluster) { snapshotTriggered = true clusterFromSnapshotListener = cluster return } function nodeCloseListener(node: Node) { return } function disableListener(cluster: Cluster) { disableTriggered = true clusterFromDisableListener = cluster return } function enable_throw_exc() { throw new Error(`enable threw an error`) } function disable_throw_exc( Cluster: any ){ throw new Error(`disable threw an error`) } it('enable metrics', async function () { let retval: any = await client.enableMetrics() expect(retval).to.eql(null) }) it('enable metrics extra args', async function () { try{ await (client as any).enableMetrics(null, 1) } catch(error: any){ expect(error.message).to.eql("this.callback.bind is not a function") } }) it('With valid policy ', async function () { await client.enableMetrics(blank_policy) }) it('With null policy ', async function () { await (client as any).enableMetrics(null) }) it('enable metrics incorrect args', async function () { try{ await (client as any).enableMetrics(1) } catch(error: any){ expect(error.message).to.eql("policy must be an object") } }) it('test metrics writer', async function () { let policy: MetricsPolicy = new Aerospike.MetricsPolicy({ interval: 1 }) await client.enableMetrics(policy) await new Promise(r => setTimeout(r, 3000)); await client.disableMetrics() const metricsLogFilenames = fs.readdirSync('.') .filter(file => file.match(/^metrics-.*\.log$/)); if (metricsLogFilenames.length === 0) { throw new Error('No metrics log files found'); } }) it('test setting custom listener functions', async function () { let listeners: MetricsListeners = new Aerospike.MetricsListeners( { enableListener, disableListener, nodeCloseListener, snapshotListener } ) let bucketCount = 5 let policy: MetricsPolicy = new MetricsPolicy({ metricsListeners: listeners, reportDir: metricsLogFolder, reportSizeLimit: 1000, interval: 2, latencyColumns: bucketCount, latencyShift: 2 } ) await client.enableMetrics(policy) const key = new Aerospike.Key('test', 'demo', 'demo') const key2 = new Aerospike.Key('test', 'demo', 'demo2') const key3 = new Aerospike.Key('test', 'demo', 'demo3') await client.put(key, {example: 1}) await client.put(key2, {example: 1}) await client.put(key3, {example: 1}) await client.get(key) await client.get(key2) await client.get(key3) await new Promise(r => setTimeout(r, 3000)); await client.disableMetrics() await new Promise(r => setTimeout(r, 500)); expect(enableTriggered).to.eql(true) expect(snapshotTriggered).to.eql(true) expect(disableTriggered).to.eql(true) for (const cluster of [clusterFromSnapshotListener, clusterFromDisableListener]) { let temp: Cluster = cluster expect(cluster.clusterName).to.satisfy((name: string) => (name === null) || typeof name === "string"); expect(cluster.invalidNodeCount).to.be.a("number"); expect(cluster.commandCount).to.be.a("number"); expect(cluster.retryCount).to.be.a("number"); expect(cluster.nodes).to.be.an("array"); // Also check the Node and ConnectionStats objects in the Cluster object were populated for (const node of cluster.nodes) { let tempNode: Node = node expect(node.name).to.be.a("string"); expect(node.address).to.be.a("string"); expect(node.port).to.be.a("number"); let conns: ConnectionStats = node.conns expect(node.conns.inUse).to.be.a("number"); expect(node.conns.inPool).to.be.a("number"); expect(node.conns.opened).to.be.a("number"); expect(node.conns.closed).to.be.a("number"); expect(node.errorCount).to.be.a("number"); expect(node.timeoutCount).to.be.a("number"); // Check NodeMetrics const metrics: NodeMetrics = node.metrics; const latencyBuckets = [ metrics.connLatency, metrics.writeLatency, metrics.readLatency, metrics.batchLatency, metrics.queryLatency ]; for (const buckets of latencyBuckets) { expect(buckets).to.be.an("array").with.lengthOf(bucketCount); for (const bucket of buckets) { expect(bucket).to.be.a("number"); } } } } }) it('enable metrics incorrect args latencyShift', async function () { let policy: any = { latencyShift: true, } try{ await client.enableMetrics(policy) } catch(error: any){ expect(error.message).to.eql("Metrics policy parameter invalid") } }) it('enable metrics incorrect args reportDir', async function () { let policy: any = { reportDir: true, } try{ await client.enableMetrics(policy) } catch(error: any){ expect(error.message).to.eql("Metrics policy parameter invalid") } }) it('reportDir too long', async function () { let policy: any = { reportDir: 'a'.repeat(257) } try{ await client.enableMetrics(policy) } catch(error: any){ expect(error.message).to.eql("Metrics policy parameter invalid") } }) it('disable metrics', async function () { let retval: any = await client.enableMetrics() expect(retval).to.eql(null) }) it('disable metrics incorrect args', async function () { let policy: any = { reportDir: true, } try{ await (client as any).disableMetrics(1) } catch(error: any){ expect(error.message).to.eql("this.callback.bind is not a function") } }) /* The errors are thrown in an asynchronous context rather than as a return value. If the implementation is changed, these tests can be added it('enable metric throws exception', async function () { let listeners: MetricsListeners = new Aerospike.MetricsListeners( { enableListener: enable_throw_exc, disableListener, nodeCloseListener, snapshotListener } ) let policy: MetricsPolicy = new MetricsPolicy({ metricsListeners: listeners, } ) //expect(await client.enableMetrics(policy)).to.throw("ERROR HERE") }) it('disable metric throws exception', async function () { let listeners: MetricsListeners = new Aerospike.MetricsListeners( { enableListener, disableListener: disable_throw_exc, nodeCloseListener, snapshotListener } ) let policy: MetricsPolicy = new MetricsPolicy({ metricsListeners: listeners, } ) await client.enableMetrics(policy) //expect(await client.disableMetrics()).to.throw("ERROR HERE") await new Promise(r => setTimeout(r, 3000)); }) */ })