aerospike
Version:
Aerospike Client Library
337 lines (251 loc) • 8.68 kB
text/typescript
// *****************************************************************************
// 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.
// *****************************************************************************
/* 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));
})
*/
})