UNPKG

splunk-sdk

Version:

SDK for usage with the Splunk REST API

1,198 lines (1,092 loc) 213 kB
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); }