Repository: tez Updated Branches: refs/heads/master f70aa172e -> c5ad13ed5
TEZ-3254. Tez UI: Consider downloading Hive/Pig explain plans (sree) Project: http://git-wip-us.apache.org/repos/asf/tez/repo Commit: http://git-wip-us.apache.org/repos/asf/tez/commit/c5ad13ed Tree: http://git-wip-us.apache.org/repos/asf/tez/tree/c5ad13ed Diff: http://git-wip-us.apache.org/repos/asf/tez/diff/c5ad13ed Branch: refs/heads/master Commit: c5ad13ed51878b65927e306eb3196f802cf83e4b Parents: f70aa17 Author: Sreenath Somarajapuram <[email protected]> Authored: Tue May 17 16:57:53 2016 +0530 Committer: Sreenath Somarajapuram <[email protected]> Committed: Tue May 17 16:57:53 2016 +0530 ---------------------------------------------------------------------- CHANGES.txt | 1 + tez-ui/src/main/webapp/app/controllers/dags.js | 6 +- tez-ui/src/main/webapp/app/entities/dag.js | 6 +- tez-ui/src/main/webapp/app/models/dag.js | 3 +- tez-ui/src/main/webapp/app/routes/dag/index.js | 22 +++- tez-ui/src/main/webapp/app/routes/dags.js | 3 + tez-ui/src/main/webapp/app/serializers/dag.js | 30 ++++-- .../src/main/webapp/app/templates/dag/index.hbs | 4 +- .../main/webapp/app/utils/download-dag-zip.js | 40 +++++-- .../main/webapp/tests/unit/entities/dag-test.js | 107 +++++++++++++++++++ .../main/webapp/tests/unit/models/dag-test.js | 19 ++++ .../webapp/tests/unit/routes/dag/index-test.js | 32 ++++++ .../main/webapp/tests/unit/routes/dags-test.js | 22 ++++ .../webapp/tests/unit/serializers/dag-test.js | 80 ++++++++++++++ 14 files changed, 343 insertions(+), 32 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index d319eb8..04cada7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -29,6 +29,7 @@ ALL CHANGES: TEZ-3227. Tez UI: Replace UI1 with UI2 TEZ-3233. Tez UI: Have LLAP information reflect in Tez UI TEZ-3086. Tez UI: Backward compatibility changes + TEZ-3254. Tez UI: Consider downloading Hive/Pig explain plans Release 0.8.4: Unreleased http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/app/controllers/dags.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/controllers/dags.js b/tez-ui/src/main/webapp/app/controllers/dags.js index b35c693..a25ffa3 100644 --- a/tez-ui/src/main/webapp/app/controllers/dags.js +++ b/tez-ui/src/main/webapp/app/controllers/dags.js @@ -137,9 +137,9 @@ export default TableController.extend({ headerTitle: 'Caller ID', contentPath: 'callerID' },{ - id: 'callerType', - headerTitle: 'Caller Type', - contentPath: 'callerType' + id: 'callerContext', + headerTitle: 'Caller Context', + contentPath: 'callerContext' },{ id: 'logs', headerTitle: 'Logs', http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/app/entities/dag.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/entities/dag.js b/tez-ui/src/main/webapp/app/entities/dag.js index 80862b7..0befc8d 100644 --- a/tez-ui/src/main/webapp/app/entities/dag.js +++ b/tez-ui/src/main/webapp/app/entities/dag.js @@ -21,14 +21,14 @@ import Entity from './entity'; export default Entity.extend({ queryRecord: function (loader, id, options, query, urlParams) { return this._super(loader, id, options, query, urlParams).then(function (dag) { - if(!dag.get("callerInfo")) { + if(dag.get("callerDescription") === undefined) { var dagName = dag.get("name") || "", hiveQueryID = dagName.substr(0, dagName.indexOf(":")); if(hiveQueryID && dagName !== hiveQueryID) { loader.queryRecord("hive-query", hiveQueryID, options, query, urlParams).then(function (hive) { dag.setProperties({ - callerType: "Hive", - callerInfo: hive.get("queryText") + callerContext: "Hive", + callerDescription: hive.get("queryText") }); }); } http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/app/models/dag.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/models/dag.js b/tez-ui/src/main/webapp/app/models/dag.js index fc7cacd..84509e1 100644 --- a/tez-ui/src/main/webapp/app/models/dag.js +++ b/tez-ui/src/main/webapp/app/models/dag.js @@ -65,8 +65,9 @@ export default AMTimelineModel.extend({ vertexIdNameMap: DS.attr("object"), callerID: DS.attr("string"), + callerContext: DS.attr("string"), + callerDescription: DS.attr("string"), callerType: DS.attr("string"), - callerInfo: DS.attr("string"), amWsVersion: DS.attr("string"), }); http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/app/routes/dag/index.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/routes/dag/index.js b/tez-ui/src/main/webapp/app/routes/dag/index.js index acabc58..0bf01b2 100644 --- a/tez-ui/src/main/webapp/app/routes/dag/index.js +++ b/tez-ui/src/main/webapp/app/routes/dag/index.js @@ -35,13 +35,33 @@ export default SingleAmPollsterRoute.extend({ return this.get("loader").queryRecord('dag', this.modelFor("dag").get("id"), options); }, + getCallerInfo: function (dag) { + var dagName = dag.get("name") || "", + callerType = dag.get("callerType"), + callerID = dag.get("callerID"); + + if(!callerID || !callerType) { + let hiveQueryID = dagName.substr(0, dagName.indexOf(":")); + if(hiveQueryID && dagName !== hiveQueryID) { + callerType = "HIVE_QUERY_ID"; + callerID = hiveQueryID; + } + } + + return { + type: callerType, + id: callerID + }; + }, + actions: { downloadDagJson: function () { var dag = this.get("loadedValue"), downloader = downloadDAGZip(dag, { batchSize: 500, timelineHost: this.get("hosts.timeline"), - timelineNamespace: this.get("env.app.namespaces.webService.timeline") + timelineNamespace: this.get("env.app.namespaces.webService.timeline"), + callerInfo: this.getCallerInfo(dag) }), modalContent = Ember.Object.create({ dag: dag, http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/app/routes/dags.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/routes/dags.js b/tez-ui/src/main/webapp/app/routes/dags.js index 33366c8..2247637 100644 --- a/tez-ui/src/main/webapp/app/routes/dags.js +++ b/tez-ui/src/main/webapp/app/routes/dags.js @@ -161,6 +161,9 @@ export default AbstractRoute.extend({ var loader = this.get("loader"); loader.unloadAll("dag"); loader.unloadAll("ahs-app"); + + this.set("controller.pageNum", 1); + this._super(); }, } http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/app/serializers/dag.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/serializers/dag.js b/tez-ui/src/main/webapp/app/serializers/dag.js index 39832b2..a64bfe1 100644 --- a/tez-ui/src/main/webapp/app/serializers/dag.js +++ b/tez-ui/src/main/webapp/app/serializers/dag.js @@ -127,32 +127,40 @@ export default TimelineSerializer.extend({ vertexIdNameMap: getIdNameMap, callerID: 'primaryfilters.callerId.0', + callerContext: 'callerContext', + callerDescription: 'callerDescription', callerType: 'callerType', - callerInfo: 'callerInfo', amWsVersion: 'otherinfo.amWebServiceVersion', }, - extractAttributes: function (modelClass, resourceHash) { + normalizeResourceHash: function (resourceHash) { var data = resourceHash.data, dagInfo = Ember.get(resourceHash, "data.otherinfo.dagPlan.dagInfo"), // New style, from TEZ-2851 dagContext = Ember.get(resourceHash, "data.otherinfo.dagPlan.dagContext"); // Old style - if(dagInfo) { + if(dagContext) { + data.callerContext = Ember.String.classify((Ember.get(dagContext, "context")||"").toLowerCase()); + data.callerDescription = Ember.get(dagContext, "description"); + data.callerType = Ember.get(dagContext, "callerType"); + } + else if(dagInfo) { let infoObj = {}; try{ infoObj = JSON.parse(dagInfo); - }catch(e){} + }catch(e){ + infoObj = dagInfo; + } - data.callerType = Ember.get(infoObj, "context"); - data.callerInfo = Ember.get(infoObj, "description") || Ember.get(dagInfo, "blob") || dagInfo; - } - else if(dagContext) { - data.callerType = Ember.String.classify((Ember.get(dagContext, "context")||"").toLowerCase()); - data.callerInfo = Ember.get(dagContext, "description"); + data.callerContext = Ember.get(infoObj, "context"); + data.callerDescription = Ember.get(infoObj, "description") || Ember.get(dagInfo, "blob") || dagInfo; } - return this._super(modelClass, resourceHash); + return resourceHash; + }, + + extractAttributes: function (modelClass, resourceHash) { + return this._super(modelClass, this.normalizeResourceHash(resourceHash)); }, }); http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/app/templates/dag/index.hbs ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/templates/dag/index.hbs b/tez-ui/src/main/webapp/app/templates/dag/index.hbs index baba162..6a47dbe 100644 --- a/tez-ui/src/main/webapp/app/templates/dag/index.hbs +++ b/tez-ui/src/main/webapp/app/templates/dag/index.hbs @@ -80,8 +80,8 @@ {{outlet}} - {{#if model.callerInfo}} - {{caller-info type=model.callerType info=model.callerInfo}} + {{#if model.callerDescription}} + {{caller-info type=model.callerContext info=model.callerDescription}} {{/if}} {{#if model.diagnostics}} http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/app/utils/download-dag-zip.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/utils/download-dag-zip.js b/tez-ui/src/main/webapp/app/utils/download-dag-zip.js index eeb20ac..9c91a92 100644 --- a/tez-ui/src/main/webapp/app/utils/download-dag-zip.js +++ b/tez-ui/src/main/webapp/app/utils/download-dag-zip.js @@ -128,9 +128,15 @@ var IO = { processNext(); }).fail(function(xhr, statusText/*, errorObject*/) { delete pendingRequests[reqID]; - markFailed(statusText); inProgress--; - checkForCompletion(); + if(item.onItemFail) { + item.onItemFail(); + processNext(); + } + else { + markFailed(statusText); + checkForCompletion(); + } }); } @@ -288,22 +294,34 @@ export default function downloadDagZip(dag, options) { onItemFetched: processSingleItem }, { - url: getUrl('TEZ_VERTEX_ID', dagID), + url: getUrl('TEZ_VERTEX_ID', null, dagID), context: { name: 'vertices', type: 'TEZ_VERTEX_ID', part: 0 }, onItemFetched: processMultipleItems }, { - url: getUrl('TEZ_TASK_ID', dagID), + url: getUrl('TEZ_TASK_ID', null, dagID), context: { name: 'tasks', type: 'TEZ_TASK_ID', part: 0 }, onItemFetched: processMultipleItems }, { - url: getUrl('TEZ_TASK_ATTEMPT_ID', dagID), + url: getUrl('TEZ_TASK_ATTEMPT_ID', null, dagID), context: { name: 'task_attempts', type: 'TEZ_TASK_ATTEMPT_ID', part: 0 }, onItemFetched: processMultipleItems } - ], - totalItemsToDownload = itemsToDownload.length, + ]; + + let callerID = options.callerInfo.id, + entityType = options.callerInfo.type; + if(callerID && entityType) { + itemsToDownload.push({ + url: getUrl(entityType, callerID), + context: { name: entityType.toLocaleLowerCase(), type: entityType }, + onItemFetched: processSingleItem, + onItemFail: checkIfAllDownloaded + }); + } + + var totalItemsToDownload = itemsToDownload.length, numItemTypesToDownload = totalItemsToDownload, downloader = IO.fileDownloader(), zipHelper = IO.zipHelper({ @@ -323,12 +341,12 @@ export default function downloadDagZip(dag, options) { } }); - function getUrl(type, dagID, fromID) { + function getUrl(type, id, dagID, fromID) { var url, queryBatchSize = batchSize + 1; - if (type === 'TEZ_DAG_ID' || type === 'TEZ_APPLICATION') { - url = `${baseurl}/${type}/${dagID}`; + if (id) { + url = `${baseurl}/${type}/${id}`; } else { url = `${baseurl}/${type}?primaryFilter=TEZ_DAG_ID:${dagID}&limit=${queryBatchSize}`; if (!!fromID) { @@ -376,7 +394,7 @@ export default function downloadDagZip(dag, options) { if (!!nextBatchStart) { context.part++; downloader.queueItem({ - url: getUrl(context.type, dagID, nextBatchStart), + url: getUrl(context.type, null, dagID, nextBatchStart), context: context, onItemFetched: processMultipleItems }); http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/tests/unit/entities/dag-test.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/tests/unit/entities/dag-test.js b/tez-ui/src/main/webapp/tests/unit/entities/dag-test.js index 5410ae2..f48ad3a 100644 --- a/tez-ui/src/main/webapp/tests/unit/entities/dag-test.js +++ b/tez-ui/src/main/webapp/tests/unit/entities/dag-test.js @@ -16,6 +16,7 @@ * limitations under the License. */ +import Ember from 'ember'; import { moduleFor, test } from 'ember-qunit'; moduleFor('entitie:dag', 'Unit | Entity | dag', { @@ -26,4 +27,110 @@ moduleFor('entitie:dag', 'Unit | Entity | dag', { test('Basic creation test', function(assert) { let entity = this.subject(); assert.ok(entity); + assert.ok(entity.queryRecord); +}); + +test('queryRecord-Hive:No description test', function(assert) { + let testQuery = "testQuery", + entityName = "entity-name", + testDag = Ember.Object.create({ + name: "testName:1" + }), + hiveQuery = Ember.Object.create({ + queryText: testQuery + }), + store = { + queryRecord: function (name) { + assert.equal(name, entityName); + return Ember.RSVP.resolve(testDag); + } + }, + loader = Ember.Object.create({ + nameSpace: "ns", + queryRecord: function (type, id/*, options, query, urlParams*/) { + assert.equal(type, "hive-query"); + assert.equal(id, "testName"); + return Ember.RSVP.resolve(hiveQuery); + } + }), + entity = this.subject({ + name: entityName, + store: store + }); + + assert.expect(1 + 2 + 3); + + entity.queryRecord(loader).then(function (dag) { + assert.equal(testDag, dag); + assert.equal(testDag.get("callerContext"), "Hive"); + assert.equal(testDag.get("callerDescription"), testQuery); + }); +}); + +test('queryRecord-Not Hive:No description test', function(assert) { + let testQuery = "testQuery", + entityName = "entity-name", + testDag = Ember.Object.create({ + name: "testName" + }), + hiveQuery = Ember.Object.create({ + queryText: testQuery + }), + store = { + queryRecord: function (name) { + assert.equal(name, entityName); + return Ember.RSVP.resolve(testDag); + } + }, + loader = Ember.Object.create({ + nameSpace: "ns", + queryRecord: function (/*type, id, options, query, urlParams*/) { + assert.ok(false); + return Ember.RSVP.resolve(hiveQuery); + } + }), + entity = this.subject({ + name: entityName, + store: store + }); + + assert.expect(1 + 3); + + entity.queryRecord(loader).then(function (dag) { + assert.equal(testDag, dag); + assert.ok(!testDag.get("callerContext")); + assert.ok(!testDag.get("callerDescription")); + }); +}); + +test('queryRecord-With description test', function(assert) { + let testQuery = "testQuery", + entityName = "entity-name", + testDag = Ember.Object.create({ + name: "testName", + callerDescription: testQuery + }), + loader = Ember.Object.create({ + nameSpace: "ns", + queryRecord: function (/*type, id, options, query, urlParams*/) { + assert.ok(false); + } + }), + store = { + queryRecord: function (name) { + assert.equal(name, entityName); + return Ember.RSVP.resolve(testDag); + } + }, + entity = this.subject({ + name: entityName, + store: store + }); + + assert.expect(1 + 2); + + entity.queryRecord(loader).then(function (dag) { + assert.equal(testDag, dag); + assert.equal(testDag.get("callerDescription"), testQuery); + }); }); http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/tests/unit/models/dag-test.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/tests/unit/models/dag-test.js b/tez-ui/src/main/webapp/tests/unit/models/dag-test.js index 513af7d..78affcf 100644 --- a/tez-ui/src/main/webapp/tests/unit/models/dag-test.js +++ b/tez-ui/src/main/webapp/tests/unit/models/dag-test.js @@ -37,4 +37,23 @@ test('Basic creation test', function(assert) { assert.ok(!!model.needs.am); assert.equal(model.get("queue"), testQueue); }); + + assert.ok(model.name); + assert.ok(model.submitter); + + assert.ok(model.vertices); + assert.ok(model.edges); + assert.ok(model.vertexGroups); + + assert.ok(model.domain); + assert.ok(model.containerLogs); + + assert.ok(model.vertexIdNameMap); + + assert.ok(model.callerID); + assert.ok(model.callerContext); + assert.ok(model.callerDescription); + assert.ok(model.callerType); + + assert.ok(model.amWsVersion); }); http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/tests/unit/routes/dag/index-test.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/tests/unit/routes/dag/index-test.js b/tez-ui/src/main/webapp/tests/unit/routes/dag/index-test.js index 8c0cb5d..b7ee27f 100644 --- a/tez-ui/src/main/webapp/tests/unit/routes/dag/index-test.js +++ b/tez-ui/src/main/webapp/tests/unit/routes/dag/index-test.js @@ -16,6 +16,7 @@ * limitations under the License. */ +import Ember from 'ember'; import { moduleFor, test } from 'ember-qunit'; moduleFor('route:dag/index', 'Unit | Route | dag/index', { @@ -31,6 +32,7 @@ test('Basic creation test', function(assert) { assert.ok(route.loaderNamespace); assert.ok(route.setupController); assert.ok(route.load); + assert.ok(route.getCallerInfo); }); test('setupController test', function(assert) { @@ -45,3 +47,33 @@ test('setupController test', function(assert) { route.setupController({}, {}); }); +test('getCallerInfo test', function(assert) { + let route = this.subject({ + startCrumbBubble: Ember.K + }), + + testID = "id", + testType = "entity", + + dag = Ember.Object.create({ + name: "hive_query_id:1", + }), + callerInfo; + + // callerID computed - No callerType + callerInfo = route.getCallerInfo(dag); + assert.equal(callerInfo.id, "hive_query_id"); + assert.equal(callerInfo.type, "HIVE_QUERY_ID"); + + // callerID computed - No callerID + dag.set("callerType", testType); + callerInfo = route.getCallerInfo(dag); + assert.equal(callerInfo.id, "hive_query_id"); + assert.equal(callerInfo.type, "HIVE_QUERY_ID"); + + // callerID & callerType available + dag.set("callerID", testID); + callerInfo = route.getCallerInfo(dag); + assert.equal(callerInfo.id, testID); + assert.equal(callerInfo.type, testType); +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/tests/unit/routes/dags-test.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/tests/unit/routes/dags-test.js b/tez-ui/src/main/webapp/tests/unit/routes/dags-test.js index dfa8223..39a3300 100644 --- a/tez-ui/src/main/webapp/tests/unit/routes/dags-test.js +++ b/tez-ui/src/main/webapp/tests/unit/routes/dags-test.js @@ -130,3 +130,25 @@ test('loadNewPage test', function(assert) { route.loadNewPage(); }); + +test('actions.willTransition test', function(assert) { + let testPageNum = 5, + controller = Ember.Object.create({ + pageNum: testPageNum + }), + route = this.subject({ + controller: controller, + }); + + route.set("loader", { + unloadAll: function () { + assert.ok(true); + } + }); + + assert.expect(2 + 1 + 1); + + assert.equal(controller.get("pageNum"), testPageNum); + route.send("willTransition"); + assert.equal(controller.get("pageNum"), 1); // PageNum must be reset +}); http://git-wip-us.apache.org/repos/asf/tez/blob/c5ad13ed/tez-ui/src/main/webapp/tests/unit/serializers/dag-test.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/tests/unit/serializers/dag-test.js b/tez-ui/src/main/webapp/tests/unit/serializers/dag-test.js index eb39508..7df4084 100644 --- a/tez-ui/src/main/webapp/tests/unit/serializers/dag-test.js +++ b/tez-ui/src/main/webapp/tests/unit/serializers/dag-test.js @@ -27,6 +27,9 @@ test('Basic creation test', function(assert) { let serializer = this.subject(); assert.ok(serializer); + + assert.ok(serializer.normalizeResourceHash); + assert.ok(serializer.maps.atsStatus); assert.ok(serializer.maps.startTime); assert.ok(serializer.maps.endTime); @@ -129,3 +132,80 @@ test('vertexIdNameMap test', function(assert) { ID3: "name3", }); }); + +test('normalizeResourceHash test', function(assert) { + let serializer = this.subject(), + + callerInfo = { + callerId: "id_1", + callerType: "HIVE_QUERY_ID", + context: "Hive", + description: "hive query" + }, + + data; + + // dagContext test + data = serializer.normalizeResourceHash({ + data: { + otherinfo: { + dagPlan: { + dagContext: callerInfo + } + } + } + }).data; + + assert.equal(data.callerContext, callerInfo.context); + assert.equal(data.callerDescription, callerInfo.description); + assert.equal(data.callerType, callerInfo.callerType); + + // dagInfo test + data = serializer.normalizeResourceHash({ + data: { + otherinfo: { + dagPlan: { + dagInfo: `{"context": "${callerInfo.context}", "description": "${callerInfo.description}"}` + } + } + } + }).data; + + assert.equal(data.callerContext, callerInfo.context); + assert.equal(data.callerDescription, callerInfo.description); + assert.notOk(data.callerType); + + // dagInfo.blob test + data = serializer.normalizeResourceHash({ + data: { + otherinfo: { + dagPlan: { + dagInfo: { + context: callerInfo.context, + blob: callerInfo.description + } + } + } + } + }).data; + + assert.equal(data.callerContext, callerInfo.context); + assert.equal(data.callerDescription, callerInfo.description); + assert.notOk(data.callerType); + + // dagContext have presidence over dagInfo + data = serializer.normalizeResourceHash({ + data: { + otherinfo: { + dagPlan: { + dagContext: callerInfo, + dagInfo: `{"context": "RandomContext", "description": "RandomDesc"}` + } + } + } + }).data; + + assert.equal(data.callerContext, callerInfo.context); + assert.equal(data.callerDescription, callerInfo.description); + assert.equal(data.callerType, callerInfo.callerType); +});
