splunk-sdk
Version:
SDK for usage with the Splunk REST API
1,198 lines (1,092 loc) • 213 kB
JavaScript
var Async = splunkjs.Async;
var utils = splunkjs.Utils;
assert = chai.assert;
var idCounter = 0;
var getNextId = function() {
return "id" + (idCounter++) + "_" + ((new Date()).valueOf());
};
describe("Service Tests ", function(){
describe("Namespace tests", () => {
beforeEach(async function () {
this.service = svc;
let that = this;
let appName1 = "jssdk_testapp_" + getNextId();
let appName2 = "jssdk_testapp_" + getNextId();
let userName1 = "jssdk_testuser_" + getNextId();
let userName2 = "jssdk_testuser_" + getNextId();
let apps = this.service.apps();
let users = this.service.users();
this.namespace11 = { owner: userName1, app: appName1 };
this.namespace12 = { owner: userName1, app: appName2 };
this.namespace21 = { owner: userName2, app: appName1 };
this.namespace22 = { owner: userName2, app: appName2 };
let app1 = await apps.create({ name: appName1 });
that.app1 = app1;
that.appName1 = appName1;
let app2 = await apps.create({ name: appName2 });
that.app2 = app2;
that.appName2 = appName2;
let user1 = users.create({ name: userName1, password: "abcdefg!", roles: ["user"] });
that.user1 = user1;
that.userName1 = userName1;
let user2 = users.create({ name: userName2, password: "abcdefg!", roles: ["user"] });
that.user2 = user2;
that.userName2 = userName2;
await utils.sleep(2000);
});
it("Namespace protection", async function () {
let searchName = "jssdk_search_" + getNextId();
let search = "search *";
let service = this.service;
let savedSearches11 = service.savedSearches(this.namespace11);
let savedSearches21 = service.savedSearches(this.namespace21);
// Create the saved search only in the 11 namespace
await savedSearches11.create({ name: searchName, search: search });
// Refresh the 11 saved searches
await savedSearches11.fetch();
// Refresh the 21 saved searches
await savedSearches21.fetch();
let entity11 = savedSearches11.item(searchName);
let entity21 = savedSearches21.item(searchName);
// Make sure the saved search exists in the 11 namespace
assert.ok(entity11);
assert.strictEqual(entity11.name, searchName);
assert.strictEqual(entity11.properties().search, search);
// Make sure the saved search doesn't exist in the 11 namespace
assert.ok(!entity21);
});
it("Namespace item", async function () {
let searchName = "jssdk_search_" + getNextId();
let search = "search *";
let service = this.service;
let namespace_1 = { owner: "-", app: this.appName1 };
let namespace_nobody1 = { owner: "nobody", app: this.appName1 };
let savedSearches11 = service.savedSearches(this.namespace11);
let savedSearches21 = service.savedSearches(this.namespace21);
let savedSearches_1 = service.savedSearches(namespace_1);
let savedSearches_nobody1 = service.savedSearches(namespace_nobody1);
let that = this;
// Create a saved search in the 11 namespace
await savedSearches11.create({ name: searchName, search: search });
// Create a saved search in the 21 namespace
await savedSearches21.create({ name: searchName, search: search });
// Refresh the -/1 namespace
await savedSearches_1.fetch();
// Refresh the 1/1 namespace
await savedSearches11.fetch();
// Refresh the 2/1 namespace
await savedSearches21.fetch();
let entity11 = savedSearches11.item(searchName, that.namespace11);
let entity21 = savedSearches21.item(searchName, that.namespace21);
// Ensure that the saved search exists in the 11 namespace
assert.ok(entity11);
assert.strictEqual(entity11.name, searchName);
assert.strictEqual(entity11.properties().search, search);
assert.strictEqual(entity11.namespace.owner, that.namespace11.owner);
assert.strictEqual(entity11.namespace.app, that.namespace11.app);
// Ensure that the saved search exists in the 21 namespace
assert.ok(entity21);
assert.strictEqual(entity21.name, searchName);
assert.strictEqual(entity21.properties().search, search);
assert.strictEqual(entity21.namespace.owner, that.namespace21.owner);
assert.strictEqual(entity21.namespace.app, that.namespace21.app);
// Create a saved search in the nobody/1 namespace
await savedSearches_nobody1.create({ name: searchName, search: search });
// Refresh the 1/1 namespace
await savedSearches11.fetch();
// Refresh the 2/1 namespace
await savedSearches21.fetch();
// Ensure that we can't get the item from the generic
// namespace without specifying a namespace
try {
savedSearches_1.item(searchName);
assert.ok(false);
} catch (err) {
assert.ok(err);
}
// Ensure that we can't get the item using wildcard namespaces.
try {
savedSearches_1.item(searchName, { owner: '-' });
assert.ok(false);
} catch (err) {
assert.ok(err);
}
try {
savedSearches_1.item(searchName, { app: '-' });
assert.ok(false);
} catch (err) {
assert.ok(err);
}
try {
savedSearches_1.item(searchName, { app: '-', owner: '-' });
assert.ok(false);
} catch (err) {
assert.ok(err);
}
// Ensure we get the right entities from the -/1 namespace when we
// specify it.
entity11 = savedSearches_1.item(searchName, that.namespace11);
entity21 = savedSearches_1.item(searchName, that.namespace21);
assert.ok(entity11);
assert.strictEqual(entity11.name, searchName);
assert.strictEqual(entity11.properties().search, search);
assert.strictEqual(entity11.namespace.owner, that.namespace11.owner);
assert.strictEqual(entity11.namespace.app, that.namespace11.app);
assert.ok(entity21);
assert.strictEqual(entity21.name, searchName);
assert.strictEqual(entity21.properties().search, search);
assert.strictEqual(entity21.namespace.owner, that.namespace21.owner);
assert.strictEqual(entity21.namespace.app, that.namespace21.app);
});
it("Delete test users", async function () {
let users = this.service.users();
users = await users.fetch();
let userList = users.list();
await utils.parallelEach(
userList,
async function (user, idx) {
if (utils.startsWith(user.name, "jssdk_")) {
await user.remove();
}
}
);
})
});
describe("Job tests", function (done) {
beforeEach(function (done) {
this.service = svc;
done();
});
// Disabling the test for now because the apps/appinstall endpoint have been deprecated from Splunk 8.2
// it("Callback#Create+abort job", function (done) {
// var service = this.service;
// Async.chain([
// function (done) {
// var app_name = path.join(process.env.SPLUNK_HOME, ('/etc/apps/sdkappcollection/build/sleep_command.tar'));
// // Fix path on Windows if $SPLUNK_HOME contains a space (ex: C:/Program%20Files/Splunk)
// app_name = app_name.replace("%20", " ");
// // var app_name = "sleep_command";
// service.post("apps/local", { update: 1, name: app_name, filename: true }, done);
// },
// function (done) {
// var sid = getNextId();
// var options = { id: sid };
// var jobs = service.jobs();
// var req = jobs.oneshotSearch('search index=_internal | head 1 | sleep 10', options, function (err, job) {
// assert.ok(err);
// assert.ok(!job);
// assert.strictEqual(err.error, "abort");
// });
// Async.sleep(1000, function () {
// req.abort();
// });
// }
// ],
// function (err) {
// assert.ok(!err);
// done();
// });
// done();
// });
it("Job Create Urls validation", function () {
let testData = {
"v1_1": {
"qualifiedPath": "/servicesNS/admin/foo/search/jobs/id5_1649796951725",
"relpath": "search/jobs/id5_1649796951725/events",
"expected": "/servicesNS/admin/foo/search/jobs/id5_1649796951725/events"
},
"v1_2": {
"qualifiedPath": "/services/search/jobs/id5_1649796951725",
"relpath": "search/jobs/id5_1649796951725/events",
"expected": "/services/search/jobs/id5_1649796951725/events"
},
"v2_1": {
"qualifiedPath": "/servicesNS/admin/foo/search/v2/jobs/id5_1649796951725",
"relpath": "search/v2/jobs/id5_1649796951725/events",
"expected": "/servicesNS/admin/foo/search/v2/jobs/id5_1649796951725/events"
},
"v2_2": {
"qualifiedPath": "/services/search/v2/jobs/id5_1649796951725",
"relpath": "search/v2/jobs/id5_1649796951725/events",
"expected": "/services/search/v2/jobs/id5_1649796951725/events"
}
}
for (const [key, value] of Object.entries(testData)) {
createdUrl = this.service.jobs().createUrl(value.qualifiedPath, value.relpath);
assert.strictEqual(value.expected, createdUrl);
}
});
it("Create and cancel job", async function () {
let sid = getNextId();
let job = await this.service.jobs().search('search index=_internal | head 1', { id: sid });
assert.ok(job);
assert.strictEqual(job.sid, sid);
await job.cancel();
});
it("Create job error", async function () {
let sid = getNextId();
try {
let res = await this.service.jobs().search({ search: 'index=_internal | head 1', id: sid });
assert.ok(!res);
} catch (error) {
assert.ok(error);
}
});
it("List jobs", async function () {
let jobs = await this.service.jobs().fetch();
assert.ok(jobs);
let jobsList = jobs.list();
assert.ok(jobsList.length > 0);
for (let i = 0; i < jobsList.length; i++) {
assert.ok(jobsList[i]);
};
});
it("Contains job", async function () {
var that = this;
let sid = getNextId();
let jobs = this.service.jobs();
let job = await jobs.search('search index=_internal | head 1', { id: sid });
assert.ok(job);
assert.strictEqual(job.sid, sid);
jobs = await jobs.fetch();
job = jobs.item(sid);
assert.ok(job);
await job.cancel();
});
it("Job results", async function () {
let sid = getNextId();
let service = this.service;
let that = this;
let job = await that.service.jobs().search('search index=_internal | head 1 | stats count', { id: sid });
assert.strictEqual(job.sid, sid);
await pollUntil(
job,
function (j) {
return job.properties()["isDone"];
},
10
);
[results, job] = await job.results({});
assert.strictEqual(results.rows.length, 1);
assert.strictEqual(results.fields.length, 1);
assert.strictEqual(results.fields[0], "count");
assert.strictEqual(results.rows[0][0], "1");
await job.cancel();
});
it("Job events", async function () {
let sid = getNextId();
let service = this.service;
let that = this;
let job = await that.service.jobs().search('search index=_internal | head 1', { id: sid });
assert.strictEqual(job.sid, sid);
await pollUntil(
job,
function (j) {
return job.properties()["isDone"];
},
10
);
[results, job] = await job.events({});
assert.strictEqual(results.rows.length, 1);
assert.strictEqual(results.fields.length, results.rows[0].length);
await job.cancel();
});
it("Job events - post processing search params", async function () {
let sid = getNextId();
let service = this.service;
let that = this;
let job = await that.service.jobs().search('search index=_internal | head 2', { id: sid });
assert.strictEqual(job.sid, sid);
await pollUntil(
job,
function (j) {
return job.properties()["isDone"];
},
10
);
[results, job] = await job.events({ search: "| head 1" });
assert.strictEqual(results.post_process_count, 1);
assert.strictEqual(results.rows.length, 1);
assert.strictEqual(results.fields.length, results.rows[0].length);
await job.cancel();
});
it("Job results preview", async function () {
let sid = getNextId();
let service = this.service;
let that = this;
let job = await that.service.jobs().search('search index=_internal | head 1 | stats count', { id: sid });
assert.strictEqual(job.sid, sid);
await pollUntil(
job,
function (j) {
return job.properties()["isDone"];
},
10
);
[results, job] = await job.preview({});
assert.strictEqual(results.rows.length, 1);
assert.strictEqual(results.fields.length, 1);
assert.strictEqual(results.fields[0], "count");
assert.strictEqual(results.rows[0][0], "1");
await job.cancel();
});
it("Job results iterator", async function () {
let that = this;
let job = await that.service.jobs().search('search index=_internal | head 10', {});
await pollUntil(
job,
function (j) {
return job.properties()["isDone"];
},
10
);
let iterator = job.iterator("results", { pagesize: 4 });
let hasMore = true;
let pageSizes = [];
await utils.whilst(
function () { return hasMore; },
async function () {
try {
[results, _hasMore] = await iterator.next();
hasMore = _hasMore;
if (hasMore) {
pageSizes.push(results.rows.length);
}
} catch (error) {
return error;
}
}
);
assert.deepStrictEqual(pageSizes, [4, 4, 2]);
});
// Disabling the test for now because the apps/appinstall endpoint have been deprecated from Splunk 8.2
// it("Callback#Enable + disable preview", function (done) {
// var that = this;
// var sid = getNextId();
// var service = this.service.specialize("nobody", "sdkappcollection");
// Async.chain([
// function (done) {
// service.jobs().search('search index=_internal | head 1 | sleep 60', { id: sid }, done);
// },
// function (job, done) {
// job.enablePreview(done);
// },
// function (job, done) {
// job.disablePreview(done);
// },
// function (job, done) {
// job.cancel(done);
// }
// ],
// function (err) {
// assert.ok(!err);
// done();
// }
// );
// });
// Disabling the test for now because the apps/appinstall endpoint have been deprecated from Splunk 8.2
// it("Callback#Pause + unpause + finalize preview", function (done) {
// var that = this;
// var sid = getNextId();
// var service = this.service.specialize("nobody", "sdkappcollection");
// Async.chain([
// function (done) {
// service.jobs().search('search index=_internal | head 1 | sleep 5', { id: sid }, done);
// },
// function (job, done) {
// job.pause(done);
// },
// function (job, done) {
// pollUntil(
// job,
// function (j) {
// return j.properties()["isPaused"];
// },
// 10,
// done
// );
// },
// function (job, done) {
// assert.ok(job.properties()["isPaused"]);
// job.unpause(done);
// },
// function (job, done) {
// pollUntil(
// job,
// function (j) {
// return !j.properties()["isPaused"];
// },
// 10,
// done
// );
// },
// function (job, done) {
// assert.ok(!job.properties()["isPaused"]);
// job.finalize(done);
// },
// function (job, done) {
// job.cancel(done);
// }
// ],
// function (err) {
// assert.ok(!err);
// done();
// }
// );
// });
it("Set TTL", async function () {
let sid = getNextId();
let originalTTL = 0;
var that = this;
let job = await that.service.jobs().search('search index=_internal | head 1', { id: sid });
job = await job.fetch();
let ttl = job.properties()["ttl"];
originalTTL = ttl;
let res = await job.setTTL(ttl * 2);
job = await job.fetch();
ttl = job.properties()["ttl"];
assert.ok(ttl > originalTTL);
assert.ok(ttl <= (originalTTL * 2));
await job.cancel();
});
// Disabling the test for now because the apps/appinstall endpoint have been deprecated from Splunk 8.2
// it("Callback#Set priority", function (done) {
// var sid = getNextId();
// var originalPriority = 0;
// var that = this;
// var service = this.service.specialize("nobody", "sdkappcollection");
// Async.chain([
// function (done) {
// service.jobs().search('search index=_internal | head 1 | sleep 5', { id: sid }, done);
// },
// function (job, done) {
// job.track({}, {
// ready: function (job) {
// done(null, job);
// }
// });
// },
// function (job, done) {
// var priority = job.properties()["priority"];
// assert.ok(priority, 5);
// job.setPriority(priority + 1, done);
// },
// function (job, done) {
// job.fetch(done);
// },
// function (job, done) {
// job.cancel(done);
// }
// ],
// function (err) {
// assert.ok(!err);
// done();
// }
// );
// });
it("Search log", async function () {
let sid = getNextId();
var that = this;
let job = await that.service.jobs().search('search index=_internal | head 1', { id: sid, exec_mode: "blocking" });
let response = await job.searchlog();
let log = response[0];
job = response[1];
assert.ok(job);
assert.ok(log);
assert.ok(log.length > 0);
assert.ok(log.split("\r\n").length > 0);
await job.cancel();
});
it("Search summary", async function () {
let sid = getNextId();
var that = this;
let job = await that.service.jobs().search(
'search index=_internal | head 1 | eval foo="bar" | fields foo',
{
id: sid,
status_buckets: 300,
rf: ["foo"]
});
// Let's sleep for 2 second so
// we let the server catch up
await utils.sleep(2000);
let response = await job.summary({});
let summary = response[0];
job = response[1];
assert.ok(job);
assert.ok(summary);
assert.strictEqual(summary.event_count, 1);
assert.strictEqual(summary.fields.foo.count, 1);
assert.strictEqual(summary.fields.foo.distinct_count, 1);
assert.ok(summary.fields.foo.is_exact, 1);
assert.strictEqual(summary.fields.foo.modes.length, 1);
assert.strictEqual(summary.fields.foo.modes[0].count, 1);
assert.strictEqual(summary.fields.foo.modes[0].value, "bar");
assert.ok(summary.fields.foo.modes[0].is_exact);
await job.cancel();
});
it("Search timeline", async function () {
let sid = getNextId();
var that = this;
let job = await that.service.jobs().search(
'search index=_internal | head 1 | eval foo="bar" | fields foo',
{
id: sid,
status_buckets: 300,
rf: ["foo"],
exec_mode: "blocking"
});
let response = await job.timeline({});
let timeline = response[0];
job = response[1];
assert.ok(job);
assert.ok(timeline);
assert.strictEqual(timeline.buckets.length, 1);
assert.strictEqual(timeline.event_count, 1);
assert.strictEqual(timeline.buckets[0].available_count, 1);
assert.strictEqual(timeline.buckets[0].duration, 0.001);
assert.strictEqual(timeline.buckets[0].earliest_time_offset, timeline.buckets[0].latest_time_offset);
assert.strictEqual(timeline.buckets[0].total_count, 1);
assert.ok(timeline.buckets[0].is_finalized);
await job.cancel();
});
it("Touch", async function () {
let sid = getNextId();
var that = this;
let originalTime = "";
let job = await that.service.jobs().search('search index=_internal | head 1', { id: sid });
job = await job.fetch();
assert.ok(job);
originalTime = job.properties().updated;
await utils.sleep(1200);
await job.touch();
job = await job.fetch();
assert.ok(originalTime !== job.updated());
await job.cancel();
});
it("Create failure", async function () {
let name = "jssdk_savedsearch_" + getNextId();
let originalSearch = "search index=_internal | head 1";
let jobs = this.service.jobs();
try {
let res = await jobs.create({ search: originalSearch, name: name, exec_mode: "oneshot" });
assert.ok(!res);
} catch (error) {
assert.ok(error);
}
});
it("Create fails with no search string", async function () {
let jobs = this.service.jobs();
try {
let res = await jobs.create("", {});
assert.ok(!res);
} catch (error) {
assert.ok(error);
}
});
it("Oneshot search", async function () {
let sid = getNextId();
var that = this;
let originalTime = "";
let results = await that.service.jobs().oneshotSearch('search index=_internal | head 1 | stats count', { id: sid });
assert.ok(results);
assert.ok(results.fields);
assert.strictEqual(results.fields.length, 1);
assert.strictEqual(results.fields[0], "count");
assert.ok(results.rows);
assert.strictEqual(results.rows.length, 1);
assert.strictEqual(results.rows[0].length, 1);
assert.strictEqual(results.rows[0][0], "1");
});
it("Oneshot search with json results", async function () {
let sid = getNextId();
var that = this;
let results = await that.service.jobs().oneshotSearch('search index=_internal | head 1 | stats count', { id: sid, output_mode: 'json' });
assert.ok(results);
assert.ok(results.fields);
assert.strictEqual(results.fields.length, 1);
});
it("Oneshot search with xml results", async function () {
let sid = getNextId();
var that = this;
let results = await that.service.jobs().oneshotSearch('search index=_internal | head 2 | stats count', { id: sid, output_mode: 'xml' });
assert.ok(results);
assert.ok(results.includes('<field>count</field>'));
assert.ok(results.includes('<value><text>2</text></value>'));
});
it("Oneshot search with csv results", async function () {
let sid = getNextId();
var that = this;
let results = await that.service.jobs().oneshotSearch('makeresults count=3 | streamstats count | eval foo="bar" | fields - _time', { id: sid, output_mode: 'csv' });
assert.ok(results);
assert.ok(results.includes('count,foo'));
assert.ok(results.includes('1,bar'));
assert.ok(results.includes('2,bar'));
assert.ok(results.includes('3,bar'));
});
it("Oneshot search with no results", async function () {
let sid = getNextId();
var that = this;
let query = 'search index=history MUST_NOT_EXISTABCDEF';
let results = await that.service.jobs().oneshotSearch(query, { id: sid });
assert.ok(results);
assert.strictEqual(results.fields.length, 0);
assert.strictEqual(results.rows.length, 0);
assert.ok(!results.preview);
});
// it("Callback#Service oneshot search", function(done) {
// var sid = getNextId();
// var that = this;
// var namespace = {owner: "admin", app: "search"};
// var splunkVersion = 6.1; // Default to pre-6.2 version
// var originalLoggerLevel = "DEBUG";
// Async.chain([
// function(done) {
// // If running on Splunk 6.2+, first set the search logger level to DEBUG
// Async.chain([
// function(done1) {
// that.service.serverInfo(done1);
// },
// function(info, done1) {
// splunkVersion = parseFloat(info.properties().version);
// if (splunkVersion < 6.2) {
// done(); // Exit the inner Async.chain
// }
// else {
// done1();
// }
// },
// function(done1) {
// that.service.configurations({owner: "admin", app: "search"}).fetch(done1);
// },
// function(confs, done1) {
// try {
// confs.item("limits").fetch(done1);
// }
// catch(e) {
// done1(e);
// }
// },
// function(conf, done1) {
// var searchInfo = conf.item("search_info");
// // Save this so it can be restored later
// originalLoggerLevel = searchInfo.properties()["infocsv_log_level"];
// searchInfo.update({"infocsv_log_level": "DEBUG"}, done1);
// },
// function(conf, done1) {
// assert.strictEqual("DEBUG", conf.properties()["infocsv_log_level"]);
// done1();
// }
// ],
// function(err) {
// assert.ok(!err);
// done();
// }
// );
// },
// function(done) {
// that.service.oneshotSearch('search index=_internal | head 1 | stats count', {id: sid}, namespace, done);
// },
// function(results, done) {
// assert.ok(results);
// assert.ok(results.fields);
// assert.strictEqual(results.fields.length, 1);
// assert.strictEqual(results.fields[0], "count");
// assert.ok(results.rows);
// assert.strictEqual(results.rows.length, 1);
// assert.strictEqual(results.rows[0].length, 1);
// assert.strictEqual(results.rows[0][0], "1");
// assert.ok(results.messages[1].text.indexOf('owner="admin"'));
// assert.ok(results.messages[1].text.indexOf('app="search"'));
// done();
// },
// function(done) {
// Async.chain([
// function(done1) {
// if (splunkVersion < 6.2) {
// done(); // Exit the inner Async.chain
// }
// else {
// done1();
// }
// },
// function(done1) {
// that.service.configurations({owner: "admin", app: "search"}).fetch(done1);
// },
// function(confs, done1) {
// try {
// confs.item("limits").fetch(done1);
// }
// catch(e) {
// done1(e);
// }
// },
// function(conf, done1) {
// var searchInfo = conf.item("search_info");
// // Restore the logger level from before
// searchInfo.update({"infocsv_log_level": originalLoggerLevel}, done1);
// },
// function(conf, done1) {
// assert.strictEqual(originalLoggerLevel, conf.properties()["infocsv_log_level"]);
// done1();
// }
// ],
// function(err) {
// assert.ok(!err);
// done();
// }
// );
// }
// ],
// function(err) {
// assert.ok(!err);
// done();
// }
// );
// });
it("Service search", async function () {
let sid = getNextId();
let service = this.service;
let that = this;
let namespace = { owner: "admin", app: "search" };
let job = await that.service.search('search index=_internal | head 1 | stats count', { id: sid }, namespace);
assert.strictEqual(job.sid, sid);
assert.strictEqual(job.namespace, namespace);
await pollUntil(
job,
function (j) {
return job.properties()["isDone"];
},
10
);
[results, job] = await job.results({});
assert.strictEqual(results.rows.length, 1);
assert.strictEqual(results.fields.length, 1);
assert.strictEqual(results.fields[0], "count");
assert.strictEqual(results.rows[0][0], "1");
await job.cancel();
});
it("Wait until job done", async function () {
let job = await this.service.search('search index=_internal | head 1000', {});
let numReadyEvents = 0;
let numProgressEvents = 0;
await job.track({ period: 200 }, {
ready: function (job) {
assert.ok(job);
numReadyEvents++;
},
progress: function (job) {
assert.ok(job);
numProgressEvents++;
},
done: function (job) {
assert.ok(job);
assert.ok(numReadyEvents === 1); // all done jobs must have become ready
assert.ok(numProgressEvents >= 1); // a job that becomes ready has progress
},
failed: function (job) {
assert.ok(job);
assert.ok(false, "Job failed unexpectedly.");
},
error: function (err) {
assert.ok(err);
assert.ok(false, "Error while tracking job.");
}
});
});
it("Wait until job failed", async function () {
let job = await this.service.search('search index=_internal | head bogusarg', {});
let numReadyEvents = 0;
let numProgressEvents = 0;
await job.track({ period: 200 }, {
ready: function (job) {
assert.ok(job);
numReadyEvents++;
},
progress: function (job) {
assert.ok(job);
numProgressEvents++;
},
done: function (job) {
assert.ok(job);
assert.ok(false, "Job became done unexpectedly.");
},
failed: function (job) {
assert.ok(job);
assert.ok(numReadyEvents === 1); // even failed jobs become ready
assert.ok(numProgressEvents >= 1); // a job that becomes ready has progress
},
error: function (err) {
assert.ok(err);
assert.ok(false, "Error while tracking job.");
}
});
});
it("track() with default params and one function", async function () {
let job = await this.service.search('search index=_internal | head 1', {});
await job.track({}, function (job) {
assert.ok(job);
});
});
it("track() should stop polling if only the ready callback is specified", async function () {
let job = await this.service.search('search index=_internal | head 1', {});
await job.track({}, {
ready: function (job) {
assert.ok(job);
},
_stoppedAfterReady: function (job) {
assert.ok(job);
}
});
});
it("track() a job that is not immediately ready", async function () {
/*jshint loopfunc:true */
let numJobs = 20;
let numJobsLeft = numJobs;
let gotJobNotImmediatelyReady = false;
for (let i = 0; i < numJobs; i++) {
this.service.search('search index=_internal | head 10000', {}).then(async (job) => {
await job.track({}, {
_preready: function (job) {
gotJobNotImmediatelyReady = true;
},
ready: function (job) {
numJobsLeft--;
if (numJobsLeft === 0) {
if (!gotJobNotImmediatelyReady) {
splunkjs.Logger.error("", "WARNING: Couldn't test code path in track() where job wasn't ready immediately.");
}
assert.ok(true);
}
}
});
});
}
});
it("Service.getJob() works", async function () {
var that = this;
let sidsMatch = false;
let job = await this.service.search('search index=_internal | head 1', {});
let sid = job.sid;
let innerJob = await that.service.getJob(sid);
assert.strictEqual(sid, innerJob.sid);
sidsMatch = sid === innerJob.sid;
assert.ok(sidsMatch);
});
});
describe("Datamodels test", () => {
beforeEach(async function () {
this.service = svc;
this.dataModels = svc.dataModels();
this.skip = false;
var that = this;
let info = await this.service.serverInfo();
if (parseInt(info.properties().version.split(".")[0], 10) < 6) {
that.skip = true;
splunkjs.Logger.log("Skipping data model tests...");
}
});
it("DataModels - fetch a built-in data model", async function () {
if (this.skip) {
return;
}
let that = this;
let dataModels = await that.dataModels.fetch();
let dm = dataModels.item("internal_audit_logs");
// Check for the 3 objects we expect
assert.ok(dm.objectByName("Audit"));
assert.ok(dm.objectByName("searches"));
assert.ok(dm.objectByName("modify"));
// Check for an object that shouldn't exist
assert.strictEqual(null, dm.objectByName(getNextId()));
});
it("DataModels - create & delete an empty data model", async function () {
if (this.skip) {
return;
}
let args;
try {
let response = await fetch("./data/empty_data_model.json");
args = await response.json();
}
catch (err) {
// Fail if we can't read the file, likely to occur in the browser
assert.ok(!err);
}
let name = "delete-me-" + getNextId();
let that = this;
let dataModels = await that.dataModels.fetch();
let initialSize = dataModels.list().length;
let dataModel = await dataModels.create(name, args);
let updatedDataModels = await that.dataModels.fetch();
// Make sure we have 1 more data model than we started with
assert.strictEqual(initialSize + 1, updatedDataModels.list().length);
// Delete the data model we just created, by name.
await updatedDataModels.item(name).remove();
let newDataModels = await that.dataModels.fetch();
assert.strictEqual(initialSize, newDataModels.list().length);
});
it("DataModels - create a data model with spaces in the name, which are swapped for -'s", async function () {
if (this.skip) {
return;
}
let args;
try {
let response = await fetch("./data/empty_data_model.json");
args = await response.json();
}
catch (err) {
// Fail if we can't read the file, likely to occur in the browser
assert.ok(!err);
}
let name = "delete-me- " + getNextId();
let that = this;
let dataModel = await that.dataModels.create(name, args);
assert.strictEqual(name.replace(" ", "_"), dataModel.name);
});
it("DataModels - create a data model with 0 objects", async function () {
if (this.skip) {
return;
}
let args;
try {
let response = await fetch("./data/empty_data_model.json");
args = await response.json();
}
catch (err) {
// Fail if we can't read the file, likely to occur in the browser
assert.ok(!err);
}
let name = "delete-me-" + getNextId();
let that = this;
let dataModel = await that.dataModels.create(name, args);
// Check for 0 objects before fetch
assert.strictEqual(0, dataModel.objects.length);
let dataModels = await that.dataModels.fetch();
assert.strictEqual(0, dataModels.item(name).objects.length);
});
it("DataModels - create a data model with 1 search object", async function () {
if (this.skip) {
return;
}
let dataModels = this.service.dataModels();
let args;
try {
let response = await fetch("./data/object_with_one_search.json");
args = await response.json();
}
catch (err) {
// Fail if we can't read the file, likely to occur in the browser
assert.ok(!err);
}
let name = "delete-me-" + getNextId();
let that = this;
let dataModel = await that.dataModels.create(name, args);
// Check for 1 object before fetch
assert.strictEqual(1, dataModel.objects.length);
dataModels = await that.dataModels.fetch();
// Check for 1 object after fetch
assert.strictEqual(1, dataModels.item(name).objects.length);
});
it("DataModels - create a data model with 2 search objects", async function () {
if (this.skip) {
return;
}
let args;
try {
let response = await fetch("./data/object_with_two_searches.json");
args = await response.json();
}
catch (err) {
// Fail if we can't read the file, likely to occur in the browser
assert.ok(!err);
}
let name = "delete-me-" + getNextId();
let that = this;
let dataModel = await that.dataModels.create(name, args);
// Check for 2 objects before fetch
assert.strictEqual(2, dataModel.objects.length);
dataModels = await that.dataModels.fetch();
// Check for 2 objects after fetch
assert.strictEqual(2, dataModels.item(name).objects.length);
});
it("DataModels - data model objects are created correctly", async function () {
if (this.skip) {
return;
}
let args;
try {
let response = await fetch("./data/object_with_two_searches.json");
args = await response.json();
}
catch (err) {
// Fail if we can't read the file, likely to occur in the browser
assert.ok(!err);
}
let name = "delete-me-" + getNextId();
let that = this;
let dataModel = await that.dataModels.create(name, args);
assert.ok(dataModel.hasObject("search1"));
assert.ok(dataModel.hasObject("search2"));
let search1 = dataModel.objectByName("search1");
assert.ok(search1);
assert.strictEqual(decodeURI("%E2%80%A1%C3%98%C2%B5%E2%80%A1%C3%98%C2%B1%E2%80%A1%C3%98%E2%88%9E%E2%80%A1%C3%98%C3%98%20-%20search%201"), search1.displayName);
let search2 = dataModel.objectByName("search2");
assert.ok(search2);
assert.strictEqual(decodeURI("%E2%80%A1%C3%98%C2%B5%E2%80%A1%C3%98%C2%B1%E2%80%A1%C3%98%E2%88%9E%E2%80%A1%C3%98%C3%98%20-%20search%202"), search2.displayName);
});
it("DataModels - data model handles unicode characters", async function () {
if (this.skip) {
return;
}
let args;
try {
let response = await fetch("./data/model_with_unicode_headers.json");
args = await response.json();
}
catch (err) {
// Fail if we can't read the file, likely to occur in the browser
assert.ok(!err);
}
let name = "delete-me-" + getNextId();
let that = this;
let dataModel = await that.dataModels.create(name, args);
assert.strictEqual(name, dataModel.name);
assert.strictEqual(decodeURI("%C2%B7%C3%84%C2%A9%C2%B7%C3%B6%C3%B4%E2%80%A1%C3%98%C2%B5"), dataModel.displayName);
assert.strictEqual(decodeURI("%E2%80%A1%C3%98%C2%B5%E2%80%A1%C3%98%C2%B1%E2%80%A1%C3%98%E2%88%9E%E2%80%A1%C3%98%C3%98"), dataModel.description);
});
it("DataModels - create data model with empty headers", async function () {
if (this.skip) {
return;
}
let args;
try {
let response = await fetch("./data/model_with_empty_headers.json");
args = await response.json();
}
catch (err) {
// Fail if we can't read the file, likely to occur in the browser
assert.ok(!err);
}
let name = "delete-me-" + getNextId();
let that = this;
let dataModel = await that.dataModels.create(name, args);
assert.strictEqual(name, dataModel.name);
assert.strictEqual("", dataModel.displayName);
assert.strictEqual("", dataModel.description);
// Make sure we're not getting a summary of the data model
assert.strictEqual("0", dataModel.concise);
});
it("DataModels - test acceleration settings", async function () {
if (this.skip) {
return;
}
let args;
try {
let response = await fetch("./data/data_model_with_test_objects.json");
args = await response.json();
}
catch (err) {
// Fail if we can't read the file, likely to occur in the browser
assert.ok(!err);
}