'use strict';goog.provide("grrUi.tests");goog.provide("grrUi.tests.browserTriggerEvent");goog.provide("grrUi.tests.browserTriggerKeyDown");goog.provide("grrUi.tests.stubDirective");goog.provide("grrUi.tests.stubTranscludeDirective");goog.provide("grrUi.tests.stubUiTrait");goog.provide("grrUi.tests.testsModule");grrUi.tests.testsModule=angular.module("grrUi.tests",["ng","ui.bootstrap"]);var $animate;beforeEach(module("ngAnimateMock"));
grrUi.tests.testsModule.config(function($interpolateProvider,$qProvider,$uibModalProvider){$interpolateProvider.startSymbol("{$");$interpolateProvider.endSymbol("$}");$qProvider.errorOnUnhandledRejections(false);$uibModalProvider.options.animation=false}).run(function($injector){$animate=$injector.get("$animate")});
beforeEach(function(){module("grrUi.tests");var grrRoutingServiceMock={go:function(state,params){},href:function(state,params){return"#test/href"},uiOnParamsChanged:function(scope,paramNames,callback){},onStateChange:function(scope,callback){}};module(function($provide){$provide.factory("grrRoutingService",function(){return grrRoutingServiceMock})})});
grrUi.tests.browserTriggerEvent=function(element,eventType){if(element.injector)element=element[0];else if(element.prevObject)element=element[0];if(eventType==="change"){$(element).triggerHandler("change");if(element.type==="checkbox")$(element).triggerHandler("click")}else if(document.createEvent){var event=document.createEvent("MouseEvents");if(eventType==="mouseenter")eventType="mouseover";if(eventType==="mouseleave")eventType="mouseout";event.initMouseEvent(eventType,true,true,window,0,0,0,0,
0,false,false,false,false,0,null);element.dispatchEvent(event)}else element.fireEvent("on"+eventType);$animate.flush(true)};grrUi.tests.browserTriggerKeyDown=function(element,keyCode){var event=jQuery.Event("keypress");event.which=keyCode;element.trigger(event)};var directiveStubCounter=0;
grrUi.tests.stubDirective=function(directiveName){var moduleName="test.directives.stubs."+directiveStubCounter;directiveStubCounter+=1;angular.module(moduleName,[]).directive(directiveName,function(){return{priority:1E5+directiveStubCounter,terminal:true}});beforeEach(module(moduleName))};
grrUi.tests.stubTranscludeDirective=function(directiveName){var moduleName="test.directives.stubs."+directiveStubCounter;directiveStubCounter+=1;angular.module(moduleName,[]).directive(directiveName,function(){return{restrict:"E",scope:{},transclude:true,priority:1E5+directiveStubCounter,terminal:true,link:function($scope,$element,$attrs,controller,$transclude){function ngTranscludeCloneAttachFn(clone){if(clone.length){$element.empty();$element.append(clone)}}$transclude(ngTranscludeCloneAttachFn,
null,null)}}});beforeEach(module(moduleName))};
grrUi.tests.stubUiTrait=function(traitName){beforeEach(inject(function($injector){const $q=$injector.get("$q");const grrApiService=$injector.get("grrApiService");var deferred=$q.defer();var response={data:{value:{interface_traits:{value:{}}}}};response["data"]["value"]["interface_traits"]["value"][traitName]={value:true};deferred.resolve(response);var currentImpl=grrApiService.getCached;spyOn(grrApiService,"getCached").and.callFake(function(url,params){if(url=="users/me")return deferred.promise;else return currentImpl(url,
params)})}))};goog.loadModule(function(exports){"use strict";goog.module("grrUi.acl.requestApprovalDialogDirectiveTest");goog.setTestOnly();const {aclModule}=goog.require("grrUi.acl.acl");const {browserTriggerEvent,testsModule,stubDirective}=goog.require("grrUi.tests");describe("request approval dialog",()=>{let $compile;let $q;let $rootScope;let closeSpy;let dismissSpy;let grrApiService;beforeEach(module("/static/angular-components/acl/"+"request-approval-dialog.html"));beforeEach(module("/static/angular-components/core/"+
"confirmation-dialog.html"));beforeEach(module(aclModule.name));beforeEach(module(testsModule.name));stubDirective("grrApproverInput");beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService");closeSpy=jasmine.createSpy("close");dismissSpy=jasmine.createSpy("dismiss")}));const renderTestTemplate=(approvalType,createUrl,createArgs,description)=>{$rootScope.approvalType=approvalType;$rootScope.createUrl=
createUrl;$rootScope.createArgs=createArgs;$rootScope.description=description;$rootScope.$close=closeSpy;$rootScope.$dismiss=dismissSpy;const template="<grr-request-approval-dialog "+'approval-type="approvalType" '+'create-request-url="createUrl" '+'create-request-args="createArgs" '+'access-error-description="description" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};const setApproverInput=(element,value)=>{const valueElement=element.find("grr-approver-input");
const valueAttr=valueElement.attr("ng-model");const expression=`${valueAttr} = "${value}"`;valueElement.scope().$eval(expression)};let approvals;let clientApprovalRequest;let configEntry;beforeEach(()=>{clientApprovalRequest={client_id:"C:123456",approval:{}};approvals={data:{items:[{type:"ApiClientApproval",value:{reason:{type:"RDFString",value:"reason1"}}},{type:"ApiClientApproval",value:{reason:{type:"RDFString",value:"reason2"}}}]}};configEntry={data:{value:{type:"RDFString",value:"foo@bar.com, xyz@example.com"}}};
let deferred=$q.defer();deferred.resolve(configEntry);spyOn(grrApiService,"getCached").and.returnValue(deferred.promise);deferred=$q.defer();deferred.resolve(approvals);spyOn(grrApiService,"get").and.returnValue(deferred.promise)});it("shows a list of previous client reasons",()=>{const element=renderTestTemplate("client");expect($("select option",element).length).toBe(3);expect($("select option:nth(0)",element).val()).toEqual("");expect($("select option:nth(1)",element).val()).toEqual("reason1");
expect($("select option:nth(2)",element).val()).toEqual("reason2")});it("doesn't show a list of CC addresses when not available",()=>{configEntry["data"]["value"]["value"]=undefined;const element=renderTestTemplate("client");expect(element.text()).not.toContain("CC");expect($("input[name=cc_approval]",element).length).toBe(0)});it("shows a list of CC addresses when they're available",()=>{const element=renderTestTemplate("client");expect(element.text()).toContain("CC foo@bar.com, xyz@example.com");
expect($("input[name=cc_approval]",element).length).toBe(1)});it("disables reason field when dropdown reason is selected",()=>{const element=renderTestTemplate("client");$("select",element).val("reason1");browserTriggerEvent($("select",element),"change");expect($("input[name=acl_reason]",element).attr("disabled")).toBeTruthy()});it('doesn\'t show keep-alive checkbox for "hunt"approval type',()=>{const element=renderTestTemplate("hunt");expect($("input[name=keepalive]",element).length).toBe(0)});it('shows keep-alive checkbox for "client" approval type',
()=>{const element=renderTestTemplate("client");expect($("input[name=keepalive]",element).length).toBe(1)});it("includes approvers into request if CC-checbox is selected",()=>{spyOn(grrApiService,"post").and.returnValue($q.defer().promise);const element=renderTestTemplate("client","foo/bar",clientApprovalRequest);setApproverInput(element,"foo");$("input[name=acl_reason]",element).val("bar");browserTriggerEvent($("input[name=acl_reason]",element),"change");$("input[name=cc_approval]",element).prop("checked",
true);browserTriggerEvent($("input[name=cc_approval]",element),"change");browserTriggerEvent($("button[name=Proceed]",element),"click");expect(grrApiService.post).toHaveBeenCalledWith("foo/bar",{client_id:"C:123456",approval:{reason:"bar",notified_users:["foo"],email_cc_addresses:["foo@bar.com","xyz@example.com"]},keep_client_alive:true})});it("includes keep_client_alive into request if checkbox is selected",()=>{spyOn(grrApiService,"post").and.returnValue($q.defer().promise);const element=renderTestTemplate("client",
"foo/bar",clientApprovalRequest);setApproverInput(element,"foo");$("input[name=acl_reason]",element).val("bar");browserTriggerEvent($("input[name=acl_reason]",element),"change");browserTriggerEvent($("input[name=cc_approval]",element).prop("checked",false),"change");browserTriggerEvent($("input[name=keepalive]",element).prop("checked",true),"change");browserTriggerEvent($("button[name=Proceed]",element),"click");expect(grrApiService.post).toHaveBeenCalledWith("foo/bar",{client_id:"C:123456",approval:{reason:"bar",
notified_users:["foo"]},keep_client_alive:true})});it("includes dropdown reason into request",()=>{spyOn(grrApiService,"post").and.returnValue($q.defer().promise);const element=renderTestTemplate("client","foo/bar",clientApprovalRequest);setApproverInput(element,"foo");$("input[name=acl_reason]",element).val("bar");browserTriggerEvent($("input[name=acl_reason]",element),"change");browserTriggerEvent($("input[name=cc_approval]",element).prop("checked",false),"change");$("select",element).val("reason2");
browserTriggerEvent($("select",element),"change");browserTriggerEvent($("button[name=Proceed]",element),"click");expect(grrApiService.post).toHaveBeenCalledWith("foo/bar",{client_id:"C:123456",approval:{reason:"reason2",notified_users:["foo"]},keep_client_alive:true})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.artifact.artifactDescriptorServiceTest");goog.setTestOnly();const {ArtifactDescriptorsService}=goog.require("grrUi.artifact.artifactDescriptorsService");const {artifactModule}=goog.require("grrUi.artifact.artifact");const {testsModule}=goog.require("grrUi.tests");describe("grrArtifactDescriptorsService service",()=>{let $q;let $rootScope;let grrApiServiceMock;let grrArtifactDescriptorsService;beforeEach(module(artifactModule.name));
beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiServiceMock={get:function(){}};grrArtifactDescriptorsService=$injector.instantiate(ArtifactDescriptorsService,{"grrApiService":grrApiServiceMock})}));const successResponse={data:{items:[{type:"ArtifactDescriptor",value:{artifact:{value:{name:{value:"foo"}}}}},{type:"ArtifactDescriptor",value:{artifact:{value:{name:{value:"bar"}}}}}]}};const failureResponse={data:{message:"Oh no!"}};
describe("listDescriptors()",()=>{it("resolves to a dictionary of descriptors on success",(done)=>{const deferred=$q.defer();deferred.resolve(successResponse);spyOn(grrApiServiceMock,"get").and.returnValue(deferred.promise);grrArtifactDescriptorsService.listDescriptors().then((descriptors)=>{expect(Object.keys(descriptors)).toEqual(["foo","bar"]);done()});$rootScope.$apply()});it("resolves to an error message on error",(done)=>{const deferred=$q.defer();deferred.reject(failureResponse);spyOn(grrApiServiceMock,
"get").and.returnValue(deferred.promise);grrArtifactDescriptorsService.listDescriptors().then(()=>{},(message)=>{expect(message).toBe("Oh no!");done()});$rootScope.$apply()});it("does not start more than one API requests",()=>{const deferred1=$q.defer();const deferred2=$q.defer();spyOn(grrApiServiceMock,"get").and.returnValues(deferred1.promise,deferred2.promise);grrArtifactDescriptorsService.listDescriptors();grrArtifactDescriptorsService.listDescriptors();expect(grrApiServiceMock.get.calls.count()).toBe(1)})});
describe("getDescriptorByName()",()=>{it("resolves to a descriptor",(done)=>{const deferred=$q.defer();deferred.resolve(successResponse);spyOn(grrApiServiceMock,"get").and.returnValue(deferred.promise);grrArtifactDescriptorsService.getDescriptorByName("foo").then((descriptor)=>{expect(descriptor).toEqual(successResponse.data.items[0]);done()});$rootScope.$apply()});it("resolves to undefined if descriptor not found",(done)=>{const deferred=$q.defer();deferred.resolve(successResponse);spyOn(grrApiServiceMock,
"get").and.returnValue(deferred.promise);grrArtifactDescriptorsService.getDescriptorByName("something").then((descriptor)=>{expect(descriptor).toBeUndefined();done()});$rootScope.$apply()});it("resolve to an error message in case of error",(done)=>{const deferred=$q.defer();deferred.reject(failureResponse);spyOn(grrApiServiceMock,"get").and.returnValue(deferred.promise);grrArtifactDescriptorsService.getDescriptorByName("something").then(()=>{},(message)=>{expect(message).toBe("Oh no!");done()});$rootScope.$apply()})});
describe("clearCache()",()=>{it("forces next listDescriptors call to do an API request",()=>{const deferred1=$q.defer();deferred1.resolve(successResponse);const deferred2=$q.defer();deferred2.resolve(successResponse);spyOn(grrApiServiceMock,"get").and.returnValues(deferred1.promise,deferred2.promise);grrArtifactDescriptorsService.listDescriptors();$rootScope.$apply();grrArtifactDescriptorsService.clearCache();grrArtifactDescriptorsService.listDescriptors();$rootScope.$apply();expect(grrApiServiceMock.get.calls.count()).toBe(2)})})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.artifact.artifactNameDirectiveTest");goog.setTestOnly();const {artifactModule}=goog.require("grrUi.artifact.artifact");const {testsModule}=goog.require("grrUi.tests");describe("grr-artifact-name directive",()=>{let $compile;let $q;let $rootScope;let grrArtifactDescriptorsService;beforeEach(module("/static/angular-components/artifact/artifact-name.html"));beforeEach(module(artifactModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>
{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrArtifactDescriptorsService=$injector.get("grrArtifactDescriptorsService")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-artifact-name value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};const systemDescriptor={type:"ArtifactDescriptor",value:{artifact:{value:{name:{value:"foo"}}},is_custom:{value:false}}};const userDescriptor=
{type:"ArtifactDescriptor",value:{artifact:{value:{name:{value:"foo"}}},is_custom:{value:true}}};it("shows artifact name as a string before it's resolved",()=>{const deferred=$q.defer();spyOn(grrArtifactDescriptorsService,"getDescriptorByName").and.returnValue(deferred.promise);const element=renderTestTemplate({value:"foo"});expect($("span.system",element).length).toBe(0);expect($("span.user",element).length).toBe(0);expect($("span.icon",element).length).toBe(0);expect(element.text()).toContain("foo")});
it("marks system artifacts with .system class and no icon",()=>{const deferred=$q.defer();deferred.resolve(systemDescriptor);spyOn(grrArtifactDescriptorsService,"getDescriptorByName").and.returnValue(deferred.promise);const element=renderTestTemplate({value:"foo"});expect($("span.system",element).length).toBe(1);expect($("span.user",element).length).toBe(0);expect($("span.icon",element).length).toBe(0);expect(element.text()).toContain("foo")});it("marks user artifacts with .user class and an icon",
()=>{const deferred=$q.defer();deferred.resolve(userDescriptor);spyOn(grrArtifactDescriptorsService,"getDescriptorByName").and.returnValue(deferred.promise);const element=renderTestTemplate({value:"foo"});expect($("span.system",element).length).toBe(0);expect($("span.user",element).length).toBe(1);expect(element.text()).toContain("foo")});it("does not mark unknown artifacts",()=>{const deferred=$q.defer();deferred.resolve(undefined);spyOn(grrArtifactDescriptorsService,"getDescriptorByName").and.returnValue(deferred.promise);
const element=renderTestTemplate({value:"foo"});expect($("span.system",element).length).toBe(0);expect($("span.user",element).length).toBe(0);expect($("span.icon",element).length).toBe(0);expect(element.text()).toContain("foo")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.artifact.artifactsListFormDirectiveTest");goog.setTestOnly();const {artifactModule}=goog.require("grrUi.artifact.artifact");const {browserTriggerEvent,stubDirective,testsModule}=goog.require("grrUi.tests");describe("artifacts list form directive",()=>{let $compile;let $q;let $rootScope;let grrArtifactDescriptorsService;let descriptorDarwinWindows;let descriptorLinux;beforeEach(module("/static/angular-components/artifact/artifacts-list-form.html"));
beforeEach(module(artifactModule.name));beforeEach(module(testsModule.name));stubDirective("grrSemanticValue");beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrArtifactDescriptorsService=$injector.get("grrArtifactDescriptorsService")}));const renderTestTemplate=(value)=>{$rootScope.value=value;$rootScope.descriptor={default:{type:"ArtifactName",value:""}};const template='<grr-artifacts-list-form descriptor="descriptor" '+
'value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('shows "Loading artifacts..." while artifacts are being loaded',()=>{const deferred=$q.defer();spyOn(grrArtifactDescriptorsService,"listDescriptors").and.returnValue(deferred.promise);const element=renderTestTemplate([]);expect(element.text()).toContain("Loading artifacts...")});describe("when descriptors listing fails",()=>{beforeEach(()=>{spyOn(grrArtifactDescriptorsService,"listDescriptors").and.callFake(()=>
{const deferred=$q.defer();deferred.reject("Oh no!");return deferred.promise})});it('hides "Loading artifacts..." message',()=>{const element=renderTestTemplate([]);expect(element.text()).not.toContain("Loading artifacts...")});it("shows a failure message on artifacts fetch failure",()=>{const element=renderTestTemplate([]);expect(element.text()).toContain("Oh no!")})});describe("when descriptors listing succeeds",()=>{beforeEach(()=>{descriptorLinux={type:"ArtifactDescriptor",value:{artifact:{type:"Artifact",
value:{name:{type:"ArtifactName",value:"FooLinux"},supported_os:[{type:"RDFString",value:"Linux"}]}}}};descriptorDarwinWindows={type:"ArtifactDescriptor",value:{artifact:{type:"Artifact",value:{name:{type:"ArtifactName",value:"BarDarwinWindows"},supported_os:[{type:"RDFString",value:"Darwin"},{type:"RDFString",value:"Windows"}]}}}};spyOn(grrArtifactDescriptorsService,"listDescriptors").and.callFake(()=>{const deferred=$q.defer();deferred.resolve({"FooLinux":descriptorLinux,"BarDarwinWindows":descriptorDarwinWindows});
return deferred.promise})});it('hides "Loading artifacts..." message',()=>{const element=renderTestTemplate([]);expect(element.text()).not.toContain("Loading artifacts...")});it("shows all artifacts for selection by default",()=>{const element=renderTestTemplate([]);expect(element.text()).toContain("FooLinux");expect(element.text()).toContain("BarDarwinWindows")});it("prefills selection list from model",()=>{const element=renderTestTemplate([{type:"ArtifactName",value:"FooLinux"}]);expect(element.find("table[name=SelectedArtifacts] "+
'tr:contains("FooLinux")').length).toBe(1)});it("filters artifacts by platform",()=>{const element=renderTestTemplate([]);browserTriggerEvent(element.find('a:contains("Darwin")'),"click");expect(element.text()).not.toContain("FooLinux");expect(element.text()).toContain("BarDarwinWindows");browserTriggerEvent(element.find('a:contains("Windows")'),"click");expect(element.text()).not.toContain("FooLinux");expect(element.text()).toContain("BarDarwinWindows");browserTriggerEvent(element.find('a:contains("Linux")'),
"click");expect(element.text()).toContain("FooLinux");expect(element.text()).not.toContain("BarDarwinWindows")});it("checks sources platform when filtering by platform",()=>{descriptorLinux={type:"ArtifactDescriptor",value:{artifact:{type:"Artifact",value:{name:{type:"ArtifactName",value:"FooLinux"},sources:[{type:"ArtifactSource",value:{supported_os:[{type:"RDFString",value:"Linux"}]}}]}}}};descriptorDarwinWindows={type:"ArtifactDescriptor",value:{artifact:{type:"Artifact",value:{name:{type:"ArtifactName",
value:"BarDarwinWindows"},sources:[{type:"ArtifactSource",value:{supported_os:[{type:"RDFString",value:"Darwin"},{type:"RDFString",value:"Windows"}]}}]}}}};const element=renderTestTemplate([]);browserTriggerEvent(element.find('a:contains("Darwin")'),"click");expect(element.text()).not.toContain("FooLinux");expect(element.text()).toContain("BarDarwinWindows");browserTriggerEvent(element.find('a:contains("Windows")'),"click");expect(element.text()).not.toContain("FooLinux");expect(element.text()).toContain("BarDarwinWindows");
browserTriggerEvent(element.find('a:contains("Linux")'),"click");expect(element.text()).toContain("FooLinux");expect(element.text()).not.toContain("BarDarwinWindows")});it("filters artifacts by name",()=>{const element=renderTestTemplate([]);element.find("input[name=Search]").val("bar");browserTriggerEvent(element.find("input[name=Search]"),"change");$rootScope.$apply();expect(element.text()).not.toContain("FooLinux");expect(element.text()).toContain("BarDarwinWindows")});it("shows artifact descriptor info for selected artifact",
()=>{const element=renderTestTemplate([]);let infoDirective;browserTriggerEvent(element.find('td:contains("FooLinux")'),"click");infoDirective=element.find("grr-semantic-value");expect(infoDirective.scope().$eval(infoDirective.attr("value"))).toEqual(descriptorLinux);browserTriggerEvent(element.find('td:contains("BarDarwinWindows")'),"click");infoDirective=element.find("grr-semantic-value");expect(infoDirective.scope().$eval(infoDirective.attr("value"))).toEqual(descriptorDarwinWindows)});it("picks the artifact when Add is pressed",
()=>{const element=renderTestTemplate([]);browserTriggerEvent(element.find("table[name=Artifacts] "+'td:contains("FooLinux")'),"click");browserTriggerEvent(element.find('button:contains("Add")'),"click");expect(element.find("table[name=Artifacts] "+'td:contains("FooLinux")').length).toBe(0);expect(element.find("table[name=SelectedArtifacts] "+'td:contains("FooLinux")').length).toBe(1)});it("picks the artifact on double click",()=>{const element=renderTestTemplate([]);browserTriggerEvent(element.find("table[name=Artifacts] "+
'td:contains("FooLinux")'),"dblclick");expect(element.find("table[name=Artifacts] "+'td:contains("FooLinux")').length).toBe(0);expect(element.find("table[name=SelectedArtifacts] "+'td:contains("FooLinux")').length).toBe(1)});it("updates the model when artifact is picked",()=>{const element=renderTestTemplate([]);browserTriggerEvent(element.find("table[name=Artifacts] "+'td:contains("FooLinux")'),"dblclick");expect(angular.equals($rootScope.value,[{type:"ArtifactName",value:"FooLinux"}]))});it("unpicks the artifact when Remove is pressed",
()=>{const element=renderTestTemplate([{type:"ArtifactName",value:"FooLinux"}]);browserTriggerEvent(element.find("table[name=SelectedArtifacts] "+'td:contains("FooLinux")'),"click");browserTriggerEvent(element.find('button:contains("Remove")'),"click");expect(element.find("table[name=Artifacts] "+'td:contains("FooLinux")').length).toBe(1);expect(element.find("table[name=SelectedArtifacts] "+'td:contains("FooLinux")').length).toBe(0)});it("unpicks the artifact on double click",()=>{const element=renderTestTemplate([{type:"ArtifactName",
value:"FooLinux"}]);browserTriggerEvent(element.find("table[name=SelectedArtifacts] "+'td:contains("FooLinux")'),"dblclick");expect(element.find("table[name=Artifacts] "+'td:contains("FooLinux")').length).toBe(1);expect(element.find("table[name=SelectedArtifacts] "+'td:contains("FooLinux")').length).toBe(0)});it("updates the model when artifact is unpicked",()=>{const element=renderTestTemplate([{type:"ArtifactName",value:"FooLinux"}]);browserTriggerEvent(element.find("table[name=SelectedArtifacts] "+
'td:contains("FooLinux")'),"dblclick");expect(angular.equals($rootScope.value,[]))});it("clears list of picked artifacts when Clear is pressed",()=>{const element=renderTestTemplate([{type:"ArtifactName",value:"FooLinux"},{type:"ArtifactName",value:"BarDarwinWindows"}]);browserTriggerEvent(element.find('button:contains("Clear")'),"click");expect(element.find("table[name=SelectedArtifacts] "+'td:contains("FooLinux")').length).toBe(0);expect(element.find("table[name=SelectedArtifacts] "+'td:contains("BarDarwinWindows")').length).toBe(0)});
it("updates the model when selection list is cleared",()=>{const element=renderTestTemplate([{type:"ArtifactName",value:"FooLinux"},{type:"ArtifactName",value:"BarDarwinWindows"}]);browserTriggerEvent(element.find('button:contains("Clear")'),"click");expect(angular.equals($rootScope.value,[]))})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.addClientsLabelsDialogDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {clientModule}=goog.require("grrUi.client.client");describe("add clients labels dialog",()=>{let $compile;let $q;let $rootScope;let closeSpy;let dismissSpy;let grrApiService;beforeEach(module("/static/angular-components/client/"+"add-clients-labels-dialog.html"));beforeEach(module("/static/angular-components/core/"+
"confirmation-dialog.html"));beforeEach(module("/static/angular-components/semantic/"+"client-urn.html"));beforeEach(module(clientModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService");closeSpy=jasmine.createSpy("close");dismissSpy=jasmine.createSpy("dismiss")}));const clients=[{type:"ApiClient",value:{urn:{value:"aff4:/C.0000111122223333",
type:"RDFURN"},client_id:{value:"C.0000111122223333",type:"ApiClientId"}}},{type:"ApiClient",value:{urn:{value:"aff4:/C.1111222233334444",type:"RDFURN"},client_id:{value:"C.1111222233334444",type:"ApiClientId"}}}];const renderTestTemplate=(clients)=>{$rootScope.clients=clients;$rootScope.$close=closeSpy;$rootScope.$dismiss=dismissSpy;const template="<grr-add-clients-labels-dialog "+'clients="clients" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows list of affected clients",
()=>{const element=renderTestTemplate(clients);expect(element.text()).toContain("C.0000111122223333");expect(element.text()).toContain("C.1111222233334444")});it('calls dismiss callback when "Cancel" is pressed',()=>{const element=renderTestTemplate(clients);browserTriggerEvent($("button[name=Cancel]",element),"click");expect(dismissSpy).toHaveBeenCalled()});it("disables Proceed if no label name is entered",()=>{const element=renderTestTemplate(clients);expect($("input[name=labelBox]",element).val()).toEqual("");
expect($("button[name=Proceed][disabled]",element).length).toBe(1)});it("enables Proceed if label name is entered",()=>{const element=renderTestTemplate(clients);$("input[name=labelBox]",element).val("foobar");browserTriggerEvent($("input[name=labelBox]",element),"change");$rootScope.$apply();expect($("button[name=Proceed][disabled]",element).length).toBe(0)});it("sends request when Proceed is clicked",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=
renderTestTemplate(clients);$("input[name=labelBox]",element).val("foobar");browserTriggerEvent($("input[name=labelBox]",element),"change");$rootScope.$apply();browserTriggerEvent($("button[name=Proceed]",element),"click");expect(grrApiService.post).toHaveBeenCalledWith("/clients/labels/add",{client_ids:["C.0000111122223333","C.1111222233334444"],labels:["foobar"]})});it("shows failure warning on failure",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);
const element=renderTestTemplate(clients);$("input[name=labelBox]",element).val("foobar");browserTriggerEvent($("input[name=labelBox]",element),"change");$rootScope.$apply();browserTriggerEvent($("button[name=Proceed]",element),"click");deferred.reject({data:{message:"NOT OK"}});$rootScope.$apply();expect(element.text()).toContain("NOT OK")});it("shows success message on success",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=renderTestTemplate(clients);
$("input[name=labelBox]",element).val("foobar");browserTriggerEvent($("input[name=labelBox]",element),"change");$rootScope.$apply();browserTriggerEvent($("button[name=Proceed]",element),"click");deferred.resolve("OK");$rootScope.$apply();expect(element.text()).toContain("Label was successfully added")});it("calls on-close callback when closed after success",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=renderTestTemplate(clients);$("input[name=labelBox]",
element).val("foobar");browserTriggerEvent($("input[name=labelBox]",element),"change");$rootScope.$apply();browserTriggerEvent($("button[name=Proceed]",element),"click");deferred.resolve("OK");$rootScope.$apply();browserTriggerEvent($("button[name=Close]",element),"click");expect(closeSpy).toHaveBeenCalled()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.checkClientAccessDirectiveTest");goog.setTestOnly();const {clientModule}=goog.require("grrUi.client.client");const {testsModule}=goog.require("grrUi.tests");describe("grr-check-client-access directive",()=>{let $compile;let $q;let $rootScope;let $timeout;let grrApiService;let grrRoutingService;beforeEach(module("/static/angular-components/client/"+"check-client-access.html"));beforeEach(module(clientModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$timeout=$injector.get("$timeout");grrApiService=$injector.get("grrApiService");grrRoutingService=$injector.get("grrRoutingService")}));const renderTestTemplate=(noRedirect,omitClientId)=>{$rootScope.noRedirect=noRedirect;if(!omitClientId)$rootScope.clientId="C.0001000200030004";$rootScope.outHasAccess=undefined;const template='<grr-check-client-access no-redirect="noRedirect" '+
'client-id="clientId" out-has-access="outHasAccess">foo-bar'+"</grr-check-client-access>";const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("doesn't assign .access-disabled class when clientId is undefined",()=>{spyOn(grrApiService,"head").and.returnValue($q.defer().promise);const element=renderTestTemplate(false,true);expect(element.find("div.access-disabled").length).toBe(0)});it("shows transcluded content",()=>{spyOn(grrApiService,"head").and.returnValue($q.defer().promise);
const element=renderTestTemplate();expect(element.text()).toContain("foo-bar")});it("sends HEAD request to check access",()=>{spyOn(grrApiService,"head").and.returnValue($q.defer().promise);renderTestTemplate();expect(grrApiService.head).toHaveBeenCalledWith("clients/C.0001000200030004/flows")});it('updates the "outHasAccess" binding when access is permitted',()=>{const deferred=$q.defer();deferred.resolve();spyOn(grrApiService,"head").and.returnValue(deferred.promise);renderTestTemplate();expect($rootScope.outHasAccess).toBe(true)});
it("doesn't assign .access-disabled class to container div when access is permitted",()=>{const deferred=$q.defer();deferred.resolve();spyOn(grrApiService,"head").and.returnValue(deferred.promise);const element=renderTestTemplate();expect(element.find("div.access-disabled").length).toBe(0)});it('updates the "outHasAccess" binding when access is rejected',()=>{const deferred=$q.defer();deferred.reject();spyOn(grrApiService,"head").and.returnValue(deferred.promise);renderTestTemplate();expect($rootScope.outHasAccess).toBe(false)});
it("assigns .access-disabled class to container div when access is rejected",()=>{const deferred=$q.defer();deferred.reject();spyOn(grrApiService,"head").and.returnValue(deferred.promise);const element=renderTestTemplate();expect(element.find("div.access-disabled").length).toBe(1)});it('redirects to "client" state after 1s if noRedirect!=true and access is rejected',()=>{const deferred=$q.defer();deferred.reject();spyOn(grrApiService,"head").and.returnValue(deferred.promise);renderTestTemplate();
spyOn(grrRoutingService,"go");$timeout.flush();expect(grrRoutingService.go).toHaveBeenCalledWith("client",{clientId:"C.0001000200030004"})});it("does not redirect after 1s if noRedirect=true and access is rejected",()=>{const deferred=$q.defer();deferred.resolve();spyOn(grrApiService,"head").and.returnValue(deferred.promise);renderTestTemplate();spyOn(grrRoutingService,"go");$timeout.flush();expect(grrRoutingService.go).not.toHaveBeenCalled()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.clientStatusIconsDirectiveTest");goog.setTestOnly();const {clientModule}=goog.require("grrUi.client.client");const {testsModule}=goog.require("grrUi.tests");describe("client status icons",()=>{let $compile;let $rootScope;let grrTimeService;beforeEach(module("/static/angular-components/client/client-status-icons.html"));beforeEach(module(clientModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=
$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrTimeService=$injector.get("grrTimeService")}));const render=(client)=>{$rootScope.client=client;const template='<grr-client-status-icons client="client" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows online icon when last ping is 1 minute ago",()=>{const client={type:"ApiClient",value:{"last_seen_at":{value:42*1E6}}};grrTimeService.getCurrentTimeMs=()=>(42+60)*1E3;const element=render(client);
const iconElement=$("img[name=clientStatusIcon]",element);expect(iconElement.length).toBe(1);expect(iconElement[0].src).toContain("online.png");expect(iconElement[0].title).toBe("1 minutes ago")});it("shows online-1day icon when last ping is 23 hours ago",()=>{const client={type:"ApiClient",value:{"last_seen_at":{value:42*1E6}}};grrTimeService.getCurrentTimeMs=()=>(42+60*60*23)*1E3;const element=render(client);const iconElement=$("img[name=clientStatusIcon]",element);expect(iconElement.length).toBe(1);
expect(iconElement[0].src).toContain("online-1d.png");expect(iconElement[0].title).toBe("23 hours ago")});it("shows offline icon when last ping is is 3 days ago",()=>{const client={type:"ApiClient",value:{"last_seen_at":{value:42*1E6}}};grrTimeService.getCurrentTimeMs=()=>(42+60*60*24*3)*1E3;const element=render(client);const iconElement=$("img[name=clientStatusIcon]",element);expect(iconElement.length).toBe(1);expect(iconElement[0].src).toContain("offline.png");expect(iconElement[0].title).toBe("3 days ago")});
it("does not show crash icon if no crash happened",()=>{const client={type:"ApiClient",value:{}};const element=render(client);const iconElement=$("img[name=clientCrashIcon]",element);expect(iconElement.length).toBe(0)});it("does not show crash icon if crash happened 1 week ago",()=>{const client={type:"ApiClient",value:{"last_crash_at":{value:42*1E6}}};grrTimeService.getCurrentTimeMs=()=>(42+60*60*24*7)*1E3;const element=render(client);const iconElement=$("img[name=clientCrashIcon]",element);expect(iconElement.length).toBe(0)});
it("shows crash icon if crash happened 1 hour ago",()=>{const client={type:"ApiClient",value:{"last_crash_at":{value:42*1E6}}};grrTimeService.getCurrentTimeMs=()=>(42+60*60)*1E3;const element=render(client);const iconElement=$("img[name=clientCrashIcon]",element);expect(iconElement.length).toBe(1);expect(iconElement[0].src).toContain("skull-icon.png");expect(iconElement[0].title).toBe("1 hours ago")});it("shows no disk warning icon if none are present",()=>{const element=render({type:"ApiClient",
value:{}});const warningElement=$("img[name=clientDiskWarnings]",element);expect(warningElement.length).toBe(0)});it("shows disk warning icon if some are present",()=>{const volume1={name:{value:"/Volume/A"},total_allocation_units:{value:100},actual_available_allocation_units:{value:3}};const volume2={name:{value:"C:"},total_allocation_units:{value:100},actual_available_allocation_units:{value:4}};const client={type:"ApiClient",value:{volumes:[{type:"Volume",value:volume1},{type:"Volume",value:volume2}]}};
const element=render(client);const warningElement=$("img[name=clientDiskWarnings]",element);expect(warningElement.length).toBe(1)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.clientUsernamesDirectiveTest");goog.setTestOnly();const {clientModule}=goog.require("grrUi.client.client");const {semanticModule}=goog.require("grrUi.semantic.semantic");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("client usernames",()=>{let $compile;let $rootScope;beforeEach(module(clientModule.name));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));stubDirective("grrSemanticValue");
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const render=(value)=>{$rootScope.value=value;const template='<grr-client-usernames value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("List client usernames with grr-semantic-value",()=>{const usernames={value:"test_1 test_2 test_3"};const element=render(usernames);const directive=element.find("grr-semantic-value");expect(directive.scope().$eval("usernames").length).toEqual(3);
expect(directive.scope().$eval("usernames")[0].value).toEqual("test_1");expect(directive.scope().$eval("usernames")[1].value).toEqual("test_2");expect(directive.scope().$eval("usernames")[2].value).toEqual("test_3");expect(directive.scope().$eval("usernames")[0].type).toEqual("RDFString");expect(directive.scope().$eval("usernames")[1].type).toEqual("RDFString");expect(directive.scope().$eval("usernames")[2].type).toEqual("RDFString")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.clientsListDirectiveTest");goog.setTestOnly();const {clientModule}=goog.require("grrUi.client.client");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("clients list",()=>{let $compile;let $interval;let $q;let $rootScope;let grrApiService;let grrRoutingService;let grrReflectionService;beforeEach(module("/static/angular-components/client/clients-list.html"));beforeEach(module(clientModule.name));beforeEach(module(testsModule.name));
stubDirective("grrClientStatusIcons");stubDirective("grrSemanticValue");stubDirective("grrDisableIfNoTrait");beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$interval=$injector.get("$interval");grrApiService=$injector.get("grrApiService");grrReflectionService=$injector.get("grrReflectionService");grrRoutingService=$injector.get("grrRoutingService");grrReflectionService.getRDFValueDescriptor=(valueType)=>{const deferred=
$q.defer();deferred.resolve({name:valueType,mro:[valueType]});return deferred.promise}}));afterEach(()=>{$(document.body).html("")});const render=(query)=>{const template="<grr-clients-list />";const element=$compile(template)($rootScope);$rootScope.$apply();$("body").append(element);$interval.flush(1E3);return element};const mockApiService=(value)=>{if(value)spyOn(grrApiService,"get").and.returnValues($q.when({data:value}),$q.defer().promise);else spyOn(grrApiService,"get").and.returnValue($q.defer().promise)};
const mockRoutingService=(query)=>{spyOn(grrRoutingService,"uiOnParamsChanged").and.callFake((s,p,cb)=>{cb(query)})};it("sends request with a query to the server",()=>{mockApiService();mockRoutingService(".");render();expect(grrApiService.get).toHaveBeenCalledWith("/clients",{query:".",offset:0,count:50})});it("renders list with one client correctly",()=>{const clientsResponse={items:[{type:"VFSGRRClient",value:{client_id:{value:"C.0000000000000001",type:"ApiClientId"},first_seen_at:{value:0x4d368b34aa2eb,
type:"RDFDatetime"},last_clock:{value:0x51287f9771b73,type:"RDFDatetime"},os_info:{value:{fqdn:{value:"localhost.com",type:"RDFString"},version:{value:"10.9.5",type:"VersionString"},install_date:{value:1385377629E6,type:"RDFDatetime"}},type:"ClientInformation"},labels:[{"value":{"owner":{"value":"GRR","type":"unicode","age":0},"name":{"value":"foobar-label","type":"unicode","age":0}}}],interfaces:[{type:"Interface",value:{mac_address:"<mac address>"}}],users:[{type:"User",value:{username:{type:"RDFString",
value:"user_foo"}}},{type:"User",value:{type:"RDFString",value:"user_bar"}}]}}]};mockApiService(clientsResponse);mockRoutingService(".");const element=render();expect($("grr-client-status-icons",element).length).toBe(1)});it("ignores interfaces without mac addresses",()=>{const clientsResponse={items:[{type:"VFSGRRClient",value:{client_id:{value:"C.0000000000000001",type:"ApiClientId"},interfaces:[{type:"Interface1",value:{mac_address:"<mac address 1>"}},{type:"Interface Without Mac Address",value:{}},
{type:"Interface2",value:{mac_address:"<mac address 2>"}}]}}]};mockApiService(clientsResponse);mockRoutingService(".");const element=render();const macTableColumn=$("th:contains(MAC)",element).index();const macCell=$("tr td",element)[macTableColumn];const macDirective=$("grr-semantic-value",macCell);const macDirectiveScope=macDirective.scope();const addresses=macDirectiveScope.$eval(macDirective.attr("value"));expect(addresses).toEqual(["<mac address 1>","<mac address 2>"])})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.hostHistoryDialogDirectiveTest");goog.setTestOnly();const {clientModule}=goog.require("grrUi.client.client");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("semantic versioned proto directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;let grrTimeService;beforeEach(module("/static/angular-components/client/"+"host-history-dialog.html"));beforeEach(module(clientModule.name));beforeEach(module(testsModule.name));
stubDirective("grrSemanticValue");beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService");grrTimeService=$injector.get("grrTimeService")}));const renderTestTemplate=(fieldPath)=>{$rootScope.clientId="C.00000000000000001";$rootScope.fieldPath=fieldPath;$rootScope.close=()=>{};const template="<grr-host-history-dialog "+'client-id="clientId" field-path="fieldPath" '+'close="close()" />';
const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("fetches data for the last year",()=>{spyOn(grrTimeService,"getCurrentTimeMs").and.returnValue(31536000001);spyOn(grrApiService,"get").and.returnValue($q.defer().promise);renderTestTemplate("foo");expect(grrApiService.get).toHaveBeenCalledWith("/clients/C.00000000000000001/versions",{mode:"DIFF",start:1E3,end:31536000001E3})});it("correctly shows data for field path with 1 component",()=>{const deferred=$q.defer();
spyOn(grrApiService,"get").and.returnValue(deferred.promise);deferred.resolve({data:{items:[{type:"Foo",value:{field:{type:"RDFString",value:"bar1"},age:{type:"RDFDatetime",value:1}}},{type:"Foo",value:{age:{type:"RDFDatetime",value:2}}},{type:"Foo",value:{field:{type:"RDFString",value:"bar2"},age:{type:"RDFDatetime",value:3}}}]}});const element=renderTestTemplate("field");expect(element.find("td.version grr-semantic-value").length).toBe(2);let directive=element.find("td.version:nth(0) grr-semantic-value");
let value=directive.scope().$eval(directive.attr("value"));expect(value).toEqual({type:"RDFString",value:"bar2"});directive=element.find("td.version:nth(1) grr-semantic-value");value=directive.scope().$eval(directive.attr("value"));expect(value).toEqual({type:"RDFString",value:"bar1"})});it("correctly shows data for field path with 2 components",()=>{const deferred=$q.defer();spyOn(grrApiService,"get").and.returnValue(deferred.promise);deferred.resolve({data:{items:[{type:"Foo",value:{field1:{type:"Bar",
value:{field2:{type:"RDFString",value:"oh1"}}},age:{type:"RDFDatetime",value:1}}},{type:"Foo",value:{age:{type:"RDFDatetime",value:2}}},{type:"Foo",value:{field1:{type:"Bar",value:{field2:{type:"RDFString",value:"oh2"}}},age:{type:"RDFDatetime",value:3}}}]}});const element=renderTestTemplate("field1.field2");expect(element.find("td.version grr-semantic-value").length).toBe(2);let directive=element.find("td.version:nth(0) grr-semantic-value");let value=directive.scope().$eval(directive.attr("value"));
expect(value).toEqual({type:"RDFString",value:"oh2"});directive=element.find("td.version:nth(1) grr-semantic-value");value=directive.scope().$eval(directive.attr("value"));expect(value).toEqual({type:"RDFString",value:"oh1"})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.removeClientsLabelsDialogDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {clientModule}=goog.require("grrUi.client.client");describe("remove clients labels dialog",()=>{let $compile;let $q;let $rootScope;let closeSpy;let dismissSpy;let grrApiService;beforeEach(module("/static/angular-components/client/"+"remove-clients-labels-dialog.html"));beforeEach(module("/static/angular-components/core/"+
"confirmation-dialog.html"));beforeEach(module("/static/angular-components/semantic/"+"client-urn.html"));beforeEach(module(clientModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService");closeSpy=jasmine.createSpy("close");dismissSpy=jasmine.createSpy("dismiss")}));const renderTestTemplate=(clients)=>{$rootScope.clients=clients;$rootScope.$close=
closeSpy;$rootScope.$dismiss=dismissSpy;const template="<grr-remove-clients-labels-dialog "+'clients="clients" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows list of affected clients",()=>{const clients=[{type:"ApiClient",value:{urn:{value:"aff4:/C.0000111122223333",type:"RDFURN"},client_id:{value:"C.0000111122223333",type:"ApiClientId"}}},{type:"ApiClient",value:{urn:{value:"aff4:/C.1111222233334444",type:"RDFURN"},client_id:{value:"C.1111222233334444",
type:"ApiClientId"}}}];const element=renderTestTemplate(clients);expect(element.text()).toContain("C.0000111122223333");expect(element.text()).toContain("C.1111222233334444")});const clientsWithTwoUserLabels=[{type:"ApiClient",value:{urn:{value:"aff4:/C.0000111122223333",type:"RDFURN"},client_id:{value:"C.0000111122223333",type:"ApiClientId"},labels:[{value:{name:{value:"foo"},owner:{value:"test2"}}}]}},{type:"ApiClient",value:{urn:{value:"aff4:/C.1111222233334444",type:"RDFURN"},client_id:{value:"C.1111222233334444",
type:"ApiClientId"},labels:[{value:{name:{value:"bar"},owner:{value:"test2"}}}]}}];const clientsWithOneUserLabelAndOneSystemLabel=[{type:"ApiClient",value:{urn:{value:"aff4:/C.0000111122223333",type:"RDFURN"},client_id:{value:"C.0000111122223333",type:"ApiClientId"},labels:[{value:{name:{value:"foo"},owner:{value:"GRR"}}}]}},{type:"ApiClient",value:{urn:{value:"aff4:/C.1111222233334444",type:"RDFURN"},client_id:{value:"C.1111222233334444",type:"ApiClientId"},labels:[{value:{name:{value:"bar"},owner:{value:"test2"}}}]}}];
it("shows dropdown with a union of labels from all clients",()=>{const element=renderTestTemplate(clientsWithTwoUserLabels);expect($("select option",element).length).toBe(2);expect($("select option[label=foo]",element).length).toBe(1);expect($("select option[label=bar]",element).length).toBe(1)});it("does not show system labels in the list",()=>{const element=renderTestTemplate(clientsWithOneUserLabelAndOneSystemLabel);expect($("select option",element).length).toBe(1);expect($("select option[label=foo]",
element).length).toBe(0);expect($("select option[label=bar]",element).length).toBe(1)});it("has a label selected by default",()=>{const element=renderTestTemplate(clientsWithTwoUserLabels);const selected=$(":selected",element).text();expect(selected).toBeDefined()});it('calls dismiss callback when "Cancel" is pressed',()=>{const element=renderTestTemplate(clientsWithTwoUserLabels);browserTriggerEvent($("button[name=Cancel]",element),"click");expect(dismissSpy).toHaveBeenCalled()});it("sends request when proceed is clicked",
()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=renderTestTemplate(clientsWithTwoUserLabels);browserTriggerEvent($("button[name=Proceed]",element),"click");expect(grrApiService.post).toHaveBeenCalledWith("/clients/labels/remove",{client_ids:["C.0000111122223333","C.1111222233334444"],labels:["foo"]})});it("shows failure warning on failure",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=
renderTestTemplate(clientsWithTwoUserLabels);browserTriggerEvent($("button[name=Proceed]",element),"click");deferred.reject({data:{message:"NOT OK"}});$rootScope.$apply();expect(element.text()).toContain("NOT OK")});it("shows success message on success",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=renderTestTemplate(clientsWithTwoUserLabels);browserTriggerEvent($("button[name=Proceed]",element),"click");deferred.resolve("OK");$rootScope.$apply();
expect(element.text()).toContain("Label was successfully removed")});it("calls on-close callback when closed after success",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=renderTestTemplate(clientsWithTwoUserLabels);browserTriggerEvent($("button[name=Proceed]",element),"click");deferred.resolve("OK");$rootScope.$apply();browserTriggerEvent($("button[name=Close]",element),"click");expect(closeSpy).toHaveBeenCalled()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.config.binariesListDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {configModule}=goog.require("grrUi.config.config");const {sortBinaries}=goog.require("grrUi.config.binariesListDirective");describe("grr-binaries-list directive",()=>{describe("sortBinaries()",()=>{it("adds correct metadata to binaries without slashes in path",()=>{const binaries=sortBinaries([{value:{path:{value:"foo"}}}]);
expect(binaries[0]["pathLen"]).toBe(1);expect(binaries[0]["dirName"]).toBe("");expect(binaries[0]["baseName"]).toBe("foo")});it("adds correct metadata to binaries with slashes in path",()=>{const binaries=sortBinaries([{value:{path:{value:"foo/bar/42"}}}]);expect(binaries[0]["pathLen"]).toBe(3);expect(binaries[0]["dirName"]).toBe("foo/bar");expect(binaries[0]["baseName"]).toBe("42")});it("puts paths with more slashes first",()=>{const binaries=sortBinaries([{value:{path:{value:"foo"}}},{value:{path:{value:"foo/bar"}}},
{value:{path:{value:"foo/bar/42"}}}]);expect(binaries[0]["value"]["path"]["value"]).toBe("foo/bar/42");expect(binaries[1]["value"]["path"]["value"]).toBe("foo/bar");expect(binaries[2]["value"]["path"]["value"]).toBe("foo")});it("sorts paths with same number of slashes alphabetically",()=>{const binaries=sortBinaries([{value:{path:{value:"foo/b"}}},{value:{path:{value:"foo/c"}}},{value:{path:{value:"foo/a"}}}]);expect(binaries[0]["value"]["path"]["value"]).toBe("foo/a");expect(binaries[1]["value"]["path"]["value"]).toBe("foo/b");
expect(binaries[2]["value"]["path"]["value"]).toBe("foo/c")})});let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/config/binaries-list.html"));beforeEach(module(configModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService")}));const render=(binaries,typeFilter)=>{$rootScope.binaries=
binaries;$rootScope.typeFilter=typeFilter;const template='<grr-binaries-list binaries="binaries" '+'type-filter="{$ typeFilter $}" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("triggers download when row is clicked",()=>{const element=render([{value:{path:{value:"foo/bar"},type:{value:"PYTHON_HACK"}}}],"PYTHON_HACK");const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);browserTriggerEvent(element.find('tr:contains("foo")'),
"click");expect(grrApiService.downloadFile).toHaveBeenCalledWith("/config/binaries-blobs/PYTHON_HACK/foo/bar")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.apiItemsProviderDirectiveTest");goog.setTestOnly();const {ApiItemsProviderController}=goog.require("grrUi.core.apiItemsProviderDirective");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("API items provider directive",()=>{let $compile;let $q;let $rootScope;let grrApiServiceMock;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>
{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiServiceMock={get:function(){}}}));const getController=(url,queryParams,transformItems,testResponse)=>{let controller;$rootScope.testUrl=url;$rootScope.testQueryParams=queryParams;$rootScope.testTransformItems=transformItems;inject(($injector)=>{controller=$injector.instantiate(ApiItemsProviderController,{"$scope":$rootScope,"$attrs":{"url":"testUrl","queryParams":"testQueryParams","transformItems":transformItems?
"testTransformItems(items)":undefined},"grrApiService":grrApiServiceMock})});const deferred=$q.defer();deferred.resolve(testResponse);spyOn(grrApiServiceMock,"get").and.returnValue(deferred.promise);$rootScope.$apply();return controller};it("fetches ranges of items according to offset and count",()=>{const controller=getController("some/api/path",undefined,undefined);controller.fetchItems(0,10);expect(grrApiServiceMock.get).toHaveBeenCalledWith("some/api/path",{offset:0,count:10})});it("does not fetch total count when opt_withTotalCount is true",
()=>{const controller=getController("some/api/path",undefined,undefined);controller.fetchItems(0,10,true);expect(grrApiServiceMock.get).toHaveBeenCalledWith("some/api/path",{offset:0,count:10})});it('adds "filter" to query when fetching filtered items',()=>{const controller=getController("some/api/path",undefined,undefined);controller.fetchFilteredItems("some",0,10);expect(grrApiServiceMock.get).toHaveBeenCalledWith("some/api/path",{offset:0,count:10,filter:"some"})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.apiServiceTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");const {encodeUrlPath,stripTypeInfo,UNAUTHORIZED_API_RESPONSE_EVENT}=goog.require("grrUi.core.apiService");describe("API service",()=>{let $httpBackend;let $interval;let $q;let $rootScope;let grrApiService;beforeEach(module(coreModule.name));beforeEach(inject(($injector)=>{$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");$httpBackend=
$injector.get("$httpBackend");$interval=$injector.get("$interval");grrApiService=$injector.get("grrApiService");grrApiService.markAuthDone()}));afterEach(()=>{$httpBackend.verifyNoOutstandingExpectation();$httpBackend.verifyNoOutstandingRequest()});describe("encodeUrlPath() function",()=>{it("does not touch slashes and normal characters",()=>{expect(encodeUrlPath("////")).toBe("////");expect(encodeUrlPath("/a/b/c/d/")).toBe("/a/b/c/d/")});it('encodes "?", "&" and "+" characters',()=>{expect(encodeUrlPath("/foo?bar=a+b")).toBe("/foo%3Fbar%3Da%2Bb")})});
describe("stripTypeInfo() function",()=>{it("converts richly typed primitive into a primitive value",()=>{const richData={"age":0,"mro":["RDFString","object"],"type":"unicode","value":"label2"};expect(stripTypeInfo(richData)).toEqual("label2")});it("converts typed structure into a primitive dictionary",()=>{const richData={"age":0,"mro":["AFF4ObjectLabel","RDFProtoStruct","RDFStruct","RDFValue","object"],"type":"AFF4ObjectLabel","value":{"name":{"age":0,"mro":["unicode","basestring","object"],"type":"unicode",
"value":"label2"}}};expect(stripTypeInfo(richData)).toEqual({"name":"label2"})});it("converts richly typed list into list of primitives",()=>{const richData=[{"age":0,"mro":["RDFString","object"],"type":"unicode","value":"label2"},{"age":0,"mro":["RDFString","object"],"type":"unicode","value":"label3"}];expect(stripTypeInfo(richData)).toEqual(["label2","label3"])});it("converts list structure field into list of primitives",()=>{const richData={"age":0,"mro":["AFF4ObjectLabel","RDFProtoStruct","RDFStruct",
"RDFValue","object"],"type":"AFF4ObjectLabel","value":{"name":[{"age":0,"mro":["unicode","basestring","object"],"type":"unicode","value":"label2"},{"age":0,"mro":["unicode","basestring","object"],"type":"unicode","value":"label3"}]}};expect(stripTypeInfo(richData)).toEqual({"name":["label2","label3"]})})});describe("head() method",()=>{it('adds "/api/" to a given url',()=>{$httpBackend.whenHEAD("/api/some/path").respond(200);grrApiService.head("some/path");$httpBackend.flush()});it('adds "/api/" to a given url starting with "/"',
()=>{$httpBackend.whenHEAD("/api/some/path").respond(200);grrApiService.head("/some/path");$httpBackend.flush()});it("passes user-provided headers in the request",()=>{$httpBackend.whenHEAD("/api/some/path?key1=value1&key2=value2").respond(200);grrApiService.head("some/path",{key1:"value1",key2:"value2"});$httpBackend.flush()});it("passes user-provided headers in the request",()=>{$httpBackend.whenHEAD("/api/some/path?"+"key1=value1&key2=value2").respond(200);grrApiService.head("some/path",{key1:"value1",
key2:"value2"});$httpBackend.flush()});it("url-escapes the path",()=>{$httpBackend.whenHEAD("/api/some/path%3Ffoo%26bar?key1=value1&key2=value2").respond(200);grrApiService.head("some/path?foo&bar",{key1:"value1",key2:"value2"});$httpBackend.flush()})});describe("get() method",()=>{it('adds "/api/" to a given url',()=>{$httpBackend.whenGET("/api/some/path").respond(200);grrApiService.get("some/path");$httpBackend.flush()});it('adds "/api/" to a given url starting with "/"',()=>{$httpBackend.whenGET("/api/some/path").respond(200);
grrApiService.get("/some/path");$httpBackend.flush()});it("passes user-provided headers in the request",()=>{$httpBackend.whenGET("/api/some/path?key1=value1&key2=value2").respond(200);grrApiService.get("some/path",{key1:"value1",key2:"value2"});$httpBackend.flush()});it("passes user-provided headers in the request",()=>{$httpBackend.whenGET("/api/some/path?"+"key1=value1&key2=value2").respond(200);grrApiService.get("some/path",{key1:"value1",key2:"value2"});$httpBackend.flush()});it("url-escapes the path",
()=>{$httpBackend.whenGET("/api/some/path%3Ffoo%26bar?key1=value1&key2=value2").respond(200);grrApiService.get("some/path?foo&bar",{key1:"value1",key2:"value2"});$httpBackend.flush()})});describe("poll() method",()=>{it("triggers url once if condition is immediately satisfied",()=>{$httpBackend.expectGET("/api/some/path").respond(200,{"state":"FINISHED"});grrApiService.poll("some/path",1E3);$httpBackend.flush();$interval.flush(2E3)});it("does not call callbacks when cancelled via cancelPoll()",()=>
{$httpBackend.expectGET("/api/some/path").respond(200,{});let successHandlerCalled=false;let failureHandlerCalled=false;let finallyHandlerCalled=false;const pollPromise=grrApiService.poll("some/path",1E3);pollPromise.then(()=>{successHandlerCalled=true},()=>{failureHandlerCalled=true}).finally(()=>{finallyHandlerCalled=true});grrApiService.cancelPoll(pollPromise);$httpBackend.flush();expect(successHandlerCalled).toBe(false);expect(failureHandlerCalled).toBe(false);expect(finallyHandlerCalled).toBe(false)});
it("succeeds and returns response if first try succeeds",()=>{$httpBackend.expectGET("/api/some/path").respond(200,{"foo":"bar","state":"FINISHED"});let successHandlerCalled=false;grrApiService.poll("some/path",1E3).then((response)=>{expect(response["data"]).toEqual({"foo":"bar","state":"FINISHED"});successHandlerCalled=true});$httpBackend.flush();expect(successHandlerCalled).toBe(true)});it("triggers url multiple times if condition is not satisfied",()=>{$httpBackend.expectGET("/api/some/path").respond(200,
{});grrApiService.poll("some/path",1E3);$httpBackend.flush();$httpBackend.expectGET("/api/some/path").respond(200,{});$interval.flush(2E3);$httpBackend.flush()});it("succeeds and returns response if second try succeeds",()=>{$httpBackend.expectGET("/api/some/path").respond(200,{});let successHandlerCalled=false;grrApiService.poll("some/path",1E3).then((response)=>{expect(response["data"]).toEqual({"foo":"bar","state":"FINISHED"});successHandlerCalled=true});$httpBackend.flush();$httpBackend.expectGET("/api/some/path").respond(200,
{"foo":"bar","state":"FINISHED"});$interval.flush(2E3);$httpBackend.flush();expect(successHandlerCalled).toBe(true)});it("fails if first try fails",()=>{$httpBackend.expectGET("/api/some/path").respond(500);let failureHandleCalled=false;grrApiService.poll("some/path",1E3).then(()=>{},()=>{failureHandleCalled=true});$httpBackend.flush();expect(failureHandleCalled).toBe(true)});it("fails if first try is correct, but second one fails",()=>{$httpBackend.expectGET("/api/some/path").respond(200,{});let failureHandleCalled=
false;grrApiService.poll("some/path",1E3).then(()=>{},()=>{failureHandleCalled=true});$httpBackend.flush();$httpBackend.expectGET("/api/some/path").respond(500);$interval.flush(2E3);$httpBackend.flush();expect(failureHandleCalled).toBe(true)});it("returns response payload on failure",()=>{$httpBackend.expectGET("/api/some/path").respond(500,{"foo":"bar"});grrApiService.poll("some/path",1E3).then(()=>{},(response)=>{expect(response["data"]).toEqual({"foo":"bar"})});$httpBackend.flush()});it("notifies on every intermediate poll result",
()=>{$httpBackend.expectGET("/api/some/path").respond(200,{});let notificationCount=0;grrApiService.poll("some/path",1E3).then(undefined,undefined,(data)=>{notificationCount+=1});expect(notificationCount).toBe(0);$httpBackend.flush();expect(notificationCount).toBe(1);$interval.flush(500);expect(notificationCount).toBe(1);$httpBackend.expectGET("/api/some/path").respond(200,{});$interval.flush(500);$httpBackend.flush();expect(notificationCount).toBe(2)});it("does not allow API requests to overlap",
()=>{const deferred=$q.defer();spyOn(grrApiService,"get").and.returnValue(deferred.promise);grrApiService.poll("some/path",1E3);expect(grrApiService.get).toHaveBeenCalledTimes(1);$interval.flush(2E3);expect(grrApiService.get).toHaveBeenCalledTimes(1)});it("does not resolve the promise after cancelPoll() call",()=>{$httpBackend.expectGET("/api/some/path").respond(200,{"foo":"bar","state":"FINISHED"});let successHandlerCalled=false;const promise=grrApiService.poll("some/path",1E3).then((response)=>
{successHandlerCalled=true});grrApiService.cancelPoll(promise);$httpBackend.flush();expect(successHandlerCalled).toBe(false)});it("works correctly on a chained promise",()=>{$httpBackend.expectGET("/api/some/path").respond(200,{"foo":"bar","state":"FINISHED"});let successHandlerCalled=false;let finallyHandlerCalled=false;grrApiService.poll("some/path",1E3).then(()=>{successHandlerCalled=true}).catch(()=>{}).finally(()=>{finallyHandlerCalled=true});$httpBackend.flush();expect(finallyHandlerCalled).toBe(true);
expect(successHandlerCalled).toBe(true)});it("allows cancelPoll to be called on a chained promise",()=>{$httpBackend.expectGET("/api/some/path").respond(200,{"foo":"bar","state":"FINISHED"});let successHandlerCalled=false;let finallyHandlerCalled=false;const promise=grrApiService.poll("some/path",1E3).then(()=>{successHandlerCalled=true}).catch(()=>{}).finally(()=>{finallyHandlerCalled=true});grrApiService.cancelPoll(promise);$httpBackend.flush();expect(finallyHandlerCalled).toBe(false);expect(successHandlerCalled).toBe(false)})});
describe("cancelPoll() method",()=>{it('raises if the promise does not have "cancel" attribute',()=>{const deferred=$q.defer();expect(()=>{grrApiService.cancelPoll(deferred.promise)}).toThrow(new Error("Invalid promise to cancel: not cancelable."))})});describe("delete() method",()=>{it('adds "/api/" to a given url',()=>{$httpBackend.expectDELETE("/api/some/path").respond(200);grrApiService.delete("some/path");$httpBackend.flush()});it('adds "/api/" to a given url starting with "/"',()=>{$httpBackend.expectDELETE("/api/some/path").respond(200);
grrApiService.delete("/some/path");$httpBackend.flush()});it("passes user-provided data in the request",()=>{$httpBackend.expect("DELETE","/api/some/path",{key1:"value1",key2:"value2"}).respond(200);grrApiService.delete("some/path",{key1:"value1",key2:"value2"});$httpBackend.flush()});it("url-escapes the path",()=>{$httpBackend.expectDELETE("/api/some/path%3Ffoo%26bar").respond(200);grrApiService.delete("some/path?foo&bar");$httpBackend.flush()});it("doesn't send request body if no payload provided",
()=>{$httpBackend.expect("DELETE","/api/some/path",(data)=>angular.isUndefined(data)).respond(200);grrApiService.delete("some/path");$httpBackend.flush()})});describe("patch() method",()=>{it('adds "/api/" to a given url',()=>{$httpBackend.expectPATCH("/api/some/path").respond(200);grrApiService.patch("some/path");$httpBackend.flush()});it('adds "/api/" to a given url starting with "/"',()=>{$httpBackend.expectPATCH("/api/some/path").respond(200);grrApiService.patch("/some/path");$httpBackend.flush()});
it("passes user-provided data in the request",()=>{$httpBackend.expect("PATCH","/api/some/path",{key1:"value1",key2:"value2"}).respond(200);grrApiService.patch("some/path",{key1:"value1",key2:"value2"});$httpBackend.flush()});it("url-escapes the path",()=>{$httpBackend.expectPATCH("/api/some/path%3Ffoo%26bar").respond(200);grrApiService.patch("some/path?foo&bar");$httpBackend.flush()})});describe("post() method",()=>{it('adds "/api/" to a given url',()=>{$httpBackend.whenPOST("/api/some/path").respond(200);
grrApiService.post("some/path");$httpBackend.flush()});it('adds "/api/" to a given url starting with "/"',()=>{$httpBackend.whenPOST("/api/some/path").respond(200);grrApiService.post("/some/path",{});$httpBackend.flush()});it("strips type info from params if opt_stripTypeInfo is true",()=>{const richData={"age":0,"mro":["AFF4ObjectLabel","RDFProtoStruct","RDFStruct","RDFValue","object"],"type":"AFF4ObjectLabel","value":{"name":{"age":0,"mro":["unicode","basestring","object"],"type":"unicode","value":"label2"}}};
$httpBackend.whenPOST("/api/some/path",{name:"label2"}).respond(200);grrApiService.post("some/path",richData,true);$httpBackend.flush()});it("passes user-provided headers in the request",()=>{$httpBackend.expectPOST("/api/some/path",{key1:"value1",key2:"value2"}).respond(200);grrApiService.post("some/path",{key1:"value1",key2:"value2"});$httpBackend.flush()});it("url-escapes the path",()=>{$httpBackend.whenPOST("/api/some/path%3Ffoo%26bar").respond(200);grrApiService.post("some/path?foo&bar",{});
$httpBackend.flush()});it("url-escapes the path when files are uploaded",()=>{$httpBackend.whenPOST("/api/some/path%3Ffoo%26bar").respond(200);grrApiService.post("some/path?foo&bar",{},false,{"file1":"blah"});$httpBackend.flush()})});describe("downloadFile() method",()=>{afterEach(()=>{$(document.body).html("")});it("sends HEAD request first to check if URL is accessible",()=>{$httpBackend.expectHEAD("/api/some/path").respond(200);grrApiService.downloadFile("some/path");$httpBackend.flush()});it("sends query parameters in the HEAD request",
()=>{$httpBackend.expectHEAD("/api/some/path?abra=cadabra&foo=bar").respond(200);grrApiService.downloadFile("some/path",{"foo":"bar","abra":"cadabra"});$httpBackend.flush()});it("url-escapes the path",()=>{$httpBackend.expectHEAD("/api/some/path%3Ffoo%26bar?key1=value1&key2=value2").respond(200);grrApiService.downloadFile("some/path?foo&bar",{key1:"value1",key2:"value2"});$httpBackend.flush()});it("rejects promise if HEAD request fails",()=>{$httpBackend.whenHEAD("/api/some/path").respond(500);let promiseRejected=
false;const promise=grrApiService.downloadFile("some/path");promise.then(()=>{},()=>{promiseRejected=true});$httpBackend.flush();expect(promiseRejected).toBe(true)});it("broadcasts subject/reason from UnauthorizedAccess HEAD response",()=>{$httpBackend.whenHEAD("/api/some/path").respond(403,{},{"x-grr-unauthorized-access-subject":"some subject","x-grr-unauthorized-access-reason":"some reason"});spyOn($rootScope,"$broadcast");grrApiService.downloadFile("some/path");$httpBackend.flush();expect($rootScope.$broadcast).toHaveBeenCalledWith(UNAUTHORIZED_API_RESPONSE_EVENT,
{subject:"some subject",reason:"some reason"})});it("creates an iframe request if HEAD succeeds",()=>{$httpBackend.whenHEAD("/api/some/path").respond(200);grrApiService.downloadFile("some/path");$httpBackend.flush();expect($("iframe").attr("src")).toBe("/api/some/path")});it('propagates query option to iframe "src" attribute',()=>{$httpBackend.whenHEAD("/api/some/path?abra=cadabra&foo=bar").respond(200);grrApiService.downloadFile("some/path",{"foo":"bar","abra":"cadabra"});$httpBackend.flush();expect($("iframe").attr("src")).toBe("/api/some/path?abra=cadabra&foo=bar")});
it("fails if same-origin-policy error is thrown when accessing iframe",()=>{$httpBackend.whenHEAD("/api/some/path").respond(200);let promiseRejected=false;const promise=grrApiService.downloadFile("some/path");promise.then(()=>{},()=>{promiseRejected=true});$httpBackend.flush();Object.defineProperty($("iframe")[0].contentWindow.document,"readyState",{__proto__:null,get:function(){throw new Error("Same origin policy error");}});$interval.flush(1E3);expect(promiseRejected).toBe(true)});it("cancels the interval timer if iframe request fails",
()=>{$httpBackend.whenHEAD("/api/some/path").respond(200);spyOn($interval,"cancel").and.returnValue();grrApiService.downloadFile("some/path");$httpBackend.flush();Object.defineProperty($("iframe")[0].contentWindow.document,"readyState",{__proto__:null,get:function(){throw new Error("Same origin policy error");}});$interval.flush(1E3);expect($interval.cancel).toHaveBeenCalled()});it("succeeds if iframe request succeeds",()=>{$httpBackend.whenHEAD("/api/some/path").respond(200);let promiseSucceeded=
false;const promise=grrApiService.downloadFile("some/path");promise.then(()=>{promiseSucceeded=true});$httpBackend.flush();Object.defineProperty($("iframe")[0].contentWindow.document,"readyState",{__proto__:null,get:function(){return"complete"}});$interval.flush(1E3);expect(promiseSucceeded).toBe(true)});it("cancels the interval timer if iframe request succeeds",()=>{$httpBackend.whenHEAD("/api/some/path").respond(200);spyOn($interval,"cancel").and.returnValue();grrApiService.downloadFile("some/path");
$httpBackend.flush();Object.defineProperty($("iframe")[0].contentWindow.document,"readyState",{__proto__:null,get:function(){return"complete"}});$interval.flush(1E3);expect($interval.cancel).toHaveBeenCalled()})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.bindKeyDirectiveTest");goog.setTestOnly();const {browserTriggerKeyDown,testsModule}=goog.require("grrUi.tests");const {coreModule}=goog.require("grrUi.core.core");describe("bind key directive",()=>{let $compile;let $rootScope;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector,_$interval_)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const render=
(callback,key)=>{$rootScope.callback=callback;const template='<input type="text" grr-bind-key="callback()" key="'+key+'" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("calls the specified function on keydown",(done)=>{const element=render(done,13);browserTriggerKeyDown(element,13)});it("calls the specified function only on specified keydown",()=>{const callback=()=>{fail("Callback should not be called")};const element=render(callback,13);browserTriggerKeyDown(element,
15)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.bytesToHexFilterTest");goog.setTestOnly();const {BytesToHexFilter}=goog.require("grrUi.core.bytesToHexFilter");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("grrBytesToHex filter",()=>{let grrBytesToHexFilter;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{grrBytesToHexFilter=$injector.instantiate(BytesToHexFilter)}));
it("returns the correct hex for different input bytes",()=>{let result=grrBytesToHexFilter("some text");expect(result).toBe("736f6d652074657874");result=grrBytesToHexFilter("123abc");expect(result).toBe("313233616263")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.canaryOnlyDirectiveTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("The canaryOnlyDirective package",()=>{let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");
grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=()=>{const template="<grr-canary-only>"+"This text is being canaried."+"</grr-canary-only>"+"<grr-non-canary-only>"+"This text is being deprecated."+"</grr-non-canary-only>";const element=$compile(template)($rootScope);$rootScope.$apply();return element};const setMockedCanaryModeValue=(newValue)=>{const deferred=$q.defer();deferred.resolve({data:{value:{settings:{value:{canary_mode:{value:newValue}}}}}});spyOn(grrApiService,
"getCached").and.returnValue(deferred.promise)};it("renders the grr-canary-only element in canary mode",()=>{setMockedCanaryModeValue(true);const element=renderTestTemplate();expect(element.text()).toContain("This text is being canaried.")});it("doesn't render the grr-canary-only element in non-canary mode",()=>{setMockedCanaryModeValue(false);const element=renderTestTemplate();expect(element.text()).not.toContain("This text is being canaried.")});it("renders the grr-non-canary-only element in non-canary mode",
()=>{setMockedCanaryModeValue(false);const element=renderTestTemplate();expect(element.text()).toContain("This text is being deprecated.")});it("doesn't render the grr-non-canary-only element in canary mode",()=>{setMockedCanaryModeValue(true);const element=renderTestTemplate();expect(element.text()).not.toContain("This text is being deprecated.")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.clockDirectiveTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("clock directive",()=>{let $compile;let $interval;let $rootScope;let grrTimeService;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector,_$interval_)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$interval=
_$interval_;grrTimeService=$injector.get("grrTimeService")}));afterEach(inject(($injector)=>{grrTimeService=$injector.get("grrTimeService")}));const renderTestTemplate=()=>{const template="<grr-live-clock />";const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows the current time in a clock",()=>{let time="2015-01-02 03:04:05";grrTimeService.formatAsUTC=()=>`${time} UTC`;const newElement=renderTestTemplate();expect(newElement.text()).toContain("2015-01-02 03:04:05 UTC");
time="2015-01-02 03:04:06";$interval.flush(6E4);expect(newElement.text()).toContain("03:04:06")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.confirmationDialogDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {coreModule}=goog.require("grrUi.core.core");describe("confirmation dialog directive",()=>{let $compile;let $q;let $rootScope;beforeEach(module("/static/angular-components/core/confirmation-dialog.html"));beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>
{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q")}));const render=(title,message,proceedCallback,buttonClass)=>{$rootScope.title=title;$rootScope.message=message;$rootScope.proceed=proceedCallback;$rootScope.buttonClass=buttonClass;const template="<grr-confirmation-dialog "+'    title="title" '+'    proceed="proceed()"'+'    proceed-class="buttonClass">'+"  {$ message $}"+"</grr-confirmation-dialog>";const element=$compile(template)($rootScope);$rootScope.$apply();
return element};it("shows title and message",()=>{const title="Test Title";const message="Test Content Message";const element=render(title,message);expect(element.find(".modal-header h3").text().trim()).toBe(title);expect(element.find(".modal-body").text().trim()).toContain(message)});it('applies given style to "proceed" button',()=>{const element=render("title","message",undefined,"btn-warning");expect(element.find("button.btn-warning")).not.toBe(undefined)});it("shows success on proceed promise resolve",
()=>{const successMessage="Some action just happened successfully";const proceed=()=>$q.when(successMessage);const element=render("","",proceed);spyOn($rootScope,"proceed").and.callThrough();browserTriggerEvent(element.find('button[name="Proceed"]'),"click");$rootScope.$apply();expect($rootScope.proceed).toHaveBeenCalled();expect(element.find(".modal-footer .text-success").text().trim()).toBe(successMessage);expect(element.find('button[name="Close"]').length).toBe(1)});it("shows error on proceed promise reject",
()=>{const errorMessage="Some action could not be performed";const proceed=()=>$q.reject(errorMessage);const element=render("","",proceed);spyOn($rootScope,"proceed").and.callThrough();browserTriggerEvent(element.find('button[name="Proceed"]'),"click");$rootScope.$apply();expect($rootScope.proceed).toHaveBeenCalled();expect(element.find(".modal-footer .text-danger").text().trim()).toBe(errorMessage)});it("shows a disabled proceed button when canProceed is false",()=>{let buttonEnabled=false;$rootScope.canProceed=
()=>buttonEnabled;const template='<grr-confirmation-dialog can-proceed="canProceed()">'+"</grr-confirmation-dialog>";const element=$compile(template)($rootScope);$rootScope.$apply();expect($("button[name=Proceed][disabled]",element).length).toBe(1);buttonEnabled=true;$rootScope.$apply();expect($("button[name=Proceed][disabled]",element).length).toBe(0)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.disableIfNoTraitDirectiveTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("grr-disable-if-no-trait directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");
$q=$injector.get("$q");grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=()=>{const template='<span grr-disable-if-no-trait="trait_foo"></span>';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('applied "disabled" attribute if trait is missing',()=>{const deferred=$q.defer();deferred.resolve({data:{value:{interface_traits:{value:{}}}}});spyOn(grrApiService,"getCached").and.returnValue(deferred.promise);const element=renderTestTemplate();expect(element.attr("disabled")).toBe("disabled")});
it('applied "disabled" attribute if trait is false',()=>{const deferred=$q.defer();deferred.resolve({data:{value:{interface_traits:{value:{trait_foo:{value:false}}}}}});spyOn(grrApiService,"getCached").and.returnValue(deferred.promise);const element=renderTestTemplate();expect(element.attr("disabled")).toBe("disabled")});it("does nothing if trait is true",()=>{const deferred=$q.defer();deferred.resolve({data:{value:{interface_traits:{value:{trait_foo:{value:true}}}}}});spyOn(grrApiService,"getCached").and.returnValue(deferred.promise);
const element=renderTestTemplate();expect(element.attr("disabled")).toBe(undefined)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.downloadCollectionAsDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {coreModule}=goog.require("grrUi.core.core");describe('"download collection as" panel',()=>{let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/core/download-collection-as.html"));beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>
{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=(baseUrl)=>{$rootScope.baseUrl=baseUrl||"foo/bar";const template="<grr-download-collection-as "+'base-url="baseUrl" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};const testDownloadAsType=(plugin)=>()=>{const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);
const element=renderTestTemplate();element.find("#plugin-select").val(`string:${plugin}`).change();browserTriggerEvent(element.find('button[name="download-as"]'),"click");expect(grrApiService.downloadFile).toHaveBeenCalledWith(`foo/bar/${plugin}`)};it("sends correct request for CSV download",testDownloadAsType("csv-zip"));it("sends correct request for flattened YAML download",testDownloadAsType("flattened-yaml-zip"));it("sends correct request for sqlite download",testDownloadAsType("sqlite-zip"))});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.downloadCollectionFilesDirectiveTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("download collection files directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;const $window={navigator:{}};beforeEach(module(($provide)=>{$provide.value("$window",$window)}));beforeEach(module("/static/angular-components/core/"+"download-collection-files.html"));
beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$q=$injector.get("$q");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=(opt_withExportCommand)=>{$rootScope.downloadUrl="some/download/url";if(opt_withExportCommand)$rootScope.exportCommandUrl="some/export-command/url";const template="<grr-download-collection-files "+'download-url="downloadUrl" export-command-url="exportCommandUrl" />';
const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows TAR.GZ as default option on Mac",()=>{$window.navigator.appVersion="Mac";const element=renderTestTemplate();expect(element.find("button").text()).toContain("Generate TAR.GZ");expect(element.find("ul.dropdown-menu li").text()).toContain("Generate ZIP")});it("shows ZIP as default option on Linux",()=>{$window.navigator.appVersion="Linux";const element=renderTestTemplate();expect(element.find("button").text()).toContain("Generate ZIP");
expect(element.find("ul.dropdown-menu li").text()).toContain("Generate TAR.GZ")});it("sends TAR.GZ generation request when button clicked on Mac",()=>{$window.navigator.appVersion="Mac";const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();element.find("button").click();expect(grrApiService.downloadFile).toHaveBeenCalledWith("some/download/url",{archive_format:"TAR_GZ"})});it("sends ZIP generation request when dropdownclicked on Mac",
()=>{$window.navigator.appVersion="Mac";const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();element.find("ul.dropdown-menu li a").click();expect(grrApiService.downloadFile).toHaveBeenCalledWith("some/download/url",{archive_format:"ZIP"})});it("sends ZIP generation request when button is clicked on Linux",()=>{$window.navigator.appVersion="Linux";const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);
const element=renderTestTemplate();element.find("button").click();expect(grrApiService.downloadFile).toHaveBeenCalledWith("some/download/url",{archive_format:"ZIP"})});it("sends TAR.GZ generation request when dropdown clicked on Linux",()=>{$window.navigator.appVersion="Linux";const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();element.find("ul.dropdown-menu li a").click();expect(grrApiService.downloadFile).toHaveBeenCalledWith("some/download/url",
{archive_format:"TAR_GZ"})});it("disables the button after request is sent",()=>{const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();expect(element.find("button[disabled]").length).toBe(0);element.find("ul.dropdown-menu li a").click();expect(element.find("button[disabled]").length).not.toBe(0)});it("shows success message if request succeeds",()=>{const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);
const element=renderTestTemplate();element.find("button").click();deferred.resolve({status:"OK"});$rootScope.$apply();expect(element.text()).toContain("Generation has started.")});it("shows failure message if request fails",()=>{const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();element.find("button").click();deferred.reject({data:{message:"FAIL"}});$rootScope.$apply();expect(element.text()).toContain("Can't generate archive: FAIL")});
describe("with export command url provided",()=>{let exportCommandDeferred;beforeEach(()=>{$window.navigator.appVersion="Mac";exportCommandDeferred=$q.defer();spyOn(grrApiService,"get").and.returnValue(exportCommandDeferred.promise)});it("fetches export command",()=>{renderTestTemplate(true);expect(grrApiService.get).toHaveBeenCalledWith("some/export-command/url")});it('shows "Show export command" link',()=>{exportCommandDeferred.resolve({data:{command:"blah --foo"}});const element=renderTestTemplate(true);
expect($('a:contains("Show export command")',element).length).toBe(1)});it("renders export command",()=>{exportCommandDeferred.resolve({data:{command:"blah --foo"}});const element=renderTestTemplate(true);expect($('pre:contains("blah --foo")',element).length).toBe(1)})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.fileDownloadUtilsTest");goog.setTestOnly();const {getPathSpecFromValue,makeValueDownloadable,pathSpecToAff4Path}=goog.require("grrUi.core.fileDownloadUtils");describe("statEntryDirective.buildAff4Path",()=>{it("converts os+tsk pathspec correctly",()=>{const pathspec={type:"PathSpec",value:{path:{value:"\\\\.\\Volume{1234}\\",type:"RDFString"},pathtype:{value:"OS",type:"EnumNamedValue"},mount_point:"/c:/",nested_path:{type:"PathSpec",
value:{path:{value:"/windows",type:"RDFString"},pathtype:{value:"TSK",type:"EnumNamedValue"}}}}};expect(pathSpecToAff4Path(pathspec,"C.1234567812345678")).toBe("aff4:/C.1234567812345678/fs/tsk/\\\\.\\Volume{1234}\\/windows")});it("converts os+tsk pathspec correctly when the device starts with /",()=>{const pathspec={type:"PathSpec",value:{path:{value:"/\\\\.\\Volume{1234}\\",type:"RDFString"},pathtype:{value:"OS",type:"EnumNamedValue"},mount_point:"/c:/",nested_path:{type:"PathSpec",value:{path:{value:"/windows",
type:"RDFString"},pathtype:{value:"TSK",type:"EnumNamedValue"}}}}};expect(pathSpecToAff4Path(pathspec,"C.1234567812345678")).toBe("aff4:/C.1234567812345678/fs/tsk/\\\\.\\Volume{1234}\\/windows")});it("converts os+tsk ADS pathspec correctly",()=>{const pathspec={type:"PathSpec",value:{path:{value:"\\\\.\\Volume{1234}\\",type:"RDFString"},pathtype:{value:"OS",type:"EnumNamedValue"},mount_point:"/c:/",nested_path:{type:"PathSpec",value:{path:{value:"/Test Directory/notes.txt:ads",type:"RDFString"},pathtype:{value:"TSK",
type:"EnumNamedValue"},inode:{value:66,type:"int"},ntfs_type:{value:128,type:"int"},ntfs_id:{value:2,type:"int"}}}}};expect(pathSpecToAff4Path(pathspec,"C.1234567812345678")).toBe("aff4:/C.1234567812345678/fs/tsk/\\\\.\\Volume{1234}\\/Test Directory/notes.txt:ads")})});describe("fileDownloadUtils",()=>{let artifactFilesDownloaderResult;let fileFinderResult;let pathspec;let rdfstring;let statEntry;beforeEach(()=>{pathspec={value:{path:{type:"RDFString",value:"foo/bar"}},type:"Pathspec"};statEntry=
{value:{pathspec:pathspec},type:"StatEntry"};fileFinderResult={value:{stat_entry:angular.copy(statEntry)},type:"FileFinderResult"};artifactFilesDownloaderResult={value:{downloaded_file:angular.copy(statEntry)},type:"ArtifactFilesDownloaderResult"};rdfstring={value:"blah",type:"RDFString"}});describe("getPathSpecFromValue",()=>{it("returns null if argument is null or undefined",()=>{expect(getPathSpecFromValue(null)).toBe(null);expect(getPathSpecFromValue(undefined)).toBe(null)});it("extracts pathspec from StatEntry",
()=>{expect(getPathSpecFromValue(statEntry)).toEqual(pathspec)});it("extracts pathspec from FileFinderResult",()=>{expect(getPathSpecFromValue(fileFinderResult)).toEqual(pathspec)});it("extracts pathspec from ArtifactFilesDownloaderResult",()=>{expect(getPathSpecFromValue(artifactFilesDownloaderResult)).toEqual(pathspec)});it("extracts pathspec recursively from ApiFlowResult",()=>{let apiFlowResult={value:{payload:angular.copy(statEntry)},type:"ApiFlowResult"};expect(getPathSpecFromValue(apiFlowResult)).toEqual(pathspec);
apiFlowResult={value:{payload:angular.copy(fileFinderResult)},type:"ApiFlowResult"};expect(getPathSpecFromValue(apiFlowResult)).toEqual(pathspec);apiFlowResult={value:{payload:angular.copy(artifactFilesDownloaderResult)},type:"ApiFlowResult"};expect(getPathSpecFromValue(apiFlowResult)).toEqual(pathspec)});it("extracts pathspec recursively from ApiHuntResult",()=>{let apiHuntResult={value:{payload:angular.copy(statEntry)},type:"ApiHuntResult"};expect(getPathSpecFromValue(apiHuntResult)).toEqual(pathspec);
apiHuntResult={value:{payload:angular.copy(fileFinderResult)},type:"ApiHuntResult"};expect(getPathSpecFromValue(apiHuntResult)).toEqual(pathspec);apiHuntResult={value:{payload:angular.copy(artifactFilesDownloaderResult)},type:"ApiHuntResult"};expect(getPathSpecFromValue(apiHuntResult)).toEqual(pathspec)});it("returns null for other aff4 types",()=>{expect(getPathSpecFromValue(rdfstring)).toBe(null)});it("returns null for other types wrapped in ApiFlowResult",()=>{const apiFlowResult={value:{payload:angular.copy(rdfstring)},
type:"ApiFlowResult"};expect(getPathSpecFromValue(apiFlowResult)).toBe(null)});it("returns null for other types wrapped in ApiHuntResult",()=>{const apiHuntResult={value:{payload:angular.copy(rdfstring)},type:"ApiHuntResult"};expect(getPathSpecFromValue(apiHuntResult)).toBe(null)})});describe("makeValueDownloadable",()=>{const downloadUrl="download/foo/bar";const downloadParams={foo:"bar",blah:"blah"};it("does nothing if argument is null or undefned",()=>{expect(makeValueDownloadable(null,downloadUrl,
downloadParams)).toBe(false);expect(makeValueDownloadable(undefined,downloadUrl,downloadParams)).toBe(false)});it("replaces aff4path in StatEntry",()=>{const originalStatEntry=angular.copy(statEntry);expect(makeValueDownloadable(statEntry,downloadUrl,downloadParams)).toBe(true);expect(statEntry).toEqual({downloadUrl:downloadUrl,downloadParams:downloadParams,originalValue:originalStatEntry,type:"__DownloadableStatEntry"})});it("replaces aff4path in FileFinderResult",()=>{const originalFileFinderResult=
angular.copy(fileFinderResult);expect(makeValueDownloadable(fileFinderResult,downloadUrl,downloadParams)).toBe(true);expect(fileFinderResult.value.stat_entry).toEqual({downloadUrl:downloadUrl,downloadParams:downloadParams,originalValue:originalFileFinderResult.value.stat_entry,type:"__DownloadableStatEntry"})});it("replaces aff4path in ArtifactFilesDownloaderResult",()=>{const original=angular.copy(artifactFilesDownloaderResult);expect(makeValueDownloadable(artifactFilesDownloaderResult,downloadUrl,
downloadParams)).toBe(true);expect(artifactFilesDownloaderResult.value.downloaded_file).toEqual({downloadUrl:downloadUrl,downloadParams:downloadParams,originalValue:original.value.downloaded_file,type:"__DownloadableStatEntry"})});it("replaces aff4path recursively in ApiFlowResult",()=>{const apiFlowResult={value:{payload:angular.copy(statEntry)},type:"ApiFlowResult"};expect(makeValueDownloadable(apiFlowResult,downloadUrl,downloadParams)).toBe(true);expect(apiFlowResult.value.payload).toEqual({downloadUrl:downloadUrl,
downloadParams:downloadParams,originalValue:statEntry,type:"__DownloadableStatEntry"})});it("replaces aff4path recursively in ApiHuntResult",()=>{const apiHuntResult={value:{payload:angular.copy(statEntry)},type:"ApiHuntResult"};expect(makeValueDownloadable(apiHuntResult,downloadUrl,downloadParams)).toBe(true);expect(apiHuntResult.value.payload).toEqual({downloadUrl:downloadUrl,downloadParams:downloadParams,originalValue:statEntry,type:"__DownloadableStatEntry"})});it("does nothing in other aff4 types",
()=>{const original=angular.copy(rdfstring);expect(makeValueDownloadable(original,downloadUrl,downloadParams)).toBe(false)});it("does nothing for other types wrapped in ApiFlowResult",()=>{const apiFlowResult={value:{payload:angular.copy(rdfstring)},type:"ApiFlowResult"};expect(makeValueDownloadable(apiFlowResult,downloadUrl,downloadParams)).toBe(false)});it("does nothing for other types wrapped in ApiHuntResult",()=>{const apiHuntResult={value:{payload:angular.copy(rdfstring)},type:"ApiHuntResult"};
expect(makeValueDownloadable(apiHuntResult,downloadUrl,downloadParams)).toBe(false)})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.firebaseServiceTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");window.firebase=window.firebase||{};describe("API service",()=>{let $http;let $q;let $rootScope;let grrApiService;let grrFirebaseService;let fbAuthResult;let redirectDeferred;beforeEach(module(coreModule.name));beforeEach(inject(($injector)=>{$rootScope=$injector.get("$rootScope");$http=$injector.get("$http");$q=$injector.get("$q");grrApiService=
$injector.get("grrApiService");grrFirebaseService=$injector.get("grrFirebaseService");redirectDeferred=$q.defer();fbAuthResult={getRedirectResult:jasmine.createSpy("getRedirectResult").and.returnValue(redirectDeferred.promise),onAuthStateChanged:jasmine.createSpy("onAuthStateChanged"),signInWithRedirect:jasmine.createSpy("signInWithRedirect")};firebase={auth:jasmine.createSpy("auth").and.returnValue(fbAuthResult),apps:[{options:{authProvider:"GoogleAuthProvider"}}]};firebase.auth.GoogleAuthProvider=
jasmine.createSpy("GoogleAuthProvider")}));it("does nothing and marks auth done on no firebase apps",()=>{firebase.apps=[];spyOn(grrApiService,"markAuthDone");grrFirebaseService.setupIfNeeded();$rootScope.$apply();expect(firebase.auth).not.toHaveBeenCalled();expect(grrApiService.markAuthDone).toHaveBeenCalled()});it("adjusts headers and marks auth done when user authenticates",()=>{const tokenDeferred=$q.defer();tokenDeferred.resolve("blah");const user={getToken:jasmine.createSpy("getToken").and.returnValue(tokenDeferred.promise)};
fbAuthResult.onAuthStateChanged.and.callFake((fn)=>{fn(user)});spyOn(grrApiService,"markAuthDone");grrFirebaseService.setupIfNeeded();$rootScope.$apply();expect(fbAuthResult.onAuthStateChanged).toHaveBeenCalled();expect(fbAuthResult.signInWithRedirect).not.toHaveBeenCalled();expect(grrApiService.markAuthDone).toHaveBeenCalled();expect($http.defaults.headers["common"]["Authorization"]).toBe("Bearer blah")});it("redirects to sign-in flow if the user is not authenticated",()=>{fbAuthResult.onAuthStateChanged.and.callFake((fn)=>
{fn(undefined)});spyOn(grrApiService,"markAuthDone");grrFirebaseService.setupIfNeeded();$rootScope.$apply();expect(fbAuthResult.onAuthStateChanged).toHaveBeenCalled();expect(fbAuthResult.signInWithRedirect).toHaveBeenCalled();expect(grrApiService.markAuthDone).not.toHaveBeenCalled()});it("marks auth done and does not redirect again on auth error",()=>{const redirectDeferred=$q.defer();redirectDeferred.reject("blah");fbAuthResult.getRedirectResult.and.returnValue(redirectDeferred.promise);spyOn(grrApiService,
"markAuthDone");grrFirebaseService.setupIfNeeded();$rootScope.$apply();expect(grrApiService.markAuthDone).toHaveBeenCalled();expect(fbAuthResult.signInWithRedirect).not.toHaveBeenCalled()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.forceRefreshDirectiveTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("grr-force-refresh directive",()=>{let $compile;let $rootScope;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$rootScope.value=42}));const render=
(objectEquality)=>{$rootScope.objectEquality=objectEquality;const template='<grr-force-refresh object-equality="objectEquality" '+'refresh-trigger="value">'+"{$ ::value $}</grr-force-refresh>";const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows transcluded template immediately",()=>{const element=render();expect(element.text()).toContain("42")});it("reloads children elements effectively updating one-time bindings",()=>{const element=render();expect(element.text()).toContain("42");
$rootScope.value=43;$rootScope.$apply();expect(element.text()).toContain("43")});it("reloads on object-level changes",()=>{$rootScope.value={a:"a"};const element=render(true);expect(element.text()).toContain('{"a":"a"}');$rootScope.value["a"]="b";$rootScope.$apply();expect(element.text()).toContain('{"a":"b"}')})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.hexNumberFilterTest");goog.setTestOnly();const {HexNumberFilter}=goog.require("grrUi.core.hexNumberFilter");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("grrHexNumber filter",()=>{let grrHexNumberFilter;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{grrHexNumberFilter=$injector.instantiate(HexNumberFilter)}));
it("returns the correct hex for different input numbers",()=>{let result=grrHexNumberFilter(0);expect(result).toBe("0x00000000");result=grrHexNumberFilter(255);expect(result).toBe("0x000000ff");result=grrHexNumberFilter(1010101);expect(result).toBe("0x000f69b5");result=grrHexNumberFilter(4294967296-1);expect(result).toBe("0xffffffff")});it("inserts leading 0s to always return a multiple of eight places",()=>{let result=grrHexNumberFilter(1);expect(result).toBe("0x00000001");result=grrHexNumberFilter(4294967296);
expect(result).toBe("0x0000000100000000")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.infiniteTableDirectiveTest");goog.setTestOnly();const {InfiniteTableController}=goog.require("grrUi.core.infiniteTableDirective");const {MemoryItemsProviderController}=goog.require("grrUi.core.memoryItemsProviderDirective");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("infinite table",()=>{let $compile;let $interval;let $q;let $rootScope;beforeEach(module(coreModule.name));
beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$interval=$injector.get("$interval");$q=$injector.get("$q")}));afterEach(()=>{$(document.body).html("")});const render=(items,noDomAppend,filterValue,withAutoRefresh)=>{$rootScope.testItems=items;if(filterValue)$rootScope.filterValue=filterValue;const template="<div>"+"<table>"+"<tbody>"+"<tr grr-infinite-table grr-memory-items-provider "+'    items="testItems" page-size="5"'+
(withAutoRefresh?'    auto-refresh-interval="1" ':"")+'    filter-value="filterValue"'+'    trigger-update="triggerUpdate">'+"  <td>{$ ::item.timestamp $}</td>"+"  <td>{$ ::item.message $}</td>"+"</tr>"+"</tbody"+"</table>"+"</div>";const element=$compile(template)($rootScope);$rootScope.$apply();if(!noDomAppend){$("body").append(element);$interval.flush(1E3)}return element};it("throws if items provider is not specified",()=>{const template="<table><tbody><tr grr-infinite-table />"+"</tbody></table>";
const compiledTemplate=$compile(template);expect(()=>{compiledTemplate($rootScope)}).toThrow(Error("Data provider not specified."))});it("shows empty table when there are no elements",()=>{const element=render([]);expect($("table",element).length).toBe(1);expect($("table tr",element).length).toBe(0)});it("shows 2 rows for 2 items",()=>{const element=render([{timestamp:42,message:"foo"},{timestamp:43,message:"bar"}]);expect($("table",element).length).toBe(1);expect($("table tr",element).length).toBe(2);
expect($("table tr:eq(0) td:eq(0):contains(42)",element).length).toBe(1);expect($("table tr:eq(0) td:eq(1):contains(foo)",element).length).toBe(1);expect($("table tr:eq(1) td:eq(0):contains(43)",element).length).toBe(1);expect($("table tr:eq(1) td:eq(1):contains(bar)",element).length).toBe(1)});it('does nothing when "Loading..." row is not seen',()=>{const element=render([{timestamp:42,message:"foo"},{timestamp:43,message:"bar"}],true);expect($("table",element).length).toBe(1);expect($("table tr",
element).length).toBe(1);expect($('table tr:contains("Loading...")',element).length).toBe(1);$interval.flush(1E3);expect($("table tr",element).length).toBe(1);expect($('table tr:contains("Loading...")',element).length).toBe(1);$("body").append(element);$interval.flush(1E3);expect($("table tr",element).length).toBe(2);expect($('table tr:contains("Loading...")',element).length).toBe(0);expect($("table tr:eq(0) td:eq(0):contains(42)",element).length).toBe(1);expect($("table tr:eq(0) td:eq(1):contains(foo)",
element).length).toBe(1);expect($("table tr:eq(1) td:eq(0):contains(43)",element).length).toBe(1);expect($("table tr:eq(1) td:eq(1):contains(bar)",element).length).toBe(1)});it("applies the filter when a filter value is set",()=>{const element=render([{timestamp:42,message:"foo"},{timestamp:43,message:"bar"}],false,"foo");expect($("table",element).length).toBe(1);expect($("table tr",element).length).toBe(1);expect($("table tr:eq(0) td:eq(0):contains(42)",element).length).toBe(1);expect($("table tr:eq(0) td:eq(1):contains(foo)",
element).length).toBe(1)});it("shows an empty table when the filter removes all items",()=>{const element=render([{timestamp:42,message:"foo"},{timestamp:43,message:"bar"}],false,"xxx");expect($("table",element).length).toBe(1);expect($("table tr",element).length).toBe(0)});it("cancels an in-flight request when trigger-update is called",()=>{const deferred1=$q.defer();const deferred2=$q.defer();spyOn(MemoryItemsProviderController.prototype,"fetchItems").and.returnValues(deferred1.promise,deferred2.promise);
const element=render([]);expect($("table tr",element).length).toBe(1);$rootScope.triggerUpdate();$interval.flush(1E3);deferred2.resolve({offset:0,items:[{timestamp:44,message:"foo2"},{timestamp:45,message:"bar2"}]});$rootScope.$apply();deferred1.resolve({offset:0,items:[{timestamp:42,message:"foo1"},{timestamp:43,message:"bar1"}]});$rootScope.$apply();expect($('td:contains("foo2")',element).length).toBe(1);expect($('td:contains("bar2")',element).length).toBe(1);expect($('td:contains("bar1")',element).length).toBe(0);
expect($('td:contains("bar1")',element).length).toBe(0)});describe("with auto refresh turned on",()=>{const TABLE_KEY=InfiniteTableController.UNIQUE_KEY_NAME;const ROW_HASH=InfiniteTableController.ROW_HASH_NAME;const transformItems=(items)=>{for(let i=0;i<items.length;++i){const item=items[i];item[TABLE_KEY]=item["message"];item[ROW_HASH]=item["timestamp"]}return items};it("adds new element to the beginning of the list",()=>{const element=render(transformItems([{timestamp:42,message:"foo"},{timestamp:43,
message:"bar"}]),undefined,undefined,true);expect($("table",element).length).toBe(1);expect($("table tr",element).length).toBe(2);$rootScope.testItems.push(transformItems([{timestamp:44,message:"blah"}])[0]);$interval.flush(1E3);expect($("table tr",element).length).toBe(3);expect($("table tr:eq(0) td:eq(0):contains(44)",element).length).toBe(1);expect($("table tr:eq(0) td:eq(1):contains(blah)",element).length).toBe(1);$interval.flush(2E3);expect($("table tr",element).length).toBe(3);expect($("table tr:eq(0) td:eq(0):contains(44)",
element).length).toBe(1);expect($("table tr:eq(0) td:eq(1):contains(blah)",element).length).toBe(1);expect($("table tr:eq(1) td:eq(0):contains(42)",element).length).toBe(1);expect($("table tr:eq(1) td:eq(1):contains(foo)",element).length).toBe(1);expect($("table tr:eq(2) td:eq(0):contains(43)",element).length).toBe(1);expect($("table tr:eq(2) td:eq(1):contains(bar)",element).length).toBe(1)});it("adds multiple new elements in the right order",()=>{const element=render([],undefined,undefined,true);
expect($("table tr",element).length).toBe(0);Array.prototype.push.apply($rootScope.testItems,transformItems([{timestamp:42,message:"foo"},{timestamp:43,message:"bar"}]));$interval.flush(1E3);expect($("table tr",element).length).toBe(2);expect($("table tr:eq(0) td:eq(1):contains(foo)",element).length).toBe(1);expect($("table tr:eq(1) td:eq(1):contains(bar)",element).length).toBe(1)});it("does nothing with the row if row hash has not changed",()=>{const element=render(transformItems([{timestamp:42,
message:"foo"},{timestamp:43,message:"bar"}]),undefined,undefined,true);expect($("table tr:eq(0) td:eq(0):contains(42)",element).length).toBe(1);$rootScope.testItems[0]["timestamp"]=88;$interval.flush(2E3);expect($("table tr:eq(0) td:eq(0):contains(42)",element).length).toBe(1)});it("updates the row if row hash has changed",()=>{const element=render(transformItems([{timestamp:42,message:"foo"},{timestamp:43,message:"bar"}]),undefined,undefined,true);expect($("table tr:eq(0) td:eq(0):contains(42)",
element).length).toBe(1);$rootScope.testItems[0]["timestamp"]=88;transformItems($rootScope.testItems);$interval.flush(2E3);expect($("table tr:eq(0) td:eq(0):contains(88)",element).length).toBe(1)})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.loadingIndicatorDirectiveTest");goog.setTestOnly();const {LoadingIndicatorDirective}=goog.require("grrUi.core.loadingIndicatorDirective");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("loading indicator directive",()=>{const LOADING_STARTED_EVENT_NAME=LoadingIndicatorDirective.loading_started_event_name;const LOADING_FINISHED_EVENT_NAME=LoadingIndicatorDirective.loading_finished_event_name;
let $compile;let $rootScope;let $scope;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$scope=$rootScope.$new()}));const render=()=>{const template="<grr-loading-indicator />";const element=$compile(template)($scope);$scope.$apply();return element};const isVisible=(element)=>!element.find(".ajax_spinner").hasClass("ng-hide");const broadcast=(event,key)=>{$rootScope.$apply(()=>
{$rootScope.$broadcast(event,key)})};it("should be hidden by default",()=>{const element=render();expect(isVisible(element)).toBe(false)});it("should turn visible once a loading started event is fired",()=>{const element=render();expect(isVisible(element)).toBe(false);broadcast(LOADING_STARTED_EVENT_NAME,"some key");expect(isVisible(element)).toBe(true)});it("should turn invisible once a corresponding loading finished event is fired",()=>{const element=render();expect(isVisible(element)).toBe(false);
broadcast(LOADING_STARTED_EVENT_NAME,"some key");expect(isVisible(element)).toBe(true);broadcast(LOADING_FINISHED_EVENT_NAME,"some key");expect(isVisible(element)).toBe(false)});it("should ignore unrelated loading finished events",()=>{const element=render();expect(isVisible(element)).toBe(false);broadcast(LOADING_STARTED_EVENT_NAME,"some key");expect(isVisible(element)).toBe(true);broadcast(LOADING_FINISHED_EVENT_NAME,"some other key");expect(isVisible(element)).toBe(true)});it("should turn invisible once all loading finished events occurred",
()=>{const element=render();expect(isVisible(element)).toBe(false);broadcast(LOADING_STARTED_EVENT_NAME,"some key");broadcast(LOADING_STARTED_EVENT_NAME,"some other key");broadcast(LOADING_STARTED_EVENT_NAME,"one more key");expect(isVisible(element)).toBe(true);broadcast(LOADING_FINISHED_EVENT_NAME,"one more key");expect(isVisible(element)).toBe(true);broadcast(LOADING_FINISHED_EVENT_NAME,"some key");expect(isVisible(element)).toBe(true);broadcast(LOADING_FINISHED_EVENT_NAME,"some other key");expect(isVisible(element)).toBe(false)})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.markdownDirectiveTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("markdown directive",()=>{let $compile;let $rootScope;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(source)=>{$rootScope.source=
source;const template='<grr-markdown source="source"></grr-markdown>';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("renders markdown text",()=>{const element=renderTestTemplate("*blah*");expect(element.html().trim()).toBe("<p><em>blah</em></p>")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.memoryItemsProviderDirectiveTest");goog.setTestOnly();const {MemoryItemsProviderController}=goog.require("grrUi.core.memoryItemsProviderDirective");describe("memory items provider directive",()=>{let $rootScope;beforeEach(inject(($injector)=>{$rootScope=$injector.get("$rootScope")}));const getController=(testItems)=>{$rootScope.testItems=testItems;let controller;inject(($injector)=>{controller=$injector.instantiate(MemoryItemsProviderController,
{"$scope":$rootScope,"$attrs":{"items":"testItems"}})});$rootScope.$apply();return controller};it("fetches ranges of elements according to offset and count",()=>{const controller=getController([0,1,2,3,4,5,6,7,8,9]);let items;controller.fetchItems(0,10).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:[0,1,2,3,4,5,6,7,8,9],offset:0});controller.fetchItems(9,1).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:[9],offset:9});
controller.fetchItems(9,2).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:[9],offset:9})});it("does not return total count when !opt_withTotalCount",()=>{const controller=getController([0,1,2,3,4,5,6,7,8,9]);let items;controller.fetchItems(9,1).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items.totalCount).toBeUndefined()});it("returns total count when opt_withTotalCount is true",()=>{const controller=getController([0,1,2,3,4,5,6,7,
8,9]);let items;controller.fetchItems(9,1,true).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items.totalCount).toEqual(10)});it("fetches ranges of filtered strings",()=>{const controller=getController(["foo","bar","foobar","barfoo"]);let items;controller.fetchFilteredItems("foo",0,10).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:["foo","foobar","barfoo"],offset:0});controller.fetchFilteredItems("foo",0,1).then((resultItems)=>{items=
resultItems});$rootScope.$apply();expect(items).toEqual({items:["foo"],offset:0});controller.fetchFilteredItems("foo",2,1).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:["barfoo"],offset:2})});it("ignores case when filtering strings",()=>{const controller=getController(["FOO","Bar","fooBar","barfoo"]);let items;controller.fetchFilteredItems("foo",0,10).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:["FOO","fooBar",
"barfoo"],offset:0});controller.fetchFilteredItems("BAR",0,10).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:["Bar","fooBar","barfoo"],offset:0})});it("fetches ranges of filtered dictionaries",()=>{const controller=getController([{message:"foo"},{message:"bar"},{message:"foobar"},{message:"barfoo"}]);let items;controller.fetchFilteredItems("foo",0,10).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:[{message:"foo"},
{message:"foobar"},{message:"barfoo"}],offset:0});controller.fetchFilteredItems("foo",0,1).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:[{message:"foo"}],offset:0});controller.fetchFilteredItems("foo",2,1).then((resultItems)=>{items=resultItems});$rootScope.$apply();expect(items).toEqual({items:[{message:"barfoo"}],offset:2})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.pagedFilteredTableDirectiveTest");goog.setTestOnly();const {MemoryItemsProviderController}=goog.require("grrUi.core.memoryItemsProviderDirective");const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {coreModule}=goog.require("grrUi.core.core");describe("paged filtered table",()=>{let $compile;let $interval;let $q;let $rootScope;beforeEach(module("/static/angular-components/core/paged-filtered-table-top.html"));
beforeEach(module("/static/angular-components/core/paged-filtered-table-bottom.html"));beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");$interval=$injector.get("$interval")}));const render=(items,withAutoRefresh)=>{$rootScope.testItems=items;if(withAutoRefresh)$rootScope.autoRefreshInterval=1E3;const template="<div>"+"<table>"+"<tbody>"+"<tr grr-paged-filtered-table grr-memory-items-provider "+
'items="testItems" page-size="5" '+'auto-refresh-interval="autoRefreshInterval">'+"<td>{$ item.timestamp $}</td>"+"<td>{$ item.message $}</td>"+"</tr>"+"</tbody"+"</table>"+"</div>";const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("throws if items provider is not specified",()=>{const template="<div><table><tbody><tr grr-paged-filtered-table />"+"</tbody></table></div>";const compiledTemplate=$compile(template);expect(()=>{compiledTemplate($rootScope)}).toThrow(Error("Data provider not specified."))});
it("shows empty table when there are no elements",()=>{const element=render([]);expect($("table",element).length).toBe(1);expect($("table tr",element).length).toBe(0)});it("shows 2 rows for 2 items",()=>{const element=render([{timestamp:42,message:"foo"},{timestamp:43,message:"bar"}]);expect($("table",element).length).toBe(1);expect($("table tr",element).length).toBe(2);expect(element.text()).toContain("2 entries");expect($("table tr:eq(0) td:eq(0):contains(42)",element).length).toBe(1);expect($("table tr:eq(0) td:eq(1):contains(foo)",
element).length).toBe(1);expect($("table tr:eq(1) td:eq(0):contains(43)",element).length).toBe(1);expect($("table tr:eq(1) td:eq(1):contains(bar)",element).length).toBe(1)});const checkItemsAreShown=(itemsToCheck,element)=>{angular.forEach(itemsToCheck,(item)=>{const foundElems=$("td:contains("+item.message+")",element);expect(foundElems.length).toBe(1)})};const checkItemsAreNotShown=(itemsToCheck,element)=>{angular.forEach(itemsToCheck,(item)=>{const foundElems=$("td:contains("+item.message+")",
element);expect(foundElems.length).toBe(0)})};it("switches between pages correctly when there are 2 pages",()=>{const items=[];for(let i=0;i<10;++i)items.push({timestamp:i,message:"message_"+i.toString()});const element=render(items);checkItemsAreShown(items.slice(0,5),element);checkItemsAreNotShown(items.slice(5),element);browserTriggerEvent($("a:contains(Next)",element),"click");checkItemsAreNotShown(items.slice(0,5),element);checkItemsAreShown(items.slice(5),element);browserTriggerEvent($("a:contains(Previous)",
element),"click");checkItemsAreShown(items.slice(0,5),element);checkItemsAreNotShown(items.slice(5),element)});it("switches between pages correctly when there are 15 pages",()=>{const items=[];for(let i=0;i<5*15;++i)items.push({timestamp:i,message:"message_"+i.toString()});const element=render(items);for(let i=0;i<15;++i){const pageLink=$("a",element).filter(function(){return $(this).text()==(i+1).toString()});browserTriggerEvent(pageLink,"click");checkItemsAreShown(items.slice(i*5,i*5+5),element);
if(i>0)checkItemsAreNotShown(items.slice((i-1)*5,i*5),element);if(i<14)checkItemsAreNotShown(items.slice((i+1)*5,items.length),element)}});it("filters collection of 5 elements correctly",()=>{const someItems=[{message:"some1"},{message:"some2"}];const otherItems=[{message:"other1"},{message:"other2"},{message:"other3"}];const element=render(someItems.concat(otherItems));checkItemsAreShown(someItems,element);checkItemsAreShown(otherItems,element);$("input.search-query",element).val("some");browserTriggerEvent($("input.search-query",
element),"input");browserTriggerEvent($("button:contains(Filter)",element),"click");expect(element.text()).toContain("Filtered by: some");checkItemsAreShown(someItems,element);checkItemsAreNotShown(otherItems,element);$("input.search-query",element).val("");browserTriggerEvent($("input.search-query",element),"input");browserTriggerEvent($("button:contains(Filter)",element),"click");expect(element.text()).not.toContain("Filtered by");checkItemsAreShown(someItems,element);checkItemsAreShown(otherItems,
element)});it('loads more filtered results when "Fetch More" is clicked',()=>{const someItems=[{message:"some1"},{message:"some2"},{message:"some3"},{message:"some4"},{message:"some5"},{message:"some6"},{message:"some7"}];const otherItems=[{message:"other1"},{message:"other2"},{message:"other3"}];const element=render(someItems.concat(otherItems));$("input.search-query",element).val("some");browserTriggerEvent($("input.search-query",element),"input");browserTriggerEvent($("button:contains(Filter)",
element),"click");checkItemsAreShown(someItems.slice(0,5),element);checkItemsAreNotShown(someItems.slice(5),element);checkItemsAreNotShown(otherItems,element);browserTriggerEvent($('button:contains("Fetch More")',element),"click");checkItemsAreShown(someItems,element);checkItemsAreNotShown(otherItems,element)});it('fetches 5 pages of filtered results when "Fetch 5" is clicked',()=>{const someItems=[];for(let i=0;i<35;++i)someItems.push({message:"some_"+i.toString(36)});const otherItems=[];for(let i=
0;i<20;++i)otherItems.push({message:"other"+i.toString(36)});const element=render(someItems.concat(otherItems));$("input.search-query",element).val("some");browserTriggerEvent($("input.search-query",element),"input");browserTriggerEvent($("button:contains(Filter)",element),"click");browserTriggerEvent($('a:contains("Fetch 25")',element),"click");checkItemsAreShown(someItems.slice(0,30),element);checkItemsAreNotShown(someItems.slice(30,35),element);checkItemsAreNotShown(otherItems,element)});describe("with auto-refresh-interval set",
()=>{it("adds new element to the end of the list",()=>{const someItems=[{message:"some1"},{message:"some2"}];const element=render(someItems,true);checkItemsAreShown(someItems,element);someItems.push({message:"some3"});$interval.flush(1E3);checkItemsAreShown(someItems,element)});it("updates total count",()=>{const someItems=[{message:"some1"},{message:"some2"}];const element=render(someItems,true);expect(element.text().indexOf("2 entries")!=-1).toBe(true);for(let i=0;i<5;++i)someItems.push({message:"somethingelse"});
$interval.flush(1E3);expect(element.text().indexOf("7 entries")!=-1).toBe(true)});it("updates paging",()=>{const someItems=[{message:"some1"},{message:"some2"}];const element=render(someItems,true);expect(element.find('ul.pagination li:contains("2")').length).toBe(0);for(let i=0;i<5;++i)someItems.push({message:"somethingelse"});$interval.flush(1E3);expect(element.find('ul.pagination li:contains("2")').length).toBe(1)});it("does not auto-update in filtered mode",()=>{const someItems=[{message:"some1"},
{message:"some2"}];const element=render(someItems,true);$("input.search-query",element).val("some");browserTriggerEvent($("input.search-query",element),"input");browserTriggerEvent($("button:contains(Filter)",element),"click");checkItemsAreShown(someItems,element);someItems.push({message:"some3"});$interval.flush(1E3);checkItemsAreShown(someItems.slice(0,2),element);checkItemsAreNotShown(someItems.slice(2,3),element)});it("does not auto-update if full page is shown",()=>{const someItems=[{message:"some1"},
{message:"some2"},{message:"some3"},{message:"some4"},{message:"some5"}];const element=render(someItems,true);checkItemsAreShown(someItems,element);someItems[0]={message:"someother"};someItems.push({message:"some6"});$interval.flush(1E3);checkItemsAreShown(someItems.slice(1,5),element);checkItemsAreNotShown(someItems.slice(0,1),element);checkItemsAreNotShown(someItems.slice(5,6),element)});it("skips results of the obsolete request if page is changed",()=>{const someItems=[{message:"some1"},{message:"some2"},
{message:"some3"},{message:"some4"},{message:"some5"},{message:"some6"}];const element=render(someItems,true);browserTriggerEvent($("a:contains(Next)",element),"click");checkItemsAreShown(someItems.slice(5),element);const deferred1=$q.defer();const deferred2=$q.defer();spyOn(MemoryItemsProviderController.prototype,"fetchItems").and.returnValue(deferred1.promise).and.returnValue(deferred2.promise);$interval.flush(1E3);browserTriggerEvent($("a:contains(Previous)",element),"click");deferred2.resolve({items:someItems.slice(0,
5)});$rootScope.$apply();checkItemsAreShown(someItems.slice(0,5),element);deferred1.resolve({items:someItems.slice(5,6)});$rootScope.$apply();checkItemsAreShown(someItems.slice(0,5),element);checkItemsAreNotShown(someItems.slice(5,6),element)});it("does not start auto-update request if one is in progress",()=>{const someItems=[{message:"some1"}];render(someItems,true);const deferred=$q.defer();spyOn(MemoryItemsProviderController.prototype,"fetchItems").and.returnValue(deferred.promise);$interval.flush(1E3);
$interval.flush(1E3);expect(MemoryItemsProviderController.prototype.fetchItems).toHaveBeenCalledTimes(1)})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.periodicRefreshDirectiveTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("grr-periodic-refresh directive",()=>{let $compile;let $interval;let $rootScope;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$interval=$injector.get("$interval");$rootScope=$injector.get("$rootScope")}));
it("reloads children elements effectively updating one-time bindings",()=>{$rootScope.value=42;const template='<grr-periodic-refresh interval="1000">'+"{$ ::value $}</grr-periodic-refresh>";const element=$compile(template)($rootScope);$rootScope.$apply();expect(element.text()).toContain("42");$rootScope.value=43;$rootScope.$apply();expect(element.text()).toContain("42");$interval.flush(1001);expect(element.text()).toContain("43")});it("calls a callback on timer",()=>{$rootScope.callback=jasmine.createSpy("callback");
const template='<grr-periodic-refresh interval="1000" '+'on-refresh="callback()"></grr-periodic-refresh>';$compile(template)($rootScope);$rootScope.$apply();expect($rootScope.callback).not.toHaveBeenCalled();$interval.flush(1001);expect($rootScope.callback).toHaveBeenCalled()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.reflectionServiceTest");goog.setTestOnly();const {ReflectionService}=goog.require("grrUi.core.reflectionService");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("AFF4 items provider directive",()=>{let $q;let $rootScope;let grrApiServiceMock;let grrReflectionService;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>
{$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiServiceMock={get:function(){}};grrReflectionService=$injector.instantiate(ReflectionService,{"grrApiService":grrApiServiceMock})}));it("fetches data from the server only once",()=>{const deferred=$q.defer();spyOn(grrApiServiceMock,"get").and.returnValue(deferred.promise);grrReflectionService.getRDFValueDescriptor("Duration");grrReflectionService.getRDFValueDescriptor("RDFDatetime");expect(grrApiServiceMock.get.calls.count()).toBe(1)});
it("queues requests until the data are fetched",()=>{const deferred=$q.defer();spyOn(grrApiServiceMock,"get").and.returnValue(deferred.promise);const responses=[];grrReflectionService.getRDFValueDescriptor("Duration").then((response)=>{responses.push(response)});grrReflectionService.getRDFValueDescriptor("RDFDatetime").then((response)=>{responses.push(response)});expect(responses.length).toBe(0);deferred.resolve({data:{items:[{"doc":"Duration value stored in seconds internally.","kind":"primitive",
"name":"Duration"},{"doc":"Date and time.","kind":"primitive","name":"RDFDatetime"}]}});$rootScope.$apply();expect(responses.length).toBe(2);expect(responses[0]).toEqual({"doc":"Duration value stored in seconds internally.","kind":"primitive","name":"Duration"});expect(responses[1]).toEqual({"doc":"Date and time.","kind":"primitive","name":"RDFDatetime"})});it("returns data with dependencies if opt_withDeps is true",()=>{const deferred=$q.defer();deferred.resolve({data:{items:[{"doc":"Sample struct.",
"kind":"struct","name":"Struct","fields":[{"type":"RDFInteger"}]},{"doc":"Sample integer.","kind":"primitive","name":"RDFInteger"}]}});spyOn(grrApiServiceMock,"get").and.returnValue(deferred.promise);let descriptors;grrReflectionService.getRDFValueDescriptor("Struct",true).then((response)=>{descriptors=response});$rootScope.$apply();expect(descriptors["Struct"]).toBeDefined();expect(descriptors["RDFInteger"]).toBeDefined()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.searchBoxDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,stubUiTrait,testsModule}=goog.require("grrUi.tests");const {coreModule}=goog.require("grrUi.core.core");describe("search box directive",()=>{let $compile;let $q;let $rootScope;let $scope;let grrApiService;let grrRoutingService;beforeEach(module("/static/angular-components/core/search-box.html"));beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));
stubUiTrait("search_clients_action_enabled");beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$scope=$rootScope.$new();$q=$injector.get("$q");grrApiService=$injector.get("grrApiService");grrRoutingService=$injector.get("grrRoutingService")}));const render=()=>{const template="<grr-search-box />";const element=$compile(template)($scope);$scope.$apply();return element};const mockApiServiceResponse=(results)=>{results=results||{};spyOn(grrApiService,
"get").and.callFake((apiPath,params)=>{const value=results[apiPath];if(value)return $q.resolve({data:value});else return $q.reject("Invalid")})};const triggerSearch=(element,query)=>{$("input",element).val(query).trigger("input");browserTriggerEvent($("input",element),"change");browserTriggerEvent($("button",element),"click")};const triggerSearchByKeyboard=(element,query)=>{element.find("input").val(query).trigger("input");$scope.$apply();const event=jQuery.Event("keypress");event.which=13;element.find("input").trigger(event)};
it("should invoke client search on arbitrary input",()=>{mockApiServiceResponse();spyOn(grrRoutingService,"go");const element=render();triggerSearch(element,"test query");expect(grrApiService.get).toHaveBeenCalledWith("/clients/labels");expect(grrRoutingService.go).toHaveBeenCalledWith("search",{q:"test query"})});it("should invoke client search on ENTER in input",()=>{mockApiServiceResponse();spyOn(grrRoutingService,"go");const element=render();triggerSearchByKeyboard(element,"test query");expect(grrApiService.get).toHaveBeenCalledWith("/clients/labels");
expect(grrRoutingService.go).toHaveBeenCalledWith("search",{q:"test query"})});it("should request hunt details if a hunt id is detected",()=>{mockApiServiceResponse();const element=render();triggerSearch(element,"H:12345678");expect(grrApiService.get).toHaveBeenCalledWith("hunts/H:12345678")});it("should forward to the hunt details if a hunt was found",()=>{mockApiServiceResponse({"hunts/H:12345678":{value:{hunt_id:{value:"H:12345678"}}}});spyOn(grrRoutingService,"go");const element=render();triggerSearch(element,
"H:12345678");expect(grrApiService.get).toHaveBeenCalledWith("hunts/H:12345678");expect(grrRoutingService.go).toHaveBeenCalledWith("hunts",{huntId:"H:12345678"})});it("should fall back to regular client search if no hunt was found",()=>{mockApiServiceResponse();spyOn(grrRoutingService,"go");const element=render();triggerSearch(element,"H:12345678");expect(grrApiService.get).toHaveBeenCalledWith("hunts/H:12345678");expect(grrRoutingService.go).toHaveBeenCalledWith("search",{q:"H:12345678"})});it("should check that potential hunt ids cannot start with search keywords",
()=>{mockApiServiceResponse();spyOn(grrRoutingService,"go");const element=render();triggerSearch(element,"HOST:12345678");triggerSearch(element,"FQDN:12345678");triggerSearch(element,"MAC:12345678");triggerSearch(element,"IP:12345678");triggerSearch(element,"USER:12345678");triggerSearch(element,"LABEL:12345678");expect(grrRoutingService.go).not.toHaveBeenCalledWith("hunts",{huntId:"HOST:12345678"});expect(grrRoutingService.go).not.toHaveBeenCalledWith("hunts",{huntId:"FQDN:12345678"});expect(grrRoutingService.go).not.toHaveBeenCalledWith("hunts",
{huntId:"MAC:12345678"});expect(grrRoutingService.go).not.toHaveBeenCalledWith("hunts",{huntId:"IP:12345678"});expect(grrRoutingService.go).not.toHaveBeenCalledWith("hunts",{huntId:"USER:12345678"});expect(grrRoutingService.go).not.toHaveBeenCalledWith("hunts",{huntId:"LABEL:12345678"});expect(grrRoutingService.go).toHaveBeenCalledWith("search",{q:"HOST:12345678"});expect(grrRoutingService.go).toHaveBeenCalledWith("search",{q:"FQDN:12345678"});expect(grrRoutingService.go).toHaveBeenCalledWith("search",
{q:"MAC:12345678"});expect(grrRoutingService.go).toHaveBeenCalledWith("search",{q:"IP:12345678"});expect(grrRoutingService.go).toHaveBeenCalledWith("search",{q:"USER:12345678"});expect(grrRoutingService.go).toHaveBeenCalledWith("search",{q:"LABEL:12345678"})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.semanticRegistryServiceTest");goog.setTestOnly();const {SemanticRegistryService}=goog.require("grrUi.core.semanticRegistryService");const {coreModule}=goog.require("grrUi.core.core");describe("Semantic registry",()=>{let $q;let $rootScope;let grrReflectionService;let testRegistry;beforeEach(module(coreModule.name));beforeEach(inject(($injector)=>{$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrReflectionService=
$injector.get("grrReflectionService");testRegistry=$injector.instantiate(SemanticRegistryService,{})}));describe("findDirectiveForMro",()=>{it("finds previously registered directive",()=>{testRegistry.registerDirective("SomeType",Object);const foundDirective=testRegistry.findDirectiveForMro(["SomeType"]);expect(foundDirective).toBe(Object)});it("returns undefined when searching for not registered directive",()=>{const foundDirective=testRegistry.findDirectiveForMro(["SomeType"]);expect(foundDirective).toBeUndefined()});
it("returns more specific directive when multiple directives match",()=>{const directive1=Object();const directive2=Object();testRegistry.registerDirective("SomeChildType",directive1);testRegistry.registerDirective("SomeParentType",directive2);const foundDirective=testRegistry.findDirectiveForMro(["SomeChildType","SomeParentType"]);expect(foundDirective).toBe(directive1)});it("respects override for a type without directive",()=>{const someDirective=Object();const foundDirective=testRegistry.findDirectiveForMro(["SomeType"],
{"SomeType":someDirective});expect(foundDirective).toBe(someDirective)});it("respects override for a single and only MRO type",()=>{const someDirective=Object();const directiveOverride=Object();testRegistry.registerDirective("SomeType",someDirective);const foundDirective=testRegistry.findDirectiveForMro(["SomeType"],{"SomeType":directiveOverride});expect(foundDirective).toBe(directiveOverride)});it("respects override for a non-leaf MRO type",()=>{const someDirective=Object();const directiveOverride=
Object();testRegistry.registerDirective("SomeParentType",someDirective);const foundDirective=testRegistry.findDirectiveForMro(["SomeChildType","SomeParentType"],{"SomeParentType":directiveOverride});expect(foundDirective).toBe(directiveOverride)});it("respects override for a leaf MRO type",()=>{const directive1=Object();const directive2=Object();testRegistry.registerDirective("SomeChildType",directive1);testRegistry.registerDirective("SomeParentType",directive2);const directiveOverride=Object();const foundDirective=
testRegistry.findDirectiveForMro(["SomeChildType","SomeParentType"],{"SomeChildType":directiveOverride});expect(foundDirective).toBe(directiveOverride)})});describe("findDirectiveByType",()=>{it("returns registered directive without using reflection",(done)=>{testRegistry.registerDirective("SomeType",Object);const promise=testRegistry.findDirectiveForType("SomeType");promise.then((value)=>{expect(value).toBe(Object);done()});$rootScope.$apply()});it("returns overridden directive without using reflection",
(done)=>{const someDirective=Object();const directiveOverride=Object();testRegistry.registerDirective("SomeType",someDirective);const promise=testRegistry.findDirectiveForType("SomeType",{"SomeType":directiveOverride});promise.then((value)=>{expect(value).toBe(directiveOverride);done()});$rootScope.$apply()});it("queries reflection service for MRO if type unregistered",(done)=>{testRegistry.registerDirective("SomeParentType",Object);const deferred=$q.defer();deferred.resolve({mro:["SomeChildType",
"SomeParentType"]});grrReflectionService.getRDFValueDescriptor=jasmine.createSpy("getRDFValueDescriptor").and.returnValue(deferred.promise);const promise=testRegistry.findDirectiveForType("SomeChildType");promise.then((value)=>{expect(grrReflectionService.getRDFValueDescriptor).toHaveBeenCalled();expect(value).toBe(Object);done()});$rootScope.$apply()});it("respects overrides for parent types",()=>{const someDirective=Object();const directiveOverride=Object();testRegistry.registerDirective("SomeParentType",
someDirective);const deferred=$q.defer();deferred.resolve({mro:["SomeChildType","SomeParentType"]});grrReflectionService.getRDFValueDescriptor=jasmine.createSpy("getRDFValueDescriptor").and.returnValue(deferred.promise);const promise=testRegistry.findDirectiveForType("SomeChildType",{"SomeParentType":directiveOverride});promise.then((value)=>{expect(grrReflectionService.getRDFValueDescriptor).toHaveBeenCalled();expect(value).toBe(directiveOverride);done()});$rootScope.$apply()})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.serverErrorButtonDirectiveTest");goog.setTestOnly();const {ServerErrorButtonDirective}=goog.require("grrUi.core.serverErrorButtonDirective");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("server error button directive",()=>{const ERROR_EVENT_NAME=ServerErrorButtonDirective.error_event_name;let $compile;let $rootScope;let $scope;beforeEach(module("/static/angular-components/core/server-error-button.html"));
beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$scope=$rootScope.$new()}));const render=()=>{const template="<grr-server-error-button />";const element=$compile(template)($scope);$scope.$apply();return element};const isVisible=(element)=>!element.hasClass("ng-hide");it("should be hidden by default",()=>{const element=render();expect(isVisible(element)).toBe(false)});
it("should turn visible once a non-empty server error event is fired",()=>{const element=render();expect(isVisible(element)).toBe(false);$scope.$apply(()=>{$rootScope.$broadcast(ERROR_EVENT_NAME,{message:"some event value"})});expect(isVisible(element)).toBe(true)});it("should ignore empty server error events",()=>{const element=render();expect(isVisible(element)).toBe(false);$scope.$apply(()=>{$rootScope.$broadcast(ERROR_EVENT_NAME)});expect(isVisible(element)).toBe(false)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.serverErrorDialogDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {coreModule}=goog.require("grrUi.core.core");describe("server error dialog directive",()=>{let $compile;let $rootScope;let $scope;beforeEach(module("/static/angular-components/core/server-error-dialog.html"));beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>
{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$scope=$rootScope.$new()}));const render=(message,traceBack)=>{$scope.close=()=>{};$scope.message=message;$scope.traceBack=traceBack;const template='<grr-server-error-dialog close="close()" message="message" trace-back="traceBack" />';const element=$compile(template)($scope);$scope.$apply();return element};it("should show a basic error message and traceback",()=>{const message="Some error message";const traceBack="Some trace back";
const element=render(message,traceBack);expect(element.find(".modal-header h3").text()).toBe(message);expect(element.find(".modal-body pre").text()).toBe(traceBack)});it("should operate on empty input",()=>{const message="";const traceBack="";const element=render(message,traceBack);expect(element.find(".modal-header h3").text()).toBe(message);expect(element.find(".modal-body pre").text()).toBe(traceBack)});it("should call scope.close when clicking the X",()=>{const message="...";const traceBack="...";
const element=render(message,traceBack);spyOn($scope,"close");browserTriggerEvent(element.find(".modal-header button"),"click");expect($scope.close).toHaveBeenCalled()});it("should call scope.close when clicking the close button",()=>{const message="...";const traceBack="...";const element=render(message,traceBack);spyOn($scope,"close");browserTriggerEvent(element.find(".modal-footer button"),"click");expect($scope.close).toHaveBeenCalled()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.serverErrorPreviewDirectiveTest");goog.setTestOnly();const {ServerErrorButtonDirective}=goog.require("grrUi.core.serverErrorButtonDirective");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("server error preview directive",()=>{const ERROR_EVENT_NAME=ServerErrorButtonDirective.error_event_name;let $compile;let $rootScope;let $scope;beforeEach(module(coreModule.name));
beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$scope=$rootScope.$new()}));const render=()=>{const template="<grr-server-error-preview />";const element=$compile(template)($scope);$scope.$apply();return element};const isVisible=(element)=>!element.hasClass("ng-hide");it("should be hidden by default",()=>{const element=render();expect(isVisible(element)).toBe(false)});it("should show error message once a non-empty server error event is fired",
()=>{const errorMessage="some event value";const element=render();expect(isVisible(element)).toBe(false);$scope.$apply(()=>{$rootScope.$broadcast(ERROR_EVENT_NAME,{message:errorMessage})});expect(isVisible(element)).toBe(true);expect(element.text().trim()).toBe(errorMessage)});it("should ignore empty server error events",()=>{const element=render();expect(isVisible(element)).toBe(false);$scope.$apply(()=>{$rootScope.$broadcast(ERROR_EVENT_NAME)});expect(isVisible(element)).toBe(false)})});exports=
{};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.splitterDirectiveTest");goog.setTestOnly();const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("grr-splitter directive",()=>{let $compile;let $rootScope;let $interval;const splitSpy=jasmine.createSpy("Split");let prevSplit;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=
$injector.get("$rootScope");$interval=$injector.get("$interval")}));beforeEach(()=>{prevSplit=window.Split;window.Split=splitSpy});afterEach(()=>{window.Split=prevSplit});const renderTestTemplate=(template)=>{const element=$compile(template)($rootScope);element.css({"width":"300px",height:"300px"});$interval.flush(101);$rootScope.$apply();return element};it("calls Split() correctly for a simple horizontal splitter",()=>{const element=renderTestTemplate(`\n<div grr-splitter orientation="horizontal">\n  <div grr-splitter-pane></div>\n  <div grr-splitter-pane></div>\n</div>\n`);
expect(splitSpy).toHaveBeenCalled();const lastArgs=splitSpy.calls.mostRecent().args;expect(lastArgs).toEqual([element.find("div[grr-splitter-pane]").toArray(),{gutterSize:4,sizes:[50,50],direction:"vertical"}])});it("calls Split() correctly for a simple vertical splitter",()=>{const element=renderTestTemplate(`\n<div grr-splitter orientation="vertical">\n  <div grr-splitter-pane></div>\n  <div grr-splitter-pane></div>\n</div>\n`);expect(splitSpy).toHaveBeenCalled();const lastArgs=splitSpy.calls.mostRecent().args;
expect(lastArgs).toEqual([element.find("div[grr-splitter-pane]").toArray(),{gutterSize:4,sizes:[50,50],direction:"horizontal"}])});it("calls Split() correctly for a vertical splitter with sizes set",()=>{const element=renderTestTemplate(`\n<div grr-splitter orientation="vertical">\n  <div grr-splitter-pane size="25"></div>\n  <div grr-splitter-pane></div>\n</div>\n`);expect(splitSpy).toHaveBeenCalled();const lastArgs=splitSpy.calls.mostRecent().args;expect(lastArgs).toEqual([element.find("div[grr-splitter-pane]").toArray(),
{gutterSize:4,sizes:[25,75],direction:"horizontal"}])});it("correctly fills-in missing sizes if some are not specified",()=>{})});return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.timeSinceFilterTest");goog.setTestOnly();const {TimeSinceFilter}=goog.require("grrUi.core.timeSinceFilter");const {clientModule}=goog.require("grrUi.client.client");const {testsModule}=goog.require("grrUi.tests");describe("grrTimeSince filter",()=>{let grrTimeSinceFilter;const referenceTime=5*60*60*24*1E6;beforeEach(module(clientModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{grrTimeSinceFilter=
$injector.instantiate(TimeSinceFilter,{"grrTimeService":{"getCurrentTimeMs":function(){return referenceTime/1E3}}})}));it("returns seconds when value is 42 seconds ago",()=>{const result=grrTimeSinceFilter(referenceTime-42*1E6);expect(result).toBe("42 seconds ago")});it("returns hours when value is 3 hours ago",()=>{const result=grrTimeSinceFilter(referenceTime-(60*60*3+42)*1E6);expect(result).toBe("3 hours ago")});it("returns days when value is 3 days ago",()=>{const result=grrTimeSinceFilter(referenceTime-
(60*60*24*3+42)*1E6);expect(result).toBe("3 days ago")});it("returns seconds when value is 42 seconds in the future",()=>{const result=grrTimeSinceFilter(referenceTime+42*1E6);expect(result).toBe("in 42 seconds")});it("returns hours when value is 3 hours in the future",()=>{const result=grrTimeSinceFilter(referenceTime+(60*60*3+42)*1E6);expect(result).toBe("in 3 hours")});it("returns days when value is 3 days in the future",()=>{const result=grrTimeSinceFilter(referenceTime+(60*60*24*3+42)*1E6);expect(result).toBe("in 3 days")});
it("returns error message when value is 0",()=>{const result=grrTimeSinceFilter(0);expect(result).toBe("<invalid time value>")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.timestampFilterTest");goog.setTestOnly();const {TimestampFilter}=goog.require("grrUi.core.timestampFilter");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("grrTimestamp filter",()=>{const MICRO_IN_MILLI=1E3;const MILLI_IN_UNIT=1E3;const SECONDS=MICRO_IN_MILLI*MILLI_IN_UNIT;const MINUTES=60*SECONDS;let grrTimestampFilter;beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{grrTimestampFilter=$injector.instantiate(TimestampFilter)}));it("returns reference date on 0",()=>{const result=grrTimestampFilter(0);expect(result).toBe("1970-01-01 00:00:00 UTC")});it("returns correct value for seconds",()=>{const result=grrTimestampFilter(42*SECONDS);expect(result).toBe("1970-01-01 00:00:42 UTC")});it("returns correct value for minutes",()=>{const result=grrTimestampFilter(10*MINUTES+42*SECONDS);expect(result).toBe("1970-01-01 00:10:42 UTC")})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.troggleDirectiveTest");goog.setTestOnly();const {TroggleDirective,TroggleState}=goog.require("grrUi.core.troggleDirective");const {coreModule}=goog.require("grrUi.core.core");describe("Troggle",()=>{let $compile;let $rootScope;beforeEach(module(TroggleDirective().templateUrl));beforeEach(module(coreModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const render=
(state)=>{const template=`<grr-troggle ng-model="state" />`;const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("correctly renders `VOID` state",()=>{$rootScope.state=TroggleState.VOID;let element=render();expect(element.text().trim()).toBe("_")});it("correctly renders `SET` state",()=>{$rootScope.state=TroggleState.SET;let element=render();expect(element.text().trim()).toBe("\u2713")});it("correctly renders `UNSET` state",()=>{$rootScope.state=TroggleState.UNSET;let element=
render();expect(element.text().trim()).toBe("\u2715")});it("changes states when clicked",()=>{$rootScope.state=TroggleState.VOID;let element=render();element.find(":first-child").click();expect(element.text().trim()).toBe("\u2713");expect($rootScope.state).toBe(TroggleState.SET);element.find(":first-child").click();expect(element.text().trim()).toBe("\u2715");expect($rootScope.state).toBe(TroggleState.UNSET);element.find(":first-child").click();expect(element.text().trim()).toBe("_");expect($rootScope.state).toBe(TroggleState.VOID)})});
return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.utilsTest");goog.setTestOnly();const {camelCaseToDashDelimited,getLastPathComponent,stringToList}=goog.require("grrUi.core.utils");describe("core utils",()=>{describe("camelCaseToDashDelimited",()=>{it("returns a dash delimited string on camel case input",()=>{const result=camelCaseToDashDelimited("someTestInput");expect(result).toBe("some-test-input")});it("replaces spaces with dashes",()=>{const result=camelCaseToDashDelimited("some string with spaces");
expect(result).toBe("some-string-with-spaces")});it("handles non-word characters by substitution with dash",()=>{const result=camelCaseToDashDelimited("some string with $ symbols");expect(result).toBe("some-string-with-symbols")});it("handles uppercase abbreviations correctly",()=>{let result=camelCaseToDashDelimited("someDDirectiveName");expect(result).toBe("some-d-directive-name");result=camelCaseToDashDelimited("someDDDirectiveName");expect(result).toBe("some-d-d-directive-name")});it("handles string beginning with uppercase characters correctly",
()=>{const result=camelCaseToDashDelimited("SOMEUppercaseString");expect(result).toBe("s-o-m-e-uppercase-string")})});describe("stringToList",()=>{it("returns empty list for empty string",()=>{const result=stringToList("");expect(result).toEqual([])});it("splits 3 items correctly",()=>{const result=stringToList("a, b, c");expect(result).toEqual(["a","b","c"])});it("trims spaces from elements",()=>{const result=stringToList("a  , b  ,c ");expect(result).toEqual(["a","b","c"])})});describe("getLastPathComponent",
()=>{it("returns empty string for an empty string",()=>{expect(getLastPathComponent("")).toBe("")});it("returns correct last component",()=>{expect(getLastPathComponent("foo")).toBe("foo");expect(getLastPathComponent("foo/bar")).toBe("bar");expect(getLastPathComponent("foo/bar/blah")).toBe("blah")})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.versionDropdownDirectiveTest");goog.setTestOnly();const {VersionDropdownDirective}=goog.require("grrUi.core.versionDropdownDirective");const {coreModule}=goog.require("grrUi.core.core");const {testsModule}=goog.require("grrUi.tests");describe("version dropdown directive",()=>{let $compile;let $q;let $rootScope;let $scope;let grrApiService;const REFRESH_VERSIONS_EVENT=VersionDropdownDirective.REFRESH_VERSIONS_EVENT;beforeEach(module("/static/angular-components/core/version-dropdown.html"));
beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService");$scope=$rootScope.$new()}));const render=(url,version)=>{$scope.url=url;$scope.version={data:version};const template='<grr-version-dropdown url="url" version="version.data" />';const element=$compile(template)($scope);$scope.$apply();return element};const mockApiService=
(responses)=>{spyOn(grrApiService,"get").and.callFake((path)=>{const response={times:responses[path]};return $q.when({data:response})})};it("shows HEAD as the first element in the versions list",()=>{mockApiService({"some/url":[{value:10}]});const element=render("some/url");expect(element.find("option").length).toBe(2);expect(element.find("option:nth(0)").val()).toBe("HEAD")});it("selects HEAD if not version specified",()=>{mockApiService({"some/url":[{value:10}]});const element=render("some/url");
expect(element.find("option[selected]").val()).toBe("HEAD")});it("should show all versions from server and select the passed one",()=>{mockApiService({"some/url":[{value:10},{value:42},{value:50}]});const element=render("some/url",42);expect(element.find("option").length).toBe(4);expect(element.find("option[selected]").val()).toBe("42");expect($scope.version.data).toBe(42)});it("should show add current version to the server versions list",()=>{mockApiService({"some/url":[{value:10},{value:41},{value:50}]});
const element=render("some/url",42);expect(element.find("option").length).toBe(5);expect(element.find("option[selected]").val()).toBe("42");expect($scope.version.data).toBe(42)});it("shows hint when a version other than the latest is shown",()=>{mockApiService({"some/url":[{value:10},{value:42},{value:50}]});const element=render("some/url",42);expect(element.find(".newer-version-hint").length).toBe(1)});it("does not show a hint when a newest version  is shown",()=>{mockApiService({"some/url":[{value:10},
{value:42},{value:50}]});const element=render("some/url",50);expect(element.find(".newer-version-hint").length).toBe(0)});it("should update the selected option on scope value change",()=>{mockApiService({"some/url":[{value:10},{value:42},{value:50}]});const element=render("some/url",42);expect(element.find("option").length).toBe(4);expect(element.find("option[selected]").val()).toBe("42");expect($scope.version.data).toBe(42);$scope.version.data=50;$scope.$apply();expect(element.find("option").length).toBe(4);
expect(element.find("option[selected]").val()).toBe("50");$scope.version.data=99;$scope.$apply();expect(element.find("option").length).toBe(5);expect(element.find("option[selected]").val()).toBe("99")});it("should be disabled when no options are available",()=>{mockApiService({"some/url":[]});const element=render("some/url",42);expect(element.find("select[disabled]").length).toBe(1);expect(element.find("option[selected]").text().trim()).toBe("No versions available.");expect($scope.version.data).toBe(42)});
it("should fetch versions again when a REFRESH_VERSIONS_EVENT is broadcasted",()=>{const items=[];mockApiService({"some/url":items});const element=render("some/url");expect(element.find("select[disabled]").length).toBe(1);expect(element.find("option[selected]").text().trim()).toBe("No versions available.");items.push({value:10});items.push({value:42});$rootScope.$broadcast(REFRESH_VERSIONS_EVENT,{});$rootScope.$apply();expect(element.find("select[disabled]").length).toBe(0);expect(element.find("option").length).toBe(3);
expect(element.find("option[selected]").val()).toBe("HEAD");expect($scope.version.data).toBeUndefined()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.wizardFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {coreModule}=goog.require("grrUi.core.core");describe("grr-wizard-form directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/core/wizard-form.html"));beforeEach(module("/static/angular-components/core/wizard-form-page.html"));beforeEach(module(coreModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(template)=>{if(angular.isUndefined(template))template='<grr-wizard-form title="Test wizard form" '+'on-resolve="resolved = true" on-reject="rejected = true">'+'<grr-wizard-form-page title="Page 1" next-button-label="go on!">'+"foo</grr-wizard-form-page>"+'<grr-wizard-form-page title="Page 2" prev-button-label="go back!">'+"bar</grr-wizard-form-page>"+"</grr-wizard-form>";
const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows first page by default",()=>{const element=renderTestTemplate();expect(element.text()).toContain("Page 1");expect(element.text()).not.toContain("Page 2")});it('clicking on "Next" button shows next page',()=>{const element=renderTestTemplate();browserTriggerEvent(element.find("button.Next"),"click");expect(element.text()).toContain("Page 2");expect(element.text()).not.toContain("Page 1")});it('clicking on "Back" button shows previous page',
()=>{const element=renderTestTemplate();browserTriggerEvent(element.find("button.Next"),"click");browserTriggerEvent(element.find("button.Back"),"click");expect(element.text()).toContain("Page 1");expect(element.text()).not.toContain("Page 2")});it('hides "Back" button on the first page',()=>{const element=renderTestTemplate();expect(element.find("button.Back[disabled]").length).toBe(0)});it('shows "Back" button on the second page',()=>{const element=renderTestTemplate();browserTriggerEvent(element.find("button.Next"),
"click");expect(element.find("button.Back[disabled]").length).toBe(0)});it('hides "Back" button if page\'s noBackButton is true',()=>{const element=renderTestTemplate("<grr-wizard-form>"+'<grr-wizard-form-page title="Page 1">foo</grr-wizard-form-page>'+'<grr-wizard-form-page title="Page 2" no-back-button="flag">bar'+"</grr-wizard-form-page>"+"</grr-wizard-form>");browserTriggerEvent(element.find("button.Next"),"click");expect(element.find("button.Back").length).toBe(1);$rootScope.flag=true;$rootScope.$apply();
expect(element.find("button.Back").length).toBe(0)});it('disables "Next" button if current page reports as invalid',()=>{const element=renderTestTemplate("<grr-wizard-form>"+'<grr-wizard-form-page title="Page 1" is-valid="flag">foo'+"</grr-wizard-form-page>"+"</grr-wizard-form>");expect(element.find("button.Next[disabled]").length).toBe(1);$rootScope.flag=true;$rootScope.$apply();expect(element.find("button.Next:not([disabled])").length).toBe(1)});it('takes "Back" button label from page settings',
()=>{const element=renderTestTemplate();browserTriggerEvent(element.find("button.Next"),"click");expect(element.find("button.Back").text().trim()).toBe("go back!")});it('takes "Next" button label from page settings',()=>{const element=renderTestTemplate();expect(element.find("button.Next").text().trim()).toBe("go on!")});it('calls "on-resolve" when "Next" is clicked on last page',()=>{const element=renderTestTemplate();expect($rootScope.resolved).toBeUndefined();browserTriggerEvent(element.find("button.Next"),
"click");expect($rootScope.resolved).toBeUndefined();browserTriggerEvent(element.find("button.Next"),"click");expect($rootScope.resolved).toBe(true)});it('calls "on-reject" when "x" is clicked',()=>{const element=renderTestTemplate();expect($rootScope.rejected).toBeUndefined();browserTriggerEvent(element.find("button.close"),"click");expect($rootScope.rejected).toBe(true)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.docs.apiHelperCurlServiceTest");goog.setTestOnly();const {docsModule}=goog.require("grrUi.docs.docs");describe("ApiHelperCurlService",()=>{let $rootScope;let grrApiHelperCurlService;beforeEach(module(docsModule.name));beforeEach(module(($provide)=>{$provide.value("$window",{location:{origin:"http://localhost:42"}})}));beforeEach(inject(($injector)=>{$rootScope=$injector.get("$rootScope");grrApiHelperCurlService=$injector.get("grrApiHelperCurlService")}));
const startFlowRequest=`CSRFTOKEN=\`curl http://localhost:42 -o /dev/null -s -c - | grep csrftoken  | cut -f 7\`; \\\n\tcurl -X POST -H "Content-Type: application/json" -H "X-CSRFToken: $CSRFTOKEN" \\\n\thttp://localhost:42/api/v2/clients/C.1111222233334444/flows -d @- << EOF\n{\n  "foo": "bar"\n}\nEOF`;it("builds start flow request",function(done){grrApiHelperCurlService.buildStartFlow("C.1111222233334444",{foo:"bar"}).then(((cmd)=>{expect(cmd).toBe(startFlowRequest);done()}).bind(this));$rootScope.$apply()})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.docs.apiHelperServiceTest");goog.setTestOnly();const {docsModule}=goog.require("grrUi.docs.docs");describe("ApiHelperService",()=>{let $q;let $rootScope;let grrApiHelperService;let grrApiService;beforeEach(module(docsModule.name));beforeEach(inject(($injector)=>{$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService");grrApiHelperService=$injector.get("grrApiHelperService");const deferred=
$q.defer();deferred.resolve({data:{value:{type:"RDFString",value:"FooBarAuthManager"}}});spyOn(grrApiService,"getCached").and.returnValue(deferred.promise);grrApiHelperService.clear()}));const fooHelper={buildStartFlow:function(clientId,createFlowJson){const deferred=$q.defer();deferred.resolve(`foo start ${clientId}`);return deferred.promise}};const barHelper={buildStartFlow:function(clientId,createFlowJson){const deferred=$q.defer();deferred.resolve(`bar start ${clientId}`);return deferred.promise}};
it("builds start flow commands with helpers of all types",(done)=>{grrApiHelperService.registerHelper("Foo",null,fooHelper);grrApiHelperService.registerHelper("Bar",null,barHelper);grrApiHelperService.buildStartFlow("C.1111222233334444",{foo:"bar"}).then((result)=>{expect(result).toEqual({"Foo":{webAuthType:null,data:"foo start C.1111222233334444"},"Bar":{webAuthType:null,data:"bar start C.1111222233334444"}});done()});$rootScope.$apply()});it("uses helper with a matching webAuthType, if available",
(done)=>{grrApiHelperService.registerHelper("Foo",null,fooHelper);grrApiHelperService.registerHelper("Foo","FooBarAuthManager",barHelper);grrApiHelperService.buildStartFlow("C.1111222233334444",{foo:"bar"}).then((result)=>{expect(result).toEqual({"Foo":{webAuthType:"FooBarAuthManager",data:"bar start C.1111222233334444"}});done()});$rootScope.$apply()});it("uses helper with null webAuthType if no matches",(done)=>{grrApiHelperService.registerHelper("Foo",null,fooHelper);grrApiHelperService.registerHelper("Foo",
"SomeOtherAuthManager",barHelper);grrApiHelperService.buildStartFlow("C.1111222233334444",{foo:"bar"}).then((result)=>{expect(result).toEqual({"Foo":{webAuthType:null,data:"foo start C.1111222233334444"}});done()});$rootScope.$apply()});it("ignores helpers if no matches and no helper with null webAuthType",(done)=>{grrApiHelperService.registerHelper("Foo","YetAnotherAuthManager",fooHelper);grrApiHelperService.registerHelper("Foo","SomeOtherAuthManager",barHelper);grrApiHelperService.buildStartFlow("C.1111222233334444",
{foo:"bar"}).then((result)=>{expect(result).toEqual({});done()});$rootScope.$apply()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.flow.copyFlowFormDirectiveTest");goog.setTestOnly();const {flowModule}=goog.require("grrUi.flow.flow");const {stubDirective,stubTranscludeDirective,testsModule}=goog.require("grrUi.tests");describe("copy flow form directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;let flowObject;beforeEach(module("/static/angular-components/flow/copy-flow-form.html"));beforeEach(module(flowModule.name));beforeEach(module(testsModule.name));
stubDirective("grrFlowForm");stubTranscludeDirective("grrConfirmationDialog");beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService");flowObject={type:"ApiFlow",value:{args:{type:"FooFlowArgs",value:{aFoo:"aBar"}},runner_args:{type:"FlowRunnerArgs",value:{rFoo:"rBar"}}}};const deferred=$q.defer();deferred.resolve({data:flowObject});spyOn(grrApiService,"get").and.returnValue(deferred.promise)}));
const renderTestTemplate=()=>{$rootScope.clientId="C.0000111122223333";$rootScope.flowId="F:123456";const template="<grr-copy-flow-form "+'client-id="clientId" flow-id="flowId" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("fetches existing flow with correct client id and flow id",()=>{renderTestTemplate();expect(grrApiService.get).toHaveBeenCalledWith("clients/C.0000111122223333/flows/F:123456")});it("sends correct request when grr-confirmation-dialog triggers proceed",
()=>{const element=renderTestTemplate();const directive=element.find("grr-confirmation-dialog");const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);directive.scope().$eval(directive.attr("proceed"));expect(grrApiService.post).toHaveBeenCalledWith("clients/C.0000111122223333/flows",{flow:{args:{aFoo:"aBar"},runner_args:{rFoo:"rBar"}},original_flow:{flow_id:"F:123456",client_id:"C.0000111122223333"}})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.flow.flowDescriptorsTreeDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {flowModule}=goog.require("grrUi.flow.flow");describe("flow descriptors tree directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;let emptySettingsDeferred;beforeEach(module(flowModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");
$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService");emptySettingsDeferred=$q.defer();emptySettingsDeferred.resolve({data:{value:{settings:{value:{}}}}})}));afterEach(()=>{$(document.body).html("")});const renderTestTemplate=()=>{const template="<grr-flow-descriptors-tree "+'selected-descriptor="selectedDescriptor.value" />';const element=$compile(template)($rootScope);$rootScope.selectedDescriptor={value:undefined};$rootScope.$apply();$(document.body).html("");
$(document.body).append(element);$(element.children("div.tree")[0]).on("loaded.jstree",function(e,data){$(this).jstree("open_all")});return element};it("fetches descriptors from the server",()=>{const deferred=$q.defer();spyOn(grrApiService,"get").and.returnValue(deferred.promise);renderTestTemplate();expect(grrApiService.get).toHaveBeenCalledWith("/flows/descriptors")});it("fetches user settings from the server",()=>{const deferred=$q.defer();spyOn(grrApiService,"get").and.returnValue(deferred.promise);
renderTestTemplate();expect(grrApiService.get).toHaveBeenCalledWith("/users/me")});it("creates node per category",(done)=>{const deferred=$q.defer();spyOn(grrApiService,"get").and.callFake((url)=>{if(url=="/users/me")return emptySettingsDeferred.promise;else return deferred.promise});deferred.resolve({data:{items:[{type:"ApiFlowDescriptor",value:{category:{type:"RDFString",value:"Category foo"},name:{type:"RDFString",value:"foo"},friendly_name:{type:"RDFString",value:"friendly foo"},behaviours:[{type:"RDFString",
value:"BASIC"}]}},{type:"ApiFlowDescriptor",value:{category:{type:"RDFString",value:"Category bar"},name:{type:"RDFString",value:"bar"},friendly_name:{type:"RDFString",value:"friendly bar"},behaviours:[{type:"RDFString",value:"BASIC"}]}}]}});const element=renderTestTemplate();element.bind("DOMNodeInserted",(e)=>{if(element.text().indexOf("Category foo")!=-1&&element.text().indexOf("Category bar")!=-1)done()})});it("uses friendly name if available",(done)=>{const deferred=$q.defer();spyOn(grrApiService,
"get").and.callFake((url)=>{if(url=="/users/me")return emptySettingsDeferred.promise;else return deferred.promise});deferred.resolve({data:{items:[{type:"ApiFlowDescriptor",value:{category:{type:"RDFString",value:"Category foo"},name:{type:"RDFString",value:"foo"},friendly_name:{type:"RDFString",value:"friendly foo"},behaviours:[{type:"RDFString",value:"BASIC"}]}}]}});const element=renderTestTemplate();element.bind("DOMNodeInserted",(e)=>{if(element.text().indexOf("friendly foo")!=-1)done()})});it("hides flows without specified behavior",
(done)=>{const advancedSettingsDeferred=$q.defer();advancedSettingsDeferred.resolve({data:{value:{settings:{value:{mode:{value:"ADVANCED"}}}}}});const deferred=$q.defer();deferred.resolve({data:{items:[{type:"ApiFlowDescriptor",value:{category:{type:"RDFString",value:"Category foo"},name:{type:"RDFString",value:"foo"},friendly_name:{type:"RDFString",value:"friendly foo"},behaviours:[{type:"RDFString",value:"BASIC"}]}},{type:"ApiFlowDescriptor",value:{category:{type:"RDFString",value:"Category bar"},
name:{type:"RDFString",value:"bar"},friendly_name:{type:"RDFString",value:"friendly bar"},behaviours:[{type:"RDFString",value:"ADVANCED"}]}}]}});spyOn(grrApiService,"get").and.callFake((url)=>{if(url=="/users/me")return advancedSettingsDeferred.promise;else return deferred.promise});const element=renderTestTemplate();element.bind("DOMNodeInserted",(e)=>{if(element.text().indexOf("friendly bar")!=-1&&element.text().indexOf("friendly foo")==-1)done()})});describe("when clicked",()=>{let element;beforeEach((done)=>
{const deferred=$q.defer();spyOn(grrApiService,"get").and.callFake((url)=>{if(url=="/users/me")return emptySettingsDeferred.promise;else return deferred.promise});deferred.resolve({data:{items:[{type:"ApiFlowDescriptor",value:{category:{type:"RDFString",value:"Category 1"},name:{type:"RDFString",value:"foo"},friendly_name:{type:"RDFString",value:"friendly foo"},behaviours:[{type:"RDFString",value:"BASIC"}]}}]}});element=renderTestTemplate();element.bind("DOMNodeInserted",(e)=>{if(element.text().indexOf("friendly foo")!=
-1)done()})});it("updates selectedDescriptor binding",()=>{expect($rootScope.selectedDescriptor.value).toBeUndefined();browserTriggerEvent(element.find('a:contains("Category 1")'),"click");browserTriggerEvent(element.find('a:contains("friendly foo")'),"click");$rootScope.$apply();expect($rootScope.selectedDescriptor.value).toEqual({type:"ApiFlowDescriptor",value:{category:{type:"RDFString",value:"Category 1"},name:{type:"RDFString",value:"foo"},friendly_name:{type:"RDFString",value:"friendly foo"},
behaviours:[{type:"RDFString",value:"BASIC"}]}})})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.flow.flowFormDirectiveTest");goog.setTestOnly();const {flowModule}=goog.require("grrUi.flow.flow");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("flow form directive",()=>{let $compile;let $q;let $rootScope;let grrReflectionService;beforeEach(module("/static/angular-components/flow/flow-form.html"));beforeEach(module(flowModule.name));beforeEach(module(testsModule.name));angular.forEach(["grrFormValue","grrFormProtoRepeatedField"],
(directiveName)=>{stubDirective(directiveName)});beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrReflectionService=$injector.get("grrReflectionService");spyOn(grrReflectionService,"getRDFValueDescriptor").and.callFake((valueType)=>{const deferred=$q.defer();if(valueType=="FlowRunnerArgs")deferred.resolve({default:{type:"FlowRunnerArgs",value:{}},fields:[{name:"output_plugins",default:[],foo:"bar"}]});else if(valueType==
"OutputPluginDescriptor")deferred.resolve({default:{type:"OutputPluginDescriptor",value:"OutputPluginDescriptor-default",foo:"bar"}});return deferred.promise})}));const renderTestTemplate=(args,runnerArgs,withOutputPlugins)=>{$rootScope.clientId="C.0000111122223333";$rootScope.args=args||{type:"FooFlowArgs",value:{foo:"bar"}};$rootScope.runnerArgs=runnerArgs||{type:"FlowRunnerArgs",value:{flow_name:{type:"RDFString",value:"FooFlow"}}};if(angular.isUndefined(withOutputPlugins))withOutputPlugins=true;
$rootScope.withOutputPlugins=withOutputPlugins;const template="<grr-flow-form "+'flow-args="args" flow-runner-args="runnerArgs" '+'with-output-plugins="withOutputPlugins" '+'has-errors="hasErrors" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows flow arguments form",()=>{const element=renderTestTemplate();const directive=element.find("grr-form-value:nth(0)");expect(directive.scope().$eval(directive.attr("value"))).toEqual($rootScope.args)});it("shows flow runner arguments form",
()=>{const element=renderTestTemplate();const directive=element.find("grr-form-value:nth(1)");const expected=angular.copy($rootScope.runnerArgs);expected["value"]["output_plugins"]=[];expect(directive.scope().$eval(directive.attr("value"))).toEqual(expected)});it("preserves existing output plugins list",()=>{const runnerArgs={type:"FlowRunnerArgs",value:{flow_name:{type:"RDFString",value:"FooFlow"},output_plugins:[{type:"FooPluginArgs",value:{}}]}};const element=renderTestTemplate(undefined,angular.copy(runnerArgs));
const directive=element.find("grr-form-value:nth(1)");expect(directive.scope().$eval(directive.attr("value"))).toEqual(runnerArgs)});it("does not show output plugins if with-output-plugns=false",()=>{const element=renderTestTemplate(undefined,undefined,false);const directive=element.find("grr-form-value:nth(1)");expect(directive.scope().$eval(directive.attr("value"))).toEqual(angular.copy($rootScope.runnerArgs));const pluginsDirective=element.find("grr-form-proto-repeated-field");expect(pluginsDirective.length).toBe(0)});
it("shows output plugins list form",()=>{const element=renderTestTemplate();const directive=element.find("grr-form-proto-repeated-field");expect(directive.scope().$eval(directive.attr("descriptor"))).toEqual({default:{type:"OutputPluginDescriptor",value:"OutputPluginDescriptor-default",foo:"bar"}});expect(directive.scope().$eval(directive.attr("field"))).toEqual({name:"output_plugins",default:[],foo:"bar"});expect(directive.scope().$eval(directive.attr("value"))).toEqual([])});it("updates has-errors binding if flow arguments are invalid",
()=>{renderTestTemplate();expect($rootScope.hasErrors).toBe(false);$rootScope.args["validationError"]="Oh no!";$rootScope.$apply();expect($rootScope.hasErrors).toBe(true)});it("updates has-errors binding if runner arguments are invalid",()=>{renderTestTemplate();expect($rootScope.hasErrors).toBe(false);$rootScope.runnerArgs["validationError"]="Oh no!";$rootScope.$apply();expect($rootScope.hasErrors).toBe(true)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.flow.flowResultsDirectiveTest");goog.setTestOnly();const {flowModule}=goog.require("grrUi.flow.flow");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("flow results directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/flow/flow-results.html"));beforeEach(module(flowModule.name));beforeEach(module(testsModule.name));stubDirective("grrResultsCollection");beforeEach(inject(($injector)=>
{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(flowId)=>{$rootScope.flowId=flowId;$rootScope.apiBasePath="foo/bar";const template='<grr-flow-results flow-id="flowId" '+'api-base-path="apiBasePath" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("delegates rendering to grr-results-collection directive",()=>{const element=renderTestTemplate("F:1234");const directive=element.find("grr-results-collection:nth(0)");
expect(directive.length).toBe(1)});it("builds grr-result-collection urls correctly",()=>{const element=renderTestTemplate("F:1234");const directive=element.find("grr-results-collection:nth(0)");expect(directive.scope().$eval(directive.attr("results-url"))).toEqual("foo/bar/F:1234/results");expect(directive.scope().$eval(directive.attr("output-plugins-url"))).toEqual("foo/bar/F:1234/output-plugins");expect(directive.scope().$eval(directive.attr("download-files-url"))).toEqual("foo/bar/F:1234/results/files-archive")})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.flow.flowStatusIconDirectiveTest");goog.setTestOnly();const {flowModule}=goog.require("grrUi.flow.flow");const {testsModule}=goog.require("grrUi.tests");describe("grr-flow-status-icon directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/flow/flow-status-icon.html"));beforeEach(module(flowModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");
$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(state)=>{$rootScope.flow={type:"ApiFlow",value:{state:{type:"EnumNamedValue",value:state}}};const template='<grr-flow-status-icon flow="flow" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows an image for 4 possible flow states",()=>{const states=["TERMINATED","RUNNING","ERROR","CLIENT_CRASHED"];angular.forEach(states,(state)=>{const element=renderTestTemplate(state);expect($("img",element).length).toBe(1)})})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.flow.flowsListDirectiveTest");goog.setTestOnly();const {flattenFlowsList,toggleFlowExpansion}=goog.require("grrUi.flow.flowsListDirective");describe("grr-flows-list directive",()=>{describe("flattenFlowsList()",()=>{it("assigns zero depth when flows have no nested_flows",()=>{const source=[{value:{foo:1}},{value:{foo:2}},{value:{foo:3}}];expect(flattenFlowsList(source)).toEqual([{value:{foo:1},depth:0},{value:{foo:2},depth:0},{value:{foo:3},
depth:0}])});it("assigns depths correctly for flows with nested_flows",()=>{const source=[{value:{foo:1}},{value:{foo:2,nested_flows:[{value:{foo:21}},{value:{foo:22,nested_flows:[{value:{foo:223}},{value:{foo:224}}]}}]}},{foo:3}];expect(flattenFlowsList(source)).toEqual([{value:{foo:1},depth:0},{value:{foo:2},depth:0},{value:{foo:21},depth:1},{value:{foo:22},depth:1},{value:{foo:223},depth:2},{value:{foo:224},depth:2},{foo:3,depth:0}])})});describe("toggleFlowExpansion()",()=>{it("expands node with 2 children correctly",
()=>{const source=[{value:{foo:2},depth:0,shown:true},{value:{foo:21},depth:1,shown:false},{value:{foo:22},depth:1,shown:false}];expect(toggleFlowExpansion(source,0)).toEqual([{value:{foo:2},depth:0,shown:true,expanded:true},{value:{foo:21},depth:1,shown:true},{value:{foo:22},depth:1,shown:true}])});it("does not show adjacent items",()=>{const source=[{value:{foo:2},depth:0,shown:true},{value:{foo:21},depth:1,shown:false},{value:{foo:3},depth:0,shown:false}];expect(toggleFlowExpansion(source,0)).toEqual([{value:{foo:2},
depth:0,shown:true,expanded:true},{value:{foo:21},depth:1,shown:true},{value:{foo:3},depth:0,shown:false}])});it("collapses node with 2 children correctly",()=>{const source=[{value:{foo:2},depth:0,shown:true,expanded:true},{value:{foo:21},depth:1,shown:true},{value:{foo:22},depth:1,shown:true}];expect(toggleFlowExpansion(source,0)).toEqual([{value:{foo:2},depth:0,shown:true,expanded:false},{value:{foo:21},depth:1,shown:false},{value:{foo:22},depth:1,shown:false}])});it("recursively shows expanded children",
()=>{const source=[{value:{foo:2},depth:0,shown:true,expanded:false},{value:{foo:21},depth:1,shown:false},{value:{foo:22},depth:1,shown:false,expanded:true},{value:{foo:223},depth:2,shown:false},{value:{foo:224},depth:2,shown:false}];expect(toggleFlowExpansion(source,0)).toEqual([{value:{foo:2},depth:0,shown:true,expanded:true},{value:{foo:21},depth:1,shown:true},{value:{foo:22},depth:1,shown:true,expanded:true},{value:{foo:223},depth:2,shown:true},{value:{foo:224},depth:2,shown:true}])});it("does not recursively show collapsed children",
()=>{const source=[{value:{foo:2},depth:0,shown:true,expanded:false},{value:{foo:21},depth:1,shown:false},{value:{foo:22},depth:1,shown:false,expanded:false},{value:{foo:223},depth:2,shown:false},{value:{foo:224},depth:2,shown:false}];expect(toggleFlowExpansion(source,0)).toEqual([{value:{foo:2},depth:0,shown:true,expanded:true},{value:{foo:21},depth:1,shown:true},{value:{foo:22},depth:1,shown:true,expanded:false},{value:{foo:223},depth:2,shown:false},{value:{foo:224},depth:2,shown:false}])})})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.flow.startFlowFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,stubDirective,testsModule}=goog.require("grrUi.tests");const {flowModule}=goog.require("grrUi.flow.flow");describe("start flow form directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;let grrReflectionService;let flowRunnerArgsDefault;beforeEach(module("/static/angular-components/flow/start-flow-form.html"));beforeEach(module(flowModule.name));
beforeEach(module(testsModule.name));angular.forEach(["grrFlowForm","grrSemanticValue"],(directiveName)=>{stubDirective(directiveName)});beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService");grrReflectionService=$injector.get("grrReflectionService");flowRunnerArgsDefault={type:"FlowRunnerArgs",value:{flow_name:{type:"RDFString",value:"FooFlow"},output_plugins:[{foo:"bar"}],foo:"bar"}};
const deferred=$q.defer();deferred.resolve({default:flowRunnerArgsDefault});spyOn(grrReflectionService,"getRDFValueDescriptor").and.returnValue(deferred.promise)}));const renderTestTemplate=()=>{$rootScope.clientId="C.0000111122223333";$rootScope.descriptor={type:"ApiFlowDescriptor",value:{name:{type:"RDFString",value:"FooFlow"},default_args:{type:"FooFlowArgs",value:{foo:"bar"}}}};const template="<grr-start-flow-form "+'client-id="clientId" descriptor="descriptor" />';const element=$compile(template)($rootScope);
$rootScope.$apply();return element};it("shows flow arguments form",()=>{const element=renderTestTemplate();const directive=element.find("grr-flow-form");expect(directive.scope().$eval(directive.attr("flow-args"))).toEqual($rootScope.descriptor["value"]["default_args"]);expect(directive.scope().$eval(directive.attr("flow-runner-args"))).toEqual(flowRunnerArgsDefault)});it("sends request when Launch button is clicked",()=>{const element=renderTestTemplate();const deferred=$q.defer();spyOn(grrApiService,
"post").and.returnValue(deferred.promise);browserTriggerEvent(element.find("button.Launch"),"click");expect(grrApiService.post).toHaveBeenCalledWith("/clients/C.0000111122223333/flows",{flow:{runner_args:{flow_name:"FooFlow",output_plugins:[{foo:"bar"}],foo:"bar"},args:{foo:"bar"}}})});it("respects changes in form data when sending request",()=>{const element=renderTestTemplate();const directive=element.find("grr-flow-form:nth(0)");directive.scope().$eval(directive.attr("flow-args"))["value"]["changed"]=
true;directive.scope().$eval(directive.attr("flow-runner-args"))["value"]["changed"]=true;directive.scope().$eval(directive.attr("flow-runner-args"))["value"]["output_plugins"].push(42);$rootScope.$apply();const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);browserTriggerEvent(element.find("button.Launch"),"click");expect(grrApiService.post).toHaveBeenCalledWith("/clients/C.0000111122223333/flows",{flow:{runner_args:{flow_name:"FooFlow",output_plugins:[{foo:"bar"},
42],changed:true,foo:"bar"},args:{foo:"bar",changed:true}}})});it("shows progress message when request is processed",()=>{const element=renderTestTemplate();const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);browserTriggerEvent(element.find("button.Launch"),"click");expect(element.text()).toContain("Launching flow FooFlow...")});it("shows flow summary when launch succeeds",()=>{const element=renderTestTemplate();const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);
browserTriggerEvent(element.find("button.Launch"),"click");const flow={args:{"foo1":"bar1"},runner_args:{"foo2":"bar2"}};deferred.resolve({data:flow});$rootScope.$apply();const directive=element.find("grr-semantic-value:nth(0)");expect(directive.scope().$eval(directive.attr("value"))).toEqual(flow)});it("shows failure message when launch fails",()=>{const element=renderTestTemplate();const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);browserTriggerEvent(element.find("button.Launch"),
"click");deferred.reject({data:{message:"Something is wrong"}});$rootScope.$apply();expect(element.text()).toContain("Something is wrong")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.autoGeneratedAes128KeyFormDirectiveTest");goog.setTestOnly();const {formsModule}=goog.require("grrUi.forms.forms");const {generateRandomBytes}=goog.require("grrUi.forms.autoGeneratedAes128KeyFormDirective");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("grr-form-auto-generated-aes128key form directive",()=>{beforeEach(()=>{let i=0;const step=1/16;spyOn(Math,"random").and.callFake(()=>{const result=step*
i+step/2;if(++i>=16)i=0;return result})});describe("generateRandomBytes()",function(){it("correctly generates 4-bytes string",()=>{expect(generateRandomBytes(4)).toBe("01234567")});it("correctly generates 16 bytes string",()=>{expect(generateRandomBytes(16)).toBe("0123456789abcdef0123456789abcdef")})});let $compile;let $rootScope;beforeEach(module("/static/angular-components/forms/"+"auto-generated-aes128-key-form.html"));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));stubDirective("grrFormPrimitive");
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-form-auto-generated-aes128-key value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("delegates rendering to grr-form-primitive",()=>{const element=renderTestTemplate({type:"AutoGeneratedAES128Key",value:""});const directive=element.find("grr-form-primitive");expect(directive.length).toBe(1)});
it("prefills auto-generated key if value is empty",()=>{renderTestTemplate({type:"AutoGeneratedAES128Key",value:""});expect($rootScope.value.value).toBe("0123456789abcdef0123456789abcdef")});it("preserves value if it's set",()=>{renderTestTemplate({type:"AutoGeneratedAES128Key",value:"blah"});expect($rootScope.value.value).toBe("blah")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.bytesFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {bytesToHexEncodedString,hexEncodedStringToBytes,isByteString}=goog.require("grrUi.forms.bytesFormDirective");const {formsModule}=goog.require("grrUi.forms.forms");const hexChars=String.fromCharCode(13)+String.fromCharCode(200);const encodedHexChars="\\x0d\\xc8";const nonHexChars="foo";describe("bytesToHexEncodedString()",
()=>{it("does nothing with an empty string",()=>{expect(bytesToHexEncodedString("")).toBe("")});it("doesn't encode characters with codes from 32 to 126",()=>{let s="";for(let i=32;i<=126;++i)s+=String.fromCharCode(i);expect(bytesToHexEncodedString(s)).toBe(s)});it("encodes characters with codes from 0 to 31 and from 127 to 255",()=>{for(let i=0;i<=31;++i){const s=String.fromCharCode(i);expect(bytesToHexEncodedString(s)).toMatch(/\\x[0-9A-Fa-f]{2}/)}});it("encodes hex chars in the beginning of the string",
()=>{expect(bytesToHexEncodedString(hexChars+nonHexChars)).toBe(encodedHexChars+nonHexChars)});it("encodes hex chars in the middle of the string",()=>{expect(bytesToHexEncodedString(nonHexChars+hexChars+nonHexChars)).toBe(nonHexChars+encodedHexChars+nonHexChars)});it("encodes hex chars in the end of the string",()=>{expect(bytesToHexEncodedString(nonHexChars+hexChars)).toBe(nonHexChars+encodedHexChars)});it("encodes hex chars in the beginning and end of the string",()=>{expect(bytesToHexEncodedString(hexChars+
nonHexChars+hexChars)).toBe(encodedHexChars+nonHexChars+encodedHexChars)})});describe("hexEncodedStringToBytes()",()=>{it("does nothing with an empty string",()=>{expect(hexEncodedStringToBytes("")).toBe("")});it("decodes all possible characters",()=>{for(let i=0;i<256;++i){let s=i.toString(16);if(s.length==1)s=`0${s}`;s=`\\x${s}`;expect(hexEncodedStringToBytes(s)).toBe(String.fromCharCode(i))}});it("decodes hex chars in the beginning of the string",()=>{expect(hexEncodedStringToBytes(encodedHexChars+
nonHexChars)).toBe(hexChars+nonHexChars)});it("decodes hex chars in the middle of the string",()=>{expect(hexEncodedStringToBytes(nonHexChars+encodedHexChars+nonHexChars)).toBe(nonHexChars+hexChars+nonHexChars)});it("decodes hex chars in the end of the string",()=>{expect(hexEncodedStringToBytes(nonHexChars+encodedHexChars)).toBe(nonHexChars+hexChars)});it("decodes hex chars in the beginning and end of the string",()=>{expect(hexEncodedStringToBytes(encodedHexChars+nonHexChars+encodedHexChars)).toBe(hexChars+
nonHexChars+hexChars)})});describe("isByteString()",()=>{it("returns true if a string had only characters with car code < 256",()=>{let s="";for(let i=0;i<256;++i)s+=String.fromCharCode(i);expect(isByteString(s)).toBe(true)});it("returns false if a string has a character with a char code >= 256",()=>{expect(isByteString(String.fromCharCode(256))).toBe(false)})});describe("bytes form directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/forms/bytes-form.html"));
beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-form-bytes value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing if value is null",()=>{const element=renderTestTemplate({type:"RDFBytes",value:null});expect(element.find("input").val()).toBe("")});
it("shows base64-decoded value for plain latin characters",()=>{const element=renderTestTemplate({type:"RDFBytes",value:window.btoa("foo")});expect(element.find("input").val()).toBe("foo")});it("shows nothing for incorrectly base64-encoded value",()=>{const element=renderTestTemplate({type:"RDFBytes",value:"--"});expect(element.find("input").val()).toBe("")});it("updates value to a base64 version on input",()=>{const value={type:"RDFBytes",value:""};const element=renderTestTemplate(value);element.find("input").val("a");
browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe("YQ==")});it("updates value coorectly on hex-encoded input",()=>{const value={type:"RDFBytes",value:""};const element=renderTestTemplate(value);element.find("input").val("\\");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe("XA==");element.find("input").val("\\x");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe("XHg=");element.find("input").val("\\x0");browserTriggerEvent(element.find("input"),
"change");expect(value.value).toBe("XHgw");element.find("input").val("\\x0d");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe("DQ==")});it("shows a validation message on unicode input",()=>{const value={type:"RDFBytes",value:""};const element=renderTestTemplate(value);element.find("input").val("\u6628");browserTriggerEvent(element.find("input"),"change");expect(element.text()).toContain("Unicode characters are not allowed in a byte string")});it("updates value.validationError on unicode input",
()=>{const value={type:"RDFBytes",value:""};const element=renderTestTemplate(value);element.find("input").val("\u6628");browserTriggerEvent(element.find("input"),"change");expect(value.validationError).toContain("Unicode characters are not allowed in a byte string")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.clientLabelFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {formsModule}=goog.require("grrUi.forms.forms");describe("client label form directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;const defaultOption="-- All clients --";beforeEach(module("/static/angular-components/forms/client-label-form.html"));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService");spyOn(grrApiService,"get").and.callFake((url)=>{const deferred=$q.defer();if(url==="/clients/labels")deferred.resolve({data:{items:[{type:"AFF4ObjectLabel",value:{name:{type:"unicode",value:"ClientLabelFoo"}}},{type:"AFF4ObjectLabel",value:{name:{type:"unicode",value:"ClientLabelBar"}}}]}});else throw new Error(`Unexpected url: ${url}`);
return deferred.promise})}));const renderTestTemplate=(clientLabel,formLabel,hideEmptyOption,emptyOptionLabel)=>{$rootScope.clientLabel=clientLabel;$rootScope.formLabel=formLabel;$rootScope.hideEmptyOption=hideEmptyOption;$rootScope.emptyOptionLabel=emptyOptionLabel;const template="<grr-form-client-label "+'client-label="clientLabel" '+'form-label="formLabel" '+'hide-empty-option="hideEmptyOption" '+'empty-option-label="emptyOptionLabel" '+"></grr-form-client-label>";const element=$compile(template)($rootScope);
$rootScope.$apply();return element};it("shows the list of available client labels",()=>{const element=renderTestTemplate("");const select=element.find("select");const children=select.children();const options=children.map((index)=>children[index].innerText);expect(options).toContain(defaultOption);expect(options).toContain("ClientLabelFoo");expect(options).toContain("ClientLabelBar")});it("selects the label given through scope params initially",()=>{const initialSelection="ClientLabelFoo";const element=
renderTestTemplate(initialSelection);const select=element.find("select");const children=select.children();let found=false;for(let i=0;i<children.length;++i){expect(children[i].selected).toBe(children[i].innerText===initialSelection);if(children[i].selected)found=true}expect(found).toBe(true)});it("shows default <label> text by default",()=>{const element=renderTestTemplate("");const labelTag=element.find("label");expect(labelTag.text()).toBe("Client label")});it("shows custom <label> text if given",
()=>{const element=renderTestTemplate("","Custom label text");const labelTag=element.find("label");expect(labelTag.text()).toBe("Custom label text")});it("forwards value changes to parent scope",()=>{const element=renderTestTemplate("");const select=element.find("select");const newSelection="ClientLabelBar";select.val(`string:${newSelection}`);browserTriggerEvent(select,"change");$rootScope.$apply();expect(element.scope().$eval(element.attr("client-label"))).toEqual(newSelection)});it("hides the empty option if requested",
()=>{const element=renderTestTemplate("",undefined,true);const select=element.find("select");const children=select.children();const options=children.map((index)=>children[index].innerText);expect(options).not.toContain(defaultOption)});it("displays a given string describing the empty option if requested",()=>{const customDefaultOption="Custom empty option description";const element=renderTestTemplate("",undefined,undefined,customDefaultOption);const select=element.find("select");const children=select.children();
const options=children.map((index)=>children[index].innerText);expect(options).not.toContain(defaultOption);expect(options).toContain(customDefaultOption)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.datetimeFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {formsModule}=goog.require("grrUi.forms.forms");describe("datetime form directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/forms/datetime-form.html"));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");
$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-form-datetime value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing if time value is null",()=>{const element=renderTestTemplate({type:"RDFDatetime",value:null});expect(element.find("input").val()).toBe("")});it("shows correct date if time value is 0",()=>{const element=renderTestTemplate({type:"RDFDatetime",value:0});
expect(element.find("input").val()).toBe("1970-01-01 00:00")});it("shows nothing if time value is too big",()=>{const element=renderTestTemplate({type:"RDFDatetime",value:0x7fffffffffffffff});expect(element.find("input").val()).toBe("")});it("sets value to null on incorrect input",()=>{const value={type:"RDFDatetime",value:0};const element=renderTestTemplate(value);element.find("input").val("a");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe(null)});it("shows warning on incorrect input",
()=>{const value={type:"RDFDatetime",value:0};const element=renderTestTemplate(value);element.find("input").val("a");browserTriggerEvent(element.find("input"),"change");expect(element.text()).toContain("Expected format is")});it("correctly updates the value on correct input",()=>{const value={type:"RDFDatetime",value:0};const element=renderTestTemplate(value);element.find("input").val("1989-04-20 13:42");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe(60908292E7)});it('sets current date when "today" button is pressed',
()=>{const value={type:"RDFDatetime",value:0};const baseTime=new Date(Date.UTC(1989,4,20));jasmine.clock().mockDate(baseTime);const element=renderTestTemplate(value);browserTriggerEvent(element.find("button[name=Today]"),"click");expect(value.value).toBe(6116256E8)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.dictFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,stubDirective,testsModule}=goog.require("grrUi.tests");const {formsModule}=goog.require("grrUi.forms.forms");describe("dict form directive",()=>{let $compile;let $q;let $rootScope;let grrReflectionService;beforeEach(module("/static/angular-components/forms/dict-form.html"));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));stubDirective("grrFormValue");
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrReflectionService=$injector.get("grrReflectionService");grrReflectionService.getRDFValueDescriptor=(valueType)=>{if(valueType!="RDFString")throw new Error("This stub accepts only RDFString value type.");const deferred=$q.defer();deferred.resolve({name:"RDFString",default:{type:"RDFString",value:""}});return deferred.promise}}));const renderTestTemplate=(value)=>{$rootScope.value=
value;const template='<grr-form-dict value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};const setFormValue=(element,value)=>{const valueElement=element.find("grr-form-value");valueElement.scope().$eval(valueElement.attr("value")+'.value = "'+value+'"');$rootScope.$apply()};it('add empty key and value when "+" button is clicked',()=>{const model={type:"Dict",value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),
"click");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFString",value:""}}})});it("updates the model when key is changed",()=>{const model={type:"Dict",value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),"click");element.find("input.key").val("foo");browserTriggerEvent(element.find("input.key"),"change");expect(model).toEqual({type:"Dict",value:{"foo":{type:"RDFString",value:""}}})});it("updates the model when value is changed",()=>{const model=
{type:"Dict",value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),"click");setFormValue(element,"foo");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFString",value:"foo"}}})});it("prefills the UI with values from model",()=>{const model={type:"Dict",value:{"foo":{type:"RDFString",value:"bar"}}};const element=renderTestTemplate(model);expect(element.find("input.key").val()).toBe("foo");const valueElement=element.find("grr-form-value");expect(valueElement.scope().$eval(valueElement.attr("value"))).toEqual({type:"RDFString",
value:"bar"})});it("treats digits-only string as integers",()=>{const model={type:"Dict",value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),"click");setFormValue(element,"42");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFInteger",value:42}}})});it("dynamically changes value type from str to int and back",()=>{const model={type:"Dict",value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),
"click");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFString",value:""}}});setFormValue(element,"1");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFInteger",value:1}}});setFormValue(element,"1a");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFString",value:"1a"}}})});it("treats 0x.* strings as hex integers",()=>{const model={type:"Dict",value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),"click");setFormValue(element,"0x2f");
expect(model).toEqual({type:"Dict",value:{"":{type:"RDFInteger",value:47}}})});it("dynamically changes value type from hex int to str and back",()=>{const model={type:"Dict",value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),"click");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFString",value:""}}});setFormValue(element,"0x");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFString",value:"0x"}}});setFormValue(element,"0x2f");expect(model).toEqual({type:"Dict",
value:{"":{type:"RDFInteger",value:47}}});setFormValue(element,"0x2fz");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFString",value:"0x2fz"}}})});it('treats "true" string as a boolean',()=>{const model={type:"Dict",value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),"click");setFormValue(element,"true");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFBool",value:true}}})});it('treats "false" string as a boolean',()=>{const model={type:"Dict",
value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),"click");setFormValue(element,"false");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFBool",value:false}}})});it("dynamically changes valye type from text to bool and back",()=>{const model={type:"Dict",value:{}};const element=renderTestTemplate(model);browserTriggerEvent(element.find("button[name=Add]"),"click");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFString",value:""}}});
setFormValue(element,"true");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFBool",value:true}}});setFormValue(element,"truea");expect(model).toEqual({type:"Dict",value:{"":{type:"RDFString",value:"truea"}}})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.durationFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {formsModule}=goog.require("grrUi.forms.forms");describe("duration form directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/forms/duration-form.html"));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");
$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-form-duration value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing if duration value is null",()=>{const element=renderTestTemplate({type:"Duration",value:null});expect(element.find("input").val()).toBe("")});it("shows 0 if duration value is 0",()=>{const element=renderTestTemplate({type:"Duration",value:0});expect(element.find("input").val()).toBe("0")});
it("shows correct duration for large numbers",()=>{const element=renderTestTemplate({type:"Duration",value:1040688E6});expect(element.find("input").val()).toBe("12045000d")});it("shows duration in seconds if it's not divisible by 60",()=>{const element=renderTestTemplate({type:"Duration",value:122});expect(element.find("input").val()).toBe("122s")});it("shows duration in minutes if possible",()=>{const element=renderTestTemplate({type:"Duration",value:120});expect(element.find("input").val()).toBe("2m")});
it("shows duration in hours if possible",()=>{const element=renderTestTemplate({type:"Duration",value:7200});expect(element.find("input").val()).toBe("2h")});it("shows duration in days if possible",()=>{const element=renderTestTemplate({type:"Duration",value:172800});expect(element.find("input").val()).toBe("2d")});it("shows duration in weeks if possible",()=>{const element=renderTestTemplate({type:"Duration",value:1209600});expect(element.find("input").val()).toBe("2w")});it("sets value to null on incorrect input",
()=>{const value={type:"Duration",value:0};const element=renderTestTemplate(value);element.find("input").val("a");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe(null)});it("shows warning on incorrect input",()=>{const value={type:"Duration",value:0};const element=renderTestTemplate(value);element.find("input").val("a");browserTriggerEvent(element.find("input"),"change");expect(element.text()).toContain("Expected format is")});it("correctly updates the value when input is in weeks",
()=>{const value={type:"Duration",value:0};const element=renderTestTemplate(value);element.find("input").val("2w");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe(1209600)});it("correctly updates the value when input is in days",()=>{const value={type:"Duration",value:0};const element=renderTestTemplate(value);element.find("input").val("2d");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe(172800)});it("correctly updates the value when input is in hours",
()=>{const value={type:"Duration",value:0};const element=renderTestTemplate(value);element.find("input").val("2h");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe(7200)});it("correctly updates the value when input is in minutes",()=>{const value={type:"Duration",value:0};const element=renderTestTemplate(value);element.find("input").val("2m");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe(120)});it("correctly updates the value when input is in seconds",
()=>{const value={type:"Duration",value:0};const element=renderTestTemplate(value);element.find("input").val("2s");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe(2)});it("treats values without unit as seconds",()=>{const value={type:"Duration",value:0};const element=renderTestTemplate(value);element.find("input").val("2");browserTriggerEvent(element.find("input"),"change");expect(value.value).toBe(2)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.extFlagsLinuxPickerLongDirectiveTest");goog.setTestOnly();const {ExtFlagsLinuxPickerLongDirective}=goog.require("grrUi.forms.extFlagsLinuxPickerLongDirective");const {LINUX_FLAGS,getLinuxFlagMaskByNames}=goog.require("grrUi.client.extFlags");const {formsModule}=goog.require("grrUi.forms.forms");const {testsModule}=goog.require("grrUi.tests");describe("Extended flags picker for Linux (long)",()=>{let $compile;let $rootScope;beforeEach(module(ExtFlagsLinuxPickerLongDirective().templateUrl));
beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const render=(bits)=>{$rootScope.bitsSet=bits.set;$rootScope.bitsUnset=bits.unset;const template=`<grr-ext-flags-linux-picker-long\n      bits-set="bitsSet"\n      bits-unset="bitsUnset" />`;const element=$compile(template)($rootScope);$rootScope.$apply();return element};const parse=(element)=>{const result={};for(const flag of LINUX_FLAGS){const option=
$(element.find(`#${flag.name}`)).find("option[selected]");result[flag.name]=option.text()}return result};it("correctly renders a table if set and unset bits are empty",()=>{const table=parse(render({set:{value:0},unset:{value:0}}));for(const flag of LINUX_FLAGS)expect(table[flag.name]).toBe("ignored")});it("correctly renders a table if some bits are set",()=>{const table=parse(render({set:{value:getLinuxFlagMaskByNames(["FS_SYNC_FL","FS_UNRM_FL"])},unset:{value:0}}));expect(table["FS_SYNC_FL"]).toBe("required set");
expect(table["FS_UNRM_FL"]).toBe("required set");expect(table["FS_IMMUTABLE_FL"]).toBe("ignored")});it("correctly renders a table if some bits are unset",()=>{const table=parse(render({set:{value:0},unset:{value:getLinuxFlagMaskByNames(["FS_IMMUTABLE_FL","FS_COMPR_FL"])}}));expect(table["FS_IMMUTABLE_FL"]).toBe("required unset");expect(table["FS_COMPR_FL"]).toBe("required unset");expect(table["FS_SYNC_FL"]).toBe("ignored")});it("correctly renders a table if there are bits set and bits unset",()=>
{const table=parse(render({set:{value:getLinuxFlagMaskByNames(["FS_NOATIME_FL"])},unset:{value:getLinuxFlagMaskByNames(["FS_DIRTY_FL","FS_INDEX_FL"])}}));expect(table["FS_NOATIME_FL"]).toBe("required set");expect(table["FS_DIRTY_FL"]).toBe("required unset");expect(table["FS_INDEX_FL"]).toBe("required unset");expect(table["FS_TOPDIR_FL"]).toBe("ignored")})});return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.extFlagsLinuxPickerShortDirectiveTest");goog.setTestOnly();const {ExtFlagsLinuxPickerShortDirective}=goog.require("grrUi.forms.extFlagsLinuxPickerShortDirective");const {LINUX_FLAGS,getLinuxFlagMaskByNames}=goog.require("grrUi.client.extFlags");const {TroggleDirective}=goog.require("grrUi.core.troggleDirective");const {coreModule}=goog.require("grrUi.core.core");const {formsModule}=goog.require("grrUi.forms.forms");const {testsModule}=
goog.require("grrUi.tests");describe("Extended flags picker for Linux (short)",()=>{let $compile;let $rootScope;beforeEach(module(TroggleDirective().templateUrl));beforeEach(module(ExtFlagsLinuxPickerShortDirective().templateUrl));beforeEach(module(coreModule.name));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const render=(bits)=>{$rootScope.bitsSet=bits.set;$rootScope.bitsUnset=
bits.unset;const template=`<grr-ext-flags-linux-picker-short\n      bits-set="bitsSet"\n      bits-unset="bitsUnset" />`;const element=$compile(template)($rootScope);$rootScope.$apply();return element};const parse=(element)=>{const ths=element.find("th");const tds=element.find("td");expect(ths.length).toBe(tds.length);const result={};for(let i=0;i<ths.length;i++)result[$(ths[i]).text().trim()]=$(tds[i]).text().trim();return result};it("correctly renders a table if set and unset bits are empty",()=>
{const table=parse(render({set:{value:0},unset:{value:0}}));for(const flag of LINUX_FLAGS)expect(table[flag.identifier]).toBe("_")});it("correctly renders a table if some bits are set",()=>{const table=parse(render({set:{value:getLinuxFlagMaskByNames(["FS_IMMUTABLE_FL","FS_APPEND_FL"])},unset:{value:0}}));expect(table["a"]).toBe("\u2713");expect(table["i"]).toBe("\u2713");expect(table["c"]).toBe("_");expect(table["s"]).toBe("_")});it("correctly renders a table if some bits are unset",()=>{const table=
parse(render({set:{value:0},unset:{value:getLinuxFlagMaskByNames(["FS_NOCOMP_FL","FS_NODUMP_FL"])}}));expect(table["X"]).toBe("\u2715");expect(table["d"]).toBe("\u2715");expect(table["a"]).toBe("_");expect(table["B"]).toBe("_")});it("correctly renders a table if there are bits set and bits unset",()=>{const table=parse(render({set:{value:getLinuxFlagMaskByNames(["FS_EXTENT_FL"])},unset:{value:getLinuxFlagMaskByNames(["FS_TOPDIR_FL","FS_NOCOW_FL"])}}));expect(table["e"]).toBe("\u2713");expect(table["T"]).toBe("\u2715");
expect(table["C"]).toBe("\u2715");expect(table["a"]).toBe("_")})});return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.extFlagsOsxPickerDirectiveTest");goog.setTestOnly();const {ExtFlagsOsxPickerDirective}=goog.require("grrUi.forms.extFlagsOsxPickerDirective");const {OSX_FLAGS,getOsxFlagMaskByNames}=goog.require("grrUi.client.extFlags");const {TroggleDirective}=goog.require("grrUi.core.troggleDirective");const {coreModule}=goog.require("grrUi.core.core");const {formsModule}=goog.require("grrUi.forms.forms");const {testsModule}=goog.require("grrUi.tests");
describe("Extended flags picker for macOS",()=>{let $compile;let $rootScope;beforeEach(module(TroggleDirective().templateUrl));beforeEach(module(ExtFlagsOsxPickerDirective().templateUrl));beforeEach(module(coreModule.name));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const render=(bits)=>{$rootScope.bitsSet=bits.set;$rootScope.bitsUnset=bits.unset;const template=
`<grr-ext-flags-osx-picker\n      bits-set="bitsSet"\n      bits-unset="bitsUnset" />`;const element=$compile(template)($rootScope);$rootScope.$apply();return element};const parse=(element)=>{const ths=element.find("th");const tds=element.find("td");expect(ths.length).toBe(tds.length);const result={};for(let i=0;i<ths.length;i++)result[$(ths[i]).text().trim()]=$(tds[i]).text().trim();return result};it("correctly renders a table if set and unset bits are empty",()=>{const table=parse(render({set:{value:0},
unset:{value:0}}));for(const flag of OSX_FLAGS)expect(table[flag.identifier]).toBe("_")});it("correctly renders a table if some bits are set",()=>{const table=parse(render({set:{value:getOsxFlagMaskByNames(["UF_NODUMP","UF_IMMUTABLE"])},unset:{value:0}}));expect(table["nodump"]).toBe("\u2713");expect(table["uimmutable"]).toBe("\u2713");expect(table["archived"]).toBe("_")});it("correctly renders a table if some bits are unset",()=>{const table=parse(render({set:{value:0},unset:{value:getOsxFlagMaskByNames(["SF_APPEND",
"SF_NOUNLINK"])}}));expect(table["sappend"]).toBe("\u2715");expect(table["sunlnk"]).toBe("\u2715");expect(table["opaque"]).toBe("_")});it("correctly renders a table if there are bits set and bits unset",()=>{const table=parse(render({set:{value:getOsxFlagMaskByNames(["UF_APPEND"])},unset:{value:getOsxFlagMaskByNames(["SF_APPEND"])}}));expect(table["uappend"]).toBe("\u2713");expect(table["sappend"]).toBe("\u2715");expect(table["uimmutable"]).toBe("_");expect(table["simmutable"]).toBe("_")})});return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.extFlagsTrogglingTest");goog.module.declareLegacyNamespace();goog.setTestOnly();const {TroggableFlags}=goog.require("grrUi.forms.extFlagsTroggling");const {TroggleState}=goog.require("grrUi.core.troggleDirective");describe("TroggableFlags",()=>{let flags;beforeEach(()=>{flags=new TroggableFlags([{name:"FOO",identifier:"foo",mask:1,description:"foo"},{name:"BAR",identifier:"bar",mask:2,description:"bar"},{name:"BAZ",identifier:"baz",
mask:4,description:"baz"}])});it("should update itself if children state changes",()=>{flags.children[1].state=TroggleState.SET;expect(flags.bitsSet).toBe(2);flags.children[0].state=TroggleState.SET;expect(flags.bitsSet).toBe(3);flags.children[2].state=TroggleState.UNSET;expect(flags.bitsUnset).toBe(4)});it("should update children on bits change",()=>{flags.bitsSet=0;flags.bitsUnset=0;for(const flag of flags.children)expect(flag.state).toBe(TroggleState.VOID);flags.bitsSet=4;expect(flags.children[2].state).toBe(TroggleState.SET);
expect(flags.children[0].state).toBe(TroggleState.VOID);flags.bitsSet=5;expect(flags.children[2].state).toBe(TroggleState.SET);expect(flags.children[2].state).toBe(TroggleState.SET);flags.bitsUnset=2;expect(flags.children[1].state).toBe(TroggleState.UNSET)});it("should throw if conflicting masks are set",()=>{flags.bitsSet=6;flags.bitsUnset=2;expect(()=>flags.children[1].state).toThrow()})});return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.globExpressionFormDirectiveTest");goog.setTestOnly();const {getSuggestions}=goog.require("grrUi.forms.globExpressionFormDirective");describe("grr-glob-expression-form directive",()=>{it("shows no autocomplete without delimiter",()=>{expect(getSuggestions("fooba",["foobar","baz"])).toEqual([])});it("shows no autocompletion with closed delimiter",()=>{expect(getSuggestions("%%foobar%%/foobar",["foobar","baz"])).toEqual([])});it("shows no autocompletion for closed group",
()=>{expect(getSuggestions("%%foobar%%foo",["foobar","baz"])).toEqual([])});it("shows autocompletion for matching prefix",()=>{expect(getSuggestions("%%fooba",["foobar","baz"])).toEqual([{suggestion:"%%foobar%%",expressionWithSuggestion:"%%foobar%%"}])});it("shows autocompletion for partial matching",()=>{expect(getSuggestions("%%oba",["foobar","baz"])).toEqual([{suggestion:"%%foobar%%",expressionWithSuggestion:"%%foobar%%"}])});it("shows autocompletion while closing term",()=>{expect(getSuggestions("%%foobar%",
["foobar","baz"])).toEqual([{suggestion:"%%foobar%%",expressionWithSuggestion:"%%foobar%%"}])});it("shows autocompletion with unrelated query prefix",()=>{expect(getSuggestions("/bar/%%foo",["foobar","baz"])).toEqual([{suggestion:"%%foobar%%",expressionWithSuggestion:"/bar/%%foobar%%"}])});it("hides autocompletion for closed term",()=>{expect(getSuggestions("%%foo%%",["foobar","foo"])).toEqual([])});it("shows multiple autocomplete suggestions",()=>{const sug=getSuggestions("%%ba",["foobar","baz"]);
expect(sug.length).toBe(2);expect(sug).toContain({suggestion:"%%foobar%%",expressionWithSuggestion:"%%foobar%%"});expect(sug).toContain({suggestion:"%%baz%%",expressionWithSuggestion:"%%baz%%"})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.outputPluginDescriptorFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,stubDirective,testsModule}=goog.require("grrUi.tests");const {formsModule}=goog.require("grrUi.forms.forms");describe("grr-output-plugin-descriptor-form directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;let grrReflectionService;beforeEach(module("/static/angular-components/forms/"+"output-plugin-descriptor-form.html"));beforeEach(module(formsModule.name));
beforeEach(module(testsModule.name));stubDirective("grrFormValue");beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService");grrReflectionService=$injector.get("grrReflectionService");const apiServiceResponse=$q.defer();apiServiceResponse.resolve({data:{items:[{args_type:"FooOutputPluginArgs",name:"FooOutputPlugin",plugin_type:"LEGACY"},{args_type:"BarOutputPluginArgs",name:"BarOutputPlugin",
plugin_type:"LEGACY"},{name:"foo-bar",friendly_name:"FooBar plugin",plugin_type:"INSTANT"}]}});spyOn(grrApiService,"get").and.returnValue(apiServiceResponse.promise);spyOn(grrReflectionService,"getRDFValueDescriptor").and.callFake((name)=>{const deferred=$q.defer();if(name=="FooOutputPluginArgs")deferred.resolve({default:{type:"FooOutputPluginArgs",value:"FooValue"}});else if(name=="BarOutputPluginArgs")deferred.resolve({default:{type:"BarOutputPluginArgs",value:"BarValue"}});else throw new Error(`Unexpected name: ${name}`);
return deferred.promise})}));const renderTestTemplate=(value)=>{$rootScope.value=angular.isDefined(value)?value:{type:"OutputPluginDescriptor",value:{}};const template='<grr-output-plugin-descriptor-form value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("selects alphabetically first plugin if none is specified",()=>{const element=renderTestTemplate();expect($rootScope.value.value.plugin_name.value).toBe("BarOutputPlugin");expect(element.find("select").val()).toBe("string:BarOutputPlugin")});
it("keeps current output plugin type if one is specified",()=>{const element=renderTestTemplate({type:"OutputPluginDescriptor",value:{plugin_name:{type:"RDFString",value:"FooOutputPlugin"}}});expect($rootScope.value.value.plugin_name.value).toBe("FooOutputPlugin");expect(element.find("select").val()).toBe("string:FooOutputPlugin")});it("sets plugin args to default when plugin type is changed",()=>{const element=renderTestTemplate();expect($rootScope.value.value.plugin_args.type).toBe("BarOutputPluginArgs");
element.find("select").val(element.find('select option[label="FooOutputPlugin"]').val());browserTriggerEvent(element.find("select"),"change");expect($rootScope.value.value.plugin_args.type).toBe("FooOutputPluginArgs")});it("delegates current plugin args rendering to grr-form-value",()=>{const element=renderTestTemplate();let argsValue=$rootScope.$eval(element.find("grr-form-value").attr("value"));expect(argsValue.type).toBe("BarOutputPluginArgs");element.find("select").val(element.find('select option[label="FooOutputPlugin"]').val());
browserTriggerEvent(element.find("select"),"change");argsValue=$rootScope.$eval(element.find("grr-form-value").attr("value"));expect(argsValue.type).toBe("FooOutputPluginArgs")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.semanticEnumFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {formsModule}=goog.require("grrUi.forms.forms");describe("semantic enum form directive",()=>{let $compile;let $rootScope;let value;beforeEach(module("/static/angular-components/forms/semantic-enum-form.html"));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>
{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");value={age:0,type:"EnumNamedValue",value:"NONE",mro:["EnumNamedValue","RDFInteger","RDFString","RDFBytes","RDFValue","object"]}}));const renderTestTemplate=(metadata)=>{$rootScope.value=value;$rootScope.metadata=metadata;const template='<grr-form-enum metadata="metadata" value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows list of options from the metadata",()=>{const element=
renderTestTemplate({allowed_values:[{name:"NONE",value:0},{name:"CHOICE 1",value:1},{name:"CHOICE 2",value:2}]});expect(element.find("option").length).toBe(3);expect(element.find("option:nth(0)").attr("label")).toBe("NONE");expect(element.find("option:nth(1)").attr("label")).toBe("CHOICE 1");expect(element.find("option:nth(2)").attr("label")).toBe("CHOICE 2")});it('marks the default value with "(default)"',()=>{const element=renderTestTemplate({allowed_values:[{name:"NONE",value:0},{name:"CHOICE 1",
value:1},{name:"CHOICE 2",value:2}],default:{"age":0,"type":"EnumNamedValue","value":"CHOICE 1","mro":["EnumNamedValue","RDFInteger","RDFString","RDFBytes","RDFValue","object"]}});expect(element.find("option").length).toBe(3);expect(element.find("option:nth(0)").attr("label")).toBe("NONE");expect(element.find("option:nth(1)").attr("label")).toBe("CHOICE 1 (default)");expect(element.find("option:nth(2)").attr("label")).toBe("CHOICE 2")});it("updates the value when user selects an option",()=>{const element=
renderTestTemplate({allowed_values:[{name:"NONE",value:0},{name:"CHOICE 1",value:1},{name:"CHOICE 2",value:2}]});expect(value.value).toBe("NONE");element.find("select").val(element.find('select option[label="CHOICE 2"]').val());browserTriggerEvent(element.find("select"),"change");$rootScope.$apply();expect(value.value).toBe("CHOICE 2")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.semanticPrimitiveFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {formsModule}=goog.require("grrUi.forms.forms");describe("semantic primitive form directive",()=>{let $compile;let $q;let $rootScope;let grrReflectionService;let boolValue;let intValue;let stringValue;beforeEach(module("/static/angular-components/forms/semantic-primitive-form.html"));beforeEach(module(formsModule.name));
beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrReflectionService=$injector.get("grrReflectionService");grrReflectionService.getRDFValueDescriptor=(valueType)=>{const deferred=$q.defer();deferred.resolve({name:valueType,mro:[valueType]});return deferred.promise};stringValue={type:"RDFString",value:"foo"};intValue={type:"RDFInteger",value:42};boolValue={type:"RDFBool",value:true}}));
const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-form-primitive value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("prefills RDFString value from a model",()=>{const element=renderTestTemplate(stringValue);expect(element.find("input").val()).toBe("foo")});it("updates RDFString value when model is updated",()=>{const element=renderTestTemplate(stringValue);expect(element.find("input").val()).toBe("foo");stringValue.value=
"bar";$rootScope.$apply();expect(element.find("input").val()).toBe("bar")});it("updates RDFString model when user changes the input",()=>{const element=renderTestTemplate(stringValue);element.find("input").val("bar");browserTriggerEvent(element.find("input"),"change");$rootScope.$apply();expect(stringValue.value).toBe("bar")});it("prefills RDFInteger value from a model",()=>{const element=renderTestTemplate(intValue);expect(element.find("input").val()).toBe("42")});it("updates RDFInteger value when model is updated",
()=>{const element=renderTestTemplate(intValue);expect(element.find("input").val()).toBe("42");intValue.value=84;$rootScope.$apply();expect(element.find("input").val()).toBe("84")});it("updates RDFInteger model when user changes the input",()=>{const element=renderTestTemplate(intValue);element.find("input").val("84");browserTriggerEvent(element.find("input"),"change");$rootScope.$apply();expect(intValue.value).toBe(84)});it("prefills RDFBool value from a model",()=>{const element=renderTestTemplate(boolValue);
expect(element.find("input").prop("checked")).toBe(true)});it("updates RDFBool value when model is updated",()=>{const element=renderTestTemplate(boolValue);expect(element.find("input").prop("checked")).toBe(true);boolValue.value=false;$rootScope.$apply();expect(element.find("input").prop("checked")).toBe(false)});it("updates RDFBool model when user changes the input",()=>{const element=renderTestTemplate(boolValue);browserTriggerEvent(element.find("input").prop("checked",false),"change");$rootScope.$apply();
expect(boolValue.value).toBe(false)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.semanticProtoFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,stubDirective,testsModule}=goog.require("grrUi.tests");const {clearCaches}=goog.require("grrUi.forms.semanticValueFormDirective");const {formsModule}=goog.require("grrUi.forms.forms");describe("semantic proto form directive",()=>{let $compile;let $q;let $rootScope;let grrReflectionServiceMock;beforeEach(module("/static/angular-components/forms/semantic-proto-form.html"));
beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));angular.forEach(["grrFormProtoSingleField","grrFormProtoRepeatedField","grrFormProtoUnion"],(directiveName)=>{stubDirective(directiveName)});beforeEach(module(($provide)=>{grrReflectionServiceMock={getRDFValueDescriptor:function(){}};$provide.factory("grrReflectionService",()=>grrReflectionServiceMock)}));beforeEach(inject(($injector)=>{clearCaches();$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");
$q=$injector.get("$q")}));const renderTestTemplate=(value,metadata,hiddenFields)=>{$rootScope.value=value;$rootScope.metadata=metadata;$rootScope.hiddenFields=hiddenFields;const template='<grr-form-proto value="value" metadata="metadata" '+'hidden-fields="hiddenFields" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};describe("form for structure with 3 primitive fields",()=>{let defaultFooStructValue;beforeEach(()=>{defaultFooStructValue={type:"Foo",mro:["Foo",
"RDFProtoStruct"],value:{}};const data={"Foo":{"default":{"type":"Foo","value":{}},"doc":"This is a structure Foo.","fields":[{"doc":"Field 1 description.","dynamic":false,"friendly_name":"Field 1","index":1,"name":"field_1","repeated":false,"type":"PrimitiveType"},{"default":{"type":"PrimitiveType","value":"a foo bar"},"doc":"Field 2 description.","dynamic":false,"friendly_name":"Field 2","index":1,"name":"field_2","repeated":false,"type":"PrimitiveType"},{"default":{"type":"PrimitiveType","value":""},
"doc":"Field 3 description.","dynamic":false,"friendly_name":"Field 3","index":1,"name":"field_3","repeated":false,"type":"PrimitiveType"}],"kind":"struct","name":"Foo","mro":["Foo","RDFProtoStruct"]},"PrimitiveType":{"default":{"type":"PrimitiveType","value":""},"doc":"Test primitive type description.","kind":"primitive","name":"PrimitiveType","mro":["PrimitiveType"]}};const reflectionDeferred=$q.defer();reflectionDeferred.resolve(data);spyOn(grrReflectionServiceMock,"getRDFValueDescriptor").and.callFake((type,
opt_withDeps)=>{const reflectionDeferred=$q.defer();reflectionDeferred.resolve(opt_withDeps?data:data[type]);return reflectionDeferred.promise})});it("renders a form for structure with 3 primitive fields",()=>{const element=renderTestTemplate(defaultFooStructValue);expect(element.find("grr-form-proto-single-field").length).toBe(3)});it("does not overwrite field prefilled with non-default value",()=>{const fooValue=defaultFooStructValue;fooValue.value={field_2:{type:"PrimitiveType",value:"42"}};renderTestTemplate(fooValue);
expect(fooValue.value).toEqual({field_2:{type:"PrimitiveType",value:"42"}})});it("does not erase the field with default value prefilled with default "+"field value not equal to the default type value",()=>{const fooValue=defaultFooStructValue;fooValue.value={field_2:{type:"PrimitiveType",value:"a foo bar"}};renderTestTemplate(fooValue);expect(fooValue.value).toEqual({field_2:{type:"PrimitiveType",value:"a foo bar"}})});it("erases the field with default value prefilled with default field "+"value equal to the default type value",
()=>{const fooValue=defaultFooStructValue;fooValue.value={field_3:{type:"PrimitiveType",value:""}};renderTestTemplate(fooValue);expect(fooValue.value).toEqual({})});it("erases the field without default prefilled with default type "+"value",()=>{const fooValue=defaultFooStructValue;fooValue.value={field_1:{type:"PrimitiveType",value:""}};renderTestTemplate(fooValue);expect(fooValue.value).toEqual({})});it("does not erase hidden fields",()=>{const fooValue=defaultFooStructValue;fooValue.value={field_1:{type:"PrimitiveType",
value:""}};renderTestTemplate(fooValue,undefined,["field_1"]);expect(fooValue.value).toEqual({field_1:{type:"PrimitiveType",value:""}})});it("does not render fields listed in hidden-fields argument",()=>{const element=renderTestTemplate(defaultFooStructValue,undefined,["field_1"]);expect(element.find("grr-form-proto-single-field").length).toBe(2);let field=element.find("grr-form-proto-single-field:nth(0)");expect(field.scope().$eval(field.attr("value"))).toEqual({type:"PrimitiveType",value:"a foo bar"});
field=element.find("grr-form-proto-single-field:nth(1)");expect(field.scope().$eval(field.attr("value"))).toEqual({type:"PrimitiveType",value:""})});it("does not prefill the model with defaults",()=>{const fooValue=defaultFooStructValue;renderTestTemplate(fooValue);expect(fooValue.value).toEqual({})});it("prefills nested form elements with defaults",()=>{const fooValue=defaultFooStructValue;const element=renderTestTemplate(fooValue);let field=element.find("grr-form-proto-single-field:nth(0)");expect(field.scope().$eval(field.attr("value"))).toEqual({type:"PrimitiveType",
value:""});field=element.find("grr-form-proto-single-field:nth(1)");expect(field.scope().$eval(field.attr("value"))).toEqual({type:"PrimitiveType",value:"a foo bar"});field=element.find("grr-form-proto-single-field:nth(2)");expect(field.scope().$eval(field.attr("value"))).toEqual({type:"PrimitiveType",value:""})});it("updates model when a field is changed",()=>{const fooValue=defaultFooStructValue;const element=renderTestTemplate(fooValue);const field=element.find("grr-form-proto-single-field:nth(0)");
const fieldValue=field.scope().$eval(field.attr("value"));fieldValue.value="42";$rootScope.$apply();expect(fooValue.value).toEqual({field_1:{type:"PrimitiveType",value:"42"}})});it("updates fields when value.field_1 is changed externally",()=>{const fooValue=defaultFooStructValue;const element=renderTestTemplate(fooValue);let field=element.find("grr-form-proto-single-field:nth(0)");let fieldValue=field.scope().$eval(field.attr("value"));expect(fieldValue["value"]).toBe("");fooValue["value"]["field_1"]=
{type:"PrimitiveType",value:"foo"};$rootScope.$apply();field=element.find("grr-form-proto-single-field:nth(0)");fieldValue=field.scope().$eval(field.attr("value"));expect(fieldValue).toEqual({type:"PrimitiveType",value:"foo"})});it("with set fields: updates only changed on external change",()=>{const fooValue=defaultFooStructValue;fooValue["value"]["field_1"]={type:"PrimitiveType",value:"foo"};fooValue["value"]["field_2"]={type:"PrimitiveType",value:"bar"};const element=renderTestTemplate(fooValue);
const field1=element.find("grr-form-proto-single-field:nth(0)");const field2=element.find("grr-form-proto-single-field:nth(1)");const field1Value=field1.scope().$eval(field1.attr("value"));const field2Value=field2.scope().$eval(field2.attr("value"));fooValue["value"]["field_1"]={type:"PrimitiveType",value:"fooNew"};$rootScope.$apply();const field1New=element.find("grr-form-proto-single-field:nth(0)");const field2New=element.find("grr-form-proto-single-field:nth(1)");const field1ValueNew=field1New.scope().$eval(field1New.attr("value"));
const field2ValueNew=field2New.scope().$eval(field2New.attr("value"));expect(field1ValueNew).not.toBe(field1Value);expect(field2ValueNew).toBe(field2Value)});it("with unset fields: updates only changed on external change",()=>{const fooValue=defaultFooStructValue;const element=renderTestTemplate(fooValue);const field1=element.find("grr-form-proto-single-field:nth(0)");const field2=element.find("grr-form-proto-single-field:nth(1)");const field1Value=field1.scope().$eval(field1.attr("value"));const field2Value=
field2.scope().$eval(field2.attr("value"));fooValue["value"]["field_1"]={type:"PrimitiveType",value:"foo"};$rootScope.$apply();const field1New=element.find("grr-form-proto-single-field:nth(0)");const field2New=element.find("grr-form-proto-single-field:nth(1)");const field1ValueNew=field1New.scope().$eval(field1New.attr("value"));const field2ValueNew=field2New.scope().$eval(field2New.attr("value"));expect(field1ValueNew).not.toBe(field1Value);expect(field2ValueNew).toBe(field2Value)});it("updates fields when value.field_1 is cleared externally",
()=>{const fooValue=defaultFooStructValue;fooValue["value"]["field_1"]={type:"PrimitiveType",value:"foo"};const element=renderTestTemplate(fooValue);let field=element.find("grr-form-proto-single-field:nth(0)");let fieldValue=field.scope().$eval(field.attr("value"));expect(fieldValue["value"]).toBe("foo");fooValue["value"]["field_1"]=undefined;$rootScope.$apply();field=element.find("grr-form-proto-single-field:nth(0)");fieldValue=field.scope().$eval(field.attr("value"));expect(fieldValue).toEqual({type:"PrimitiveType",
value:""})});const icon=(element,iconName)=>element.find(`i.glyphicon-${iconName}`);const expectIcon=(element,iconName)=>{expect(icon(element,iconName).length).toBe(1)};const expectNoIcon=(element,iconName)=>{expect(icon(element,iconName).length).toBe(0)};it("does not render collapse/expand icon if depth is not set",()=>{const element=renderTestTemplate(defaultFooStructValue,{depth:undefined});expectNoIcon(element,"plus")});it("does not render collapse/expand icon if depth is 0 or 1",()=>{let element=
renderTestTemplate(defaultFooStructValue,{depth:0});expectNoIcon(element,"plus");element=renderTestTemplate(defaultFooStructValue,{depth:1});expectNoIcon(element,"plus")});it("renders as collapsed if metadata.depth is 2",()=>{const element=renderTestTemplate(defaultFooStructValue,{depth:2});expectIcon(element,"plus")});it("expands if collapsed plus icons is clicked",()=>{const element=renderTestTemplate(defaultFooStructValue,{depth:2});expect(element.find("grr-form-proto-single-field").length).toBe(0);
browserTriggerEvent(icon(element,"plus"),"click");expect(element.find("grr-form-proto-single-field").length).toBe(3);expectNoIcon(element,"plus");expectIcon(element,"minus")});it("collapses if expanded and minus icon is clicked",()=>{const element=renderTestTemplate(defaultFooStructValue,{depth:2});browserTriggerEvent(icon(element,"plus"),"click");browserTriggerEvent(icon(element,"minus"),"click");expect(element.find("grr-form-proto-single-field").length).toBe(0);expectNoIcon(element,"minus");expectIcon(element,
"plus")})});describe("form for structure with 1 dynamic field",()=>{const defaultFooStructValue={type:"Foo",mro:["Foo","RDFProtoStruct"],value:{}};beforeEach(()=>{const data={"Foo":{"default":{"type":"Foo","value":{}},"doc":"This is a structure Foo.","fields":[{"doc":"Field 1 description.","dynamic":true,"friendly_name":"Field 1","index":1,"name":"field_1","repeated":false}],"kind":"struct","name":"Foo","mro":["Foo","RDFProtoStruct"]},"PrimitiveType":{"default":{"type":"PrimitiveType","value":""},
"doc":"Test primitive type description.","kind":"primitive","name":"PrimitiveType","mro":["PrimitiveType"]}};const reflectionDeferred=$q.defer();reflectionDeferred.resolve(data);spyOn(grrReflectionServiceMock,"getRDFValueDescriptor").and.callFake((type,opt_withDeps)=>{const reflectionDeferred=$q.defer();reflectionDeferred.resolve(opt_withDeps?data:data[type]);return reflectionDeferred.promise})});it("does not prefill non-prefilled dynamic field",()=>{const fooValue=defaultFooStructValue;const element=
renderTestTemplate(fooValue);const field=element.find("grr-form-proto-repeated-field:nth(0)");const fieldValue=field.scope().$eval(field.attr("value"));expect(fieldValue).toBeUndefined()});it("uses existing dynamic field value when it's prefilled",()=>{const fooValue=defaultFooStructValue;fooValue.value={field_1:{type:"PrimitiveType",value:"42"}};const element=renderTestTemplate(angular.copy(fooValue));const field=element.find("grr-form-proto-repeated-field:nth(0)");const fieldValue=field.scope().$eval(field.attr("value"));
expect(fieldValue).toEqual(fooValue.value.field_1)})});describe("form for structure with 1 repeated field",()=>{beforeEach(()=>{const data={"Foo":{"default":{"type":"Foo","value":{}},"doc":"This is a structure Foo.","fields":[{"default":{"mro":["PrimitiveType"],"type":"PrimitiveType","value":""},"doc":"Field 1 description.","dynamic":false,"friendly_name":"Field 1","index":1,"name":"field_1","repeated":true,"type":"PrimitiveType"}],"kind":"struct","mro":["Foo","RDFProtoStruct"]},"PrimitiveType":{"default":{"type":"PrimitiveType",
"value":""},"doc":"Test primitive type description.","kind":"primitive","mro":["PrimitiveType"],"name":"PrimitiveType"}};spyOn(grrReflectionServiceMock,"getRDFValueDescriptor").and.callFake((type,opt_withDeps)=>{const reflectionDeferred=$q.defer();reflectionDeferred.resolve(opt_withDeps?data:data[type]);return reflectionDeferred.promise})});it("does not prefill the model",()=>{const fooValue={type:"Foo",value:{}};renderTestTemplate(fooValue);expect(fooValue.value).toEqual({})});it("does not overwrite prefilled data",
()=>{const fooValue={type:"Foo",value:{field_1:[{type:"PrimitiveType",value:"42"}]}};renderTestTemplate(fooValue);expect(fooValue.value.field_1.length).toBe(1);expect(fooValue.value.field_1[0]).toEqual({type:"PrimitiveType",value:"42"})});it("updates the model when repeated field is changed",()=>{const fooValue={type:"Foo",value:{}};const element=renderTestTemplate(fooValue);const field=element.find("grr-form-proto-repeated-field:nth(0)");const fieldValue=field.scope().$eval(field.attr("value"));
fieldValue.push({"type":"PrimitiveType",value:"42"});$rootScope.$apply();expect(fooValue.value).toEqual({field_1:[{type:"PrimitiveType",value:"42"}]})});it("updates fields when repeated field is changed externally",()=>{const fooValue={type:"Foo",value:{}};const element=renderTestTemplate(fooValue);let field=element.find("grr-form-proto-repeated-field:nth(0)");let fieldValue=field.scope().$eval(field.attr("value"));expect(fieldValue).toEqual([]);fooValue["value"]["field_1"]=[{"type":"PrimitiveType",
value:"42"}];$rootScope.$apply();field=element.find("grr-form-proto-repeated-field:nth(0)");fieldValue=field.scope().$eval(field.attr("value"));expect(fieldValue).toEqual([{"type":"PrimitiveType",value:"42"}])});it("renders the repeated field with corresponding directive",()=>{const fooValue={type:"Foo",value:{}};const element=renderTestTemplate(fooValue);expect(element.find("grr-form-proto-repeated-field").length).toBe(1)});it("does not render repeated field from the hidden-fields",()=>{const fooValue=
{type:"Foo",value:{}};const element=renderTestTemplate(fooValue,undefined,["field_1"]);expect(element.find("grr-form-proto-repeated-field").length).toBe(0)})});describe("form for union-type structure",()=>{beforeEach(()=>{const data={"Foo":{"default":{"type":"Foo","value":{}},"doc":"This is a structure Foo.","union_field":"type","fields":[{"default":{"mro":["PrimitiveType"],"type":"PrimitiveType","value":""},"doc":"Field 1 description.","dynamic":false,"friendly_name":"Union Type","index":1,"name":"type",
"repeated":true,"type":"PrimitiveType"}],"kind":"struct","mro":["Foo","RDFProtoStruct"]},"PrimitiveType":{"default":{"type":"PrimitiveType","value":""},"doc":"Test primitive type description.","kind":"primitive","mro":["PrimitiveType"],"name":"PrimitiveType"}};const reflectionDeferred=$q.defer();reflectionDeferred.resolve(data);spyOn(grrReflectionServiceMock,"getRDFValueDescriptor").and.callFake((type,opt_withDeps)=>{const reflectionDeferred=$q.defer();reflectionDeferred.resolve(opt_withDeps?data:
data[type]);return reflectionDeferred.promise})});it("delegates union-type structure rendering",()=>{const fooValue={type:"Foo",value:{}};const element=renderTestTemplate(fooValue);expect(element.find("grr-form-proto-union").length).toBe(1)})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.semanticProtoRepeatedFieldFormDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,stubDirective,testsModule}=goog.require("grrUi.tests");const {formsModule}=goog.require("grrUi.forms.forms");describe("semantic proto repeated field form directive",()=>{let $compile;let $q;let $rootScope;beforeEach(module("/static/angular-components/forms/semantic-proto-repeated-field-form.html"));beforeEach(module(formsModule.name));
beforeEach(module(testsModule.name));stubDirective("grrFormValue");beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q")}));const renderTestTemplate=(value,descriptor,field,noCustomTemplate)=>{$rootScope.value=value;$rootScope.descriptor=descriptor;$rootScope.field=field;$rootScope.noCustomTemplate=noCustomTemplate;const template='<grr-form-proto-repeated-field value="value" '+'descriptor="descriptor" field="field" '+'no-custom-template="noCustomTemplate" />';
const element=$compile(template)($rootScope);$rootScope.$apply();return element};const typedPrimitiveValue={type:"PrimitiveType",value:42};const primitiveValueDescriptor={type:"PrimitiveType",mro:["PrimitiveType"],kind:"primitive",default:angular.copy(typedPrimitiveValue)};describe("without custom directives",()=>{beforeEach(inject(($injector)=>{const grrSemanticRepeatedFormDirectivesRegistryService=$injector.get("grrSemanticRepeatedFormDirectivesRegistryService");spyOn(grrSemanticRepeatedFormDirectivesRegistryService,
"findDirectiveForType").and.callFake((type)=>{const q=$q.defer();q.reject();return q.promise})}));it("renders doc and friendly name",()=>{const element=renderTestTemplate([],primitiveValueDescriptor,{doc:"Field documentation",friendly_name:"Field friendly name"});expect(element.find('label[title="Field documentation"]').length).not.toBe(0);expect(element.text()).toContain("Field friendly name")});it("delegates items rendering to grr-form-value",()=>{const element=renderTestTemplate([{type:"PrimitiveType",
value:42},{type:"PrimitiveType",value:43}],primitiveValueDescriptor,{});expect(element.find("grr-form-value").length).toBe(2)});it('adds new item when "Add" is clicked',()=>{const value=[];const element=renderTestTemplate(value,primitiveValueDescriptor,{});expect(element.find("grr-form-value").length).toBe(0);browserTriggerEvent($("button[name=Add]",element),"click");expect(element.find("grr-form-value").length).toBe(1);expect(angular.equals(value,[typedPrimitiveValue])).toBe(true);browserTriggerEvent($("button[name=Add]",
element),"click");expect(element.find("grr-form-value").length).toBe(2);expect(angular.equals(value,[typedPrimitiveValue,typedPrimitiveValue])).toBe(true)});it('removes an item when "Remove" is clicked',()=>{const value=[angular.copy(typedPrimitiveValue),angular.copy(typedPrimitiveValue)];const element=renderTestTemplate(value,primitiveValueDescriptor,{});expect(element.find("grr-form-value").length).toBe(2);browserTriggerEvent($("button[name=Remove]:nth(0)",element),"click");expect(element.find("grr-form-value").length).toBe(1);
expect(angular.equals(value,[typedPrimitiveValue])).toBe(true);browserTriggerEvent($("button[name=Remove]:nth(0)",element),"click");expect(element.find("grr-form-value").length).toBe(0);expect(value).toEqual([])})});describe("with custom directive",()=>{beforeEach(inject(($injector)=>{const grrSemanticRepeatedFormDirectivesRegistryService=$injector.get("grrSemanticRepeatedFormDirectivesRegistryService");spyOn(grrSemanticRepeatedFormDirectivesRegistryService,"findDirectiveForType").and.callFake((type)=>
{const q=$q.defer();q.resolve({directive_name:"fooBar"});return q.promise})}));it("renders doc and friendly name",()=>{const element=renderTestTemplate([],primitiveValueDescriptor,{doc:"Field documentation",friendly_name:"Field friendly name"});expect(element.find('label[title="Field documentation"]').length).not.toBe(0);expect(element.text()).toContain("Field friendly name")});it("delegates items rendering to grr-form-value",()=>{const element=renderTestTemplate([],primitiveValueDescriptor,{});expect(element.find("foo-bar").length).toBe(1)});
it("ignores custom directive if no-custom-template binding is true",()=>{const element=renderTestTemplate([{type:"PrimitiveType",value:42},{type:"PrimitiveType",value:43}],primitiveValueDescriptor,{},true);expect(element.find("foo-bar").length).toBe(0);expect(element.find("grr-form-value").length).toBe(2)})});describe('with custom directive with "hideCustomTemplateLabel" set',()=>{beforeEach(inject(($injector)=>{const grrSemanticRepeatedFormDirectivesRegistryService=$injector.get("grrSemanticRepeatedFormDirectivesRegistryService");
spyOn(grrSemanticRepeatedFormDirectivesRegistryService,"findDirectiveForType").and.callFake((type)=>{const q=$q.defer();q.resolve({directive_name:"fooBar",hideCustomTemplateLabel:true});return q.promise})}));it("does not render custom field's label",()=>{const element=renderTestTemplate([],primitiveValueDescriptor,{});expect(element.find('label[title="Field documentation"]').length).toBe(0);expect(element.text()).not.toContain("Field friendly name");expect(element.find("foo-bar").length).toBe(1)})})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.semanticProtoSingleFieldFormDirectiveTest");goog.setTestOnly();const {formsModule}=goog.require("grrUi.forms.forms");const {testsModule}=goog.require("grrUi.tests");describe("semantic proto single field form directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/forms/semantic-proto-form.html"));beforeEach(module("/static/angular-components/forms/semantic-proto-union-form.html"));beforeEach(module("/static/angular-components/forms/semantic-proto-single-field-form.html"));
beforeEach(module("/static/angular-components/forms/semantic-proto-repeated-field-form.html"));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value,field)=>{$rootScope.value=value;$rootScope.field=field;const template='<grr-form-proto-single-field value="value" '+'field="field" />';const element=$compile(template)($rootScope);$rootScope.$apply();
return element};it("renders doc and friendly name",()=>{const element=renderTestTemplate({},{doc:"Field documentation",friendly_name:"Field friendly name"});expect(element.find('label[title="Field documentation"]').length).toBe(1);expect(element.text()).toContain("Field friendly name")});it("delegates rendering to grr-form-value",()=>{const element=renderTestTemplate({},{});expect(element.find("grr-form-value").length).toBe(1)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.semanticProtoUnionFormDirectiveTest");goog.setTestOnly();const {formsModule}=goog.require("grrUi.forms.forms");const {testsModule}=goog.require("grrUi.tests");describe("semantic proto union form directive",()=>{let $compile;let $q;let $rootScope;let descriptor;let grrReflectionService;beforeEach(module("/static/angular-components/forms/semantic-proto-form.html"));beforeEach(module("/static/angular-components/forms/semantic-proto-union-form.html"));
beforeEach(module("/static/angular-components/forms/semantic-proto-single-field-form.html"));beforeEach(module("/static/angular-components/forms/semantic-proto-repeated-field-form.html"));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrReflectionService=$injector.get("grrReflectionService");grrReflectionService.getRDFValueDescriptor=(valueType)=>
{const deferred=$q.defer();deferred.resolve({name:valueType,mro:[valueType]});return deferred.promise};descriptor={"default":{"mro":["Foo","RDFProtoStruct"],"type":"Foo","value":{}},"doc":"This is a structure Foo.","union_field":"type","fields":[{"default":{"mro":["PrimitiveType"],"type":"PrimitiveType","value":""},"index":1,"name":"type","repeated":false,"type":"PrimitiveType"},{"default":{"mro":["PrimitiveTypeFoo"],"type":"PrimitiveTypeFoo","value":"foo"},"index":2,"name":"foo","repeated":false,
"type":"PrimitiveTypeFoo"},{"default":{"mro":["PrimitiveTypeBar"],"type":"PrimitiveTypeBar","value":"bar"},"index":3,"name":"bar","repeated":false,"type":"PrimitiveTypeBar"}]}}));const renderTestTemplate=(value)=>{$rootScope.value=value;$rootScope.descriptor=descriptor;const template='<grr-form-proto-union value="value" '+'descriptor="descriptor" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("displays field based on union field value",()=>{const value={type:"Foo",
mro:["Foo"],value:{type:{type:"PrimitiveType",mro:["PrimitiveType"],value:"foo"},foo:{type:"PrimitiveTypeFoo",mro:["PrimitiveTypeFoo"],value:42},bar:{type:"PrimitiveTypeBar",mro:["PrimitiveTypeBar"],value:43}}};const element=renderTestTemplate(value);expect(element.text()).toContain("No directive for type: PrimitiveTypeFoo");expect(element.text()).not.toContain("No directive for type: PrimitiveTypeBar");value.value.type.value="bar";$rootScope.$apply();expect(element.text()).toContain("No directive for type: PrimitiveTypeBar");
expect(element.text()).not.toContain("No directive for type: PrimitiveTypeFoo")});it("resets entered data when union type is changed",()=>{const value={type:"Foo",mro:["Foo"],value:{type:{type:"PrimitiveType",mro:["PrimitiveType"],value:"foo"},foo:{type:"PrimitiveTypeFoo",mro:["PrimitiveTypeFoo"]},bar:{type:"PrimitiveTypeBar",mro:["PrimitiveTypeBar"]}}};renderTestTemplate(value);$rootScope.$apply();value.value.foo.value=42;$rootScope.$apply();expect(value.value.foo.value).toBe(42);value.value.type.value=
"bar";$rootScope.$apply();expect(value.value.foo.value).toEqual({})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.semanticValueFormDirectiveTest");goog.setTestOnly();const {clearCaches}=goog.require("grrUi.forms.semanticValueFormDirective");const {formsModule}=goog.require("grrUi.forms.forms");const {testsModule}=goog.require("grrUi.tests");describe("semantic value form directive",()=>{let $compile;let $q;let $rootScope;let grrSemanticFormDirectivesRegistryService;let grrReflectionService;beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{clearCaches();$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrSemanticFormDirectivesRegistryService=$injector.get("grrSemanticFormDirectivesRegistryService");grrReflectionService=$injector.get("grrReflectionService");grrReflectionService.getRDFValueDescriptor=(valueType)=>{const deferred=$q.defer();deferred.resolve({name:valueType,mro:[valueType]});return deferred.promise}}));const renderTestTemplate=(value,metadata)=>
{$rootScope.value=value;$rootScope.metadata=metadata;const template='<grr-form-value value="value" metadata="metadata" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows error message if no corresponding directive found",()=>{const fooValue={type:"Foo",mro:["Foo"],value:"foo"};const element=renderTestTemplate(fooValue);expect(element.text()).toContain("No directive for type: Foo")});it("renders registered type with a corresponding directive",()=>{const directiveMock=
{directive_name:"theTestDirective"};grrSemanticFormDirectivesRegistryService.registerDirective("Foo",directiveMock);const fooValue={type:"Foo",mro:["Foo"],value:"foo"};const element=renderTestTemplate(fooValue);expect($("the-test-directive",element).length).toBe(1);expect($("the-test-directive[value]",element).length).toBe(1);expect($("the-test-directive[metadata]",element).length).toBe(1)});it("destroys nested directive's scope if value type is changed",()=>{const directiveFooMock={directive_name:"theFooTestDirective"};
const directiveBarMock={directive_name:"theBarTestDirective"};grrSemanticFormDirectivesRegistryService.registerDirective("Foo",directiveFooMock);grrSemanticFormDirectivesRegistryService.registerDirective("Bar",directiveBarMock);const fooValue={type:"Foo",mro:["Foo"],value:"foo"};const barValue={type:"Bar",mro:["Bar"],value:"bar"};const element=renderTestTemplate(fooValue);expect($("the-foo-test-directive",element).length).toBe(1);const fooScope=$("the-foo-test-directive",element).scope();fooScope.foo=
42;let firesCount=0;fooScope.$watch("foo",()=>{firesCount+=1});$rootScope.$apply();expect(firesCount).toBe(1);fooScope.foo=43;$rootScope.$apply();expect(firesCount).toBe(2);angular.extend(fooValue,barValue);$rootScope.$apply();expect($("the-bar-test-directive",element).length).toBe(1);fooScope.foo=44;$rootScope.$apply();expect(firesCount).toBe(2)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.timerangeFormDirectiveTest");goog.setTestOnly();const {formsModule}=goog.require("grrUi.forms.forms");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("timerange form directive",()=>{let $compile;let $q;let $rootScope;let grrReflectionService;beforeEach(module("/static/angular-components/forms/timerange-form.html"));beforeEach(module(formsModule.name));beforeEach(module(testsModule.name));stubDirective("grrFormValue");
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrReflectionService=$injector.get("grrReflectionService");spyOn(grrReflectionService,"getRDFValueDescriptor").and.callFake((valueType)=>{const deferred=$q.defer();if(valueType==="RDFDatetime")deferred.resolve({default:{type:"RDFDatetime",value:0}});else if(valueType==="Duration")deferred.resolve({default:{type:"Duration",value:0}});return deferred.promise})}));const renderTestTemplate=
(startTimeSecs,durationSecs,startTimeLabel,durationLabel)=>{$rootScope.startTimeSecs=startTimeSecs;$rootScope.durationSecs=durationSecs;if(angular.isDefined(startTimeLabel))$rootScope.startTimeLabel=startTimeLabel;if(angular.isDefined(durationLabel))$rootScope.durationLabel=durationLabel;const template="<grr-form-timerange "+'start-time-secs="startTimeSecs" '+'duration-secs="durationSecs" '+(angular.isDefined(startTimeLabel)?'start-time-label="startTimeLabel" ':"")+(angular.isDefined(durationLabel)?
'duration-label="durationLabel" ':"")+"></grr-form-timerange>";const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows the given scope params initially",()=>{const element=renderTestTemplate(123,456);let directive=element.find("grr-form-value:nth(0)");expect(directive.scope().$eval(directive.attr("value"))).toEqual({type:"RDFDatetime",value:123E6});directive=element.find("grr-form-value:nth(1)");expect(directive.scope().$eval(directive.attr("value"))).toEqual({type:"Duration",
value:456})});it("shows default labels by default",()=>{const element=renderTestTemplate(123,456);expect(element.find("label:nth(0)").text()).toBe("Time range start time");expect(element.find("label:nth(1)").text()).toBe("Time range duration")});it("shows custom labels if given",()=>{const element=renderTestTemplate(123,456,"Custom start time label","Custom duration label");expect(element.find("label:nth(0)").text()).toBe("Custom start time label");expect(element.find("label:nth(1)").text()).toBe("Custom duration label")});
it("forwards changed values to parent scope",()=>{const element=renderTestTemplate(123,456);let directive=element.find("grr-form-value:nth(0)");directive.scope().$eval(directive.attr("value")+".value = 321000000");directive=element.find("grr-form-value:nth(1)");directive.scope().$eval(directive.attr("value")+".value = 654");$rootScope.$apply();expect(element.scope().$eval(element.attr("start-time-secs"))).toEqual(321);expect(element.scope().$eval(element.attr("duration-secs"))).toEqual(654)})});exports=
{};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.forms.utilsTest");goog.setTestOnly();const {valueHasErrors}=goog.require("grrUi.forms.utils");describe("forms utils",()=>{describe("valueHasErrors",()=>{it("returns false for a primitive value without errors",()=>{expect(valueHasErrors({type:"RDFString",value:"blah"})).toBe(false)});it("returns true for a primitive value with an error",()=>{expect(valueHasErrors({type:"RDFString",value:"blah",validationError:"Oh no!"})).toBe(true)});
it("returns false for a value with a struct field without errors",()=>{expect(valueHasErrors({type:"RDFString",value:{foo:{type:"RDFInteger",value:42}}})).toBe(false)});it("returns true for a value with a struct field with an error",()=>{expect(valueHasErrors({type:"RDFString",value:{foo:{type:"RDFInteger",value:42,validationError:"Oh no!"}}})).toBe(true)});it("returns false for a value with an array field without errors",()=>{expect(valueHasErrors({type:"RDFString",value:{foo:[{type:"RDFInteger",
value:42}]}})).toBe(false)});it("returns true for a value with an array field with an error",()=>{expect(valueHasErrors({type:"RDFString",value:{foo:[{type:"RDFInteger",value:42,validationError:"Oh no!"}]}})).toBe(true)})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.hunt.huntStatsDirectiveTest");goog.setTestOnly();const {huntModule}=goog.require("grrUi.hunt.hunt");const {testsModule}=goog.require("grrUi.tests");describe("hunt stats directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/hunt/hunt-stats.html"));beforeEach(module(huntModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");
$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService")}));const render=(huntId)=>{$rootScope.huntId=huntId;const template='<grr-hunt-stats hunt-id="huntId" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows user cpu usage histogram",()=>{const statsResponse={stats:{type:"ClientResourcesStats",value:{user_cpu_stats:{type:"RunningStats",value:{histogram:{type:"StatsHistogram",value:{bins:[{type:"StatsHistogramBin",
value:{num:{type:"long",value:10.55},range_max_value:{type:"float",value:16.55}}},{type:"StatsHistogramBin",value:{num:{type:"long",value:5.55},range_max_value:{type:"float",value:32768.55}}}]}}}}}}};$.plot=jasmine.createSpy("$.plot spy").and.callFake((element,series,options)=>{expect(element.hasClass("user-cpu-histogram")).toBeTruthy();expect(series[0].data.length).toEqual(2);expect(series[0].data[0]).toEqual([0,10.55]);expect(series[0].data[1]).toEqual([1,5.55]);expect(options.xaxis.ticks).toEqual([[.5,
"16.6"],[1.5,"32768.6"]])});const deferred=$q.defer();deferred.resolve({data:statsResponse});spyOn(grrApiService,"get").and.returnValue(deferred.promise);render("H:12345678");expect(grrApiService.get).toHaveBeenCalledWith("/hunts/H:12345678/stats");expect($.plot).toHaveBeenCalled()});it("shows system cpu usage histogram",()=>{const statsResponse={stats:{type:"ClientResourcesStats",value:{system_cpu_stats:{type:"RunningStats",value:{histogram:{type:"StatsHistogram",value:{bins:[{type:"StatsHistogramBin",
value:{num:{type:"long",value:10.55},range_max_value:{type:"float",value:16.55}}},{type:"StatsHistogramBin",value:{num:{type:"long",value:5.55},range_max_value:{type:"float",value:32768.55}}}]}}}}}}};$.plot=jasmine.createSpy("$.plot spy").and.callFake((element,series,options)=>{expect(element.hasClass("system-cpu-histogram")).toBeTruthy();expect(series[0].data.length).toEqual(2);expect(series[0].data[0]).toEqual([0,10.55]);expect(series[0].data[1]).toEqual([1,5.55]);expect(options.xaxis.ticks).toEqual([[.5,
"16.6"],[1.5,"32768.6"]])});const deferred=$q.defer();deferred.resolve({data:statsResponse});spyOn(grrApiService,"get").and.returnValue(deferred.promise);render("H:12345678");expect(grrApiService.get).toHaveBeenCalledWith("/hunts/H:12345678/stats");expect($.plot).toHaveBeenCalled()});it("shows network bytes histogram with correct values and xaxis labels",()=>{const statsResponse={stats:{type:"ClientResourcesStats",value:{network_bytes_sent_stats:{type:"RunningStats",value:{histogram:{type:"StatsHistogram",
value:{bins:[{type:"StatsHistogramBin",value:{num:{type:"long",value:10},range_max_value:{type:"float",value:16}}},{type:"StatsHistogramBin",value:{num:{type:"long",value:5},range_max_value:{type:"float",value:32768}}}]}}}}}}};$.plot=jasmine.createSpy("$.plot spy").and.callFake((element,series,options)=>{expect(element.hasClass("network-bytes-histogram")).toBeTruthy();expect(series[0].data.length).toEqual(2);expect(series[0].data[0]).toEqual([0,10]);expect(series[0].data[1]).toEqual([1,5]);expect(options.xaxis.ticks).toEqual([[.5,
"16B"],[1.5,"32K"]])});const deferred=$q.defer();deferred.resolve({data:statsResponse});spyOn(grrApiService,"get").and.returnValue(deferred.promise);render("H:12345678");expect(grrApiService.get).toHaveBeenCalledWith("/hunts/H:12345678/stats");expect($.plot).toHaveBeenCalled()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.hunt.rapidHuntStatusDirectiveTest");goog.setTestOnly();const {huntModule}=goog.require("grrUi.hunt.hunt");const {isEligible}=goog.require("grrUi.hunt.rapidHuntStatusDirective");const {testsModule}=goog.require("grrUi.tests");describe("rapidHuntStatusDirective.isEligible",()=>{it("considers FileFinder flow with default args eligible",()=>{expect(isEligible("FileFinder",{type:"FileFinderArgs",value:{}})).toBe(true)});it("considers ClientFileFinder flow with default args eligible",
()=>{expect(isEligible("ClientFileFinder",{type:"FileFinderArgs",value:{}})).toBe(true)});it("considers ListProcesses flow not eligible",()=>{expect(isEligible("ListProcesses",{type:"ListProcessesArgs",value:{}})).toBe(false)});it("considers FileFinder with a recursive glob non-eligible",()=>{expect(isEligible("ClientFileFinder",{type:"FileFinderArgs",value:{paths:[{type:"GlobExpression",value:"/foo/**"}]}})).toBe(false)});it("considers FileFinder with a single star in a glob eligible",()=>{expect(isEligible("ClientFileFinder",
{type:"FileFinderArgs",value:{paths:[{type:"GlobExpression",value:"/foo/*"}]}})).toBe(true)});it("considers FileFinder with two stars in a glob eligible",()=>{expect(isEligible("ClientFileFinder",{type:"FileFinderArgs",value:{paths:[{type:"GlobExpression",value:"/foo/*/bar/*"}]}})).toBe(false)});it("considers FileFinder with DOWNLOAD action non eligible",()=>{expect(isEligible("ClientFileFinder",{type:"FileFinderArgs",value:{action:{type:"FileFinderAction",value:{action_type:{type:"EnumNamedValue",
value:"DOWNLOAD"}}}}})).toBe(false)})});describe("grr-rapid-hunt-status directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/hunt/rapid-hunt-status.html"));beforeEach(module(huntModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService")}));const setRapidHuntsEnabled=(flag)=>
{const deferred=$q.defer();deferred.resolve({data:{value:{value:flag}}});spyOn(grrApiService,"getCached").and.returnValue(deferred.promise)};const render=(flowName,flowArgs,clientRate)=>{$rootScope.flowName=flowName;$rootScope.flowArgs=flowArgs;$rootScope.clientRate=clientRate;const template='<grr-rapid-hunt-status flow-name="flowName" '+'flow-args="flowArgs" client-rate="clientRate" '+'is-eligible="isEligible" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("does nothing if rapid hunts are turned off",
()=>{setRapidHuntsEnabled(false);const element=render("FileFinder",{type:"FileFinderArgs",value:{}},0);expect(element.text()).not.toContain("eligible")});it('correctly renders "eligible" note if rapid hunts are on',()=>{setRapidHuntsEnabled(true);const element=render("FileFinder",{type:"FileFinderArgs",value:{}},0);expect(element.text()).toContain("is eligible")});it('renders "Client rate set to 0" if rapid hunts are on and client rate is 0',()=>{setRapidHuntsEnabled(true);const element=render("FileFinder",
{type:"FileFinderArgs",value:{}},0);expect(element.text()).toContain("Client rate set to 0")});it('omits "Client rate set to 0" if rapid hunts are on but client rate not 0',()=>{setRapidHuntsEnabled(true);const element=render("FileFinder",{type:"FileFinderArgs",value:{}},42);expect(element.text()).not.toContain("Client rate set to 0")});it('correctly renders "non eligible" note if rapid hunts are off',()=>{setRapidHuntsEnabled(true);const element=render("ListProcesses",{type:"ListProcessesArgs",value:{}},
0);expect(element.text()).toContain("is not eligible")})});return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.outputPlugins.outputPluginLogsDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,stubDirective,testsModule}=goog.require("grrUi.tests");const {outputPluginsModule}=goog.require("grrUi.outputPlugins.outputPlugins");describe("output plugin logs directive",()=>{let $compile;let $q;let $rootScope;let $timeout;let grrApiService;beforeEach(module("/static/angular-components/output-plugins/output-plugin-logs.html"));beforeEach(module("/static/angular-components/output-plugins/output-plugin-logs-modal.html"));
beforeEach(module(outputPluginsModule.name));beforeEach(module(testsModule.name));stubDirective("grrPagedFilteredTable");beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$timeout=$injector.get("$timeout");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=()=>{$rootScope.url="foo/bar";const template='<grr-output-plugin-logs url="url" label="a foo"'+'css-class="label-danger" icon="foo-icon" />';const element=
$compile(template)($rootScope);$rootScope.$apply();return element};it("fetches and show items count",()=>{const deferred=$q.defer();deferred.resolve({data:{total_count:42}});spyOn(grrApiService,"get").and.returnValue(deferred.promise);const element=renderTestTemplate();expect(element.text()).toContain("42")});it("shows nothing if total_count is 0",()=>{const deferred=$q.defer();deferred.resolve({data:{total_count:0}});spyOn(grrApiService,"get").and.returnValue(deferred.promise);const element=renderTestTemplate();
expect(element.text().trim()).toBe("")});describe("inspect dialog",()=>{beforeEach(()=>{const deferred=$q.defer();deferred.resolve({data:{total_count:42}});spyOn(grrApiService,"get").and.returnValue(deferred.promise)});afterEach(()=>{$(document.body).html("")});it("is shown when label is clicked",()=>{const element=renderTestTemplate();browserTriggerEvent(element.find(".label"),"click");expect($(document.body).text()).toContain("Inspect a foo")});it("closes when close button is clicked",()=>{const element=
renderTestTemplate();browserTriggerEvent(element.find(".label"),"click");browserTriggerEvent($("button.close"),"click");$timeout.flush();expect($(document.body).text()).not.toContain("Inspect a foo")})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.outputPlugins.outputPluginNoteBodyDirectiveTest");goog.setTestOnly();const {outputPluginsModule}=goog.require("grrUi.outputPlugins.outputPlugins");const {testsModule}=goog.require("grrUi.tests");describe("output plugin note directive",()=>{let $compile;let $rootScope;let grrOutputPluginsDirectivesRegistryService;beforeEach(module(outputPluginsModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=
$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrOutputPluginsDirectivesRegistryService=$injector.get("grrOutputPluginsDirectivesRegistryService")}));const defaultOutputPlugin={value:{plugin_descriptor:{value:{plugin_name:{value:"Foo"}}}}};const renderTestTemplate=(outputPlugin)=>{$rootScope.outputPlugin=outputPlugin||angular.copy(defaultOutputPlugin);const template="<grr-output-plugin-note-body "+'output-plugin="outputPlugin" />';const element=$compile(template)($rootScope);$rootScope.$apply();
return element};it("shows nothing if no corresponding directive found",()=>{const element=renderTestTemplate();expect(element.text().trim()).toBe("")});it("renders registered type with a corresponding directive",()=>{const directiveMock={directive_name:"theTestDirective"};grrOutputPluginsDirectivesRegistryService.registerDirective("Foo",directiveMock);const element=renderTestTemplate();expect($("the-test-directive",element).length).toBe(1)});it("passes outputPlugin to the corresponding directive",
()=>{const directiveMock={directive_name:"theTestDirective"};grrOutputPluginsDirectivesRegistryService.registerDirective("Foo",directiveMock);const element=renderTestTemplate();const directive=element.find("the-test-directive");expect(directive.scope().$eval(directive.attr("output-plugin"))).toEqual(defaultOutputPlugin)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.outputPlugins.outputPluginNoteDirectiveTest");goog.setTestOnly();const {outputPluginsModule}=goog.require("grrUi.outputPlugins.outputPlugins");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("output plugin note directive",()=>{let $compile;let $rootScope;let grrOutputPluginsDirectivesRegistryService;beforeEach(module("/static/angular-components/output-plugins/output-plugin-note.html"));beforeEach(module(outputPluginsModule.name));
beforeEach(module(testsModule.name));stubDirective("grrOutputPluginNoteBody");stubDirective("grrOutputPluginLogs");beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrOutputPluginsDirectivesRegistryService=$injector.get("grrOutputPluginsDirectivesRegistryService")}));const defaultOutputPlugin={value:{plugin_descriptor:{value:{plugin_name:{value:"Foo"}}},id:{value:"42"}}};const renderTestTemplate=(outputPlugin)=>{$rootScope.outputPlugin=outputPlugin||
angular.copy(defaultOutputPlugin);$rootScope.outputPluginsUrl="/foo/bar";const template='<grr-output-plugin-note output-plugin="outputPlugin" '+'output-plugins-url="outputPluginsUrl" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows registered plugin title if registered",()=>{let element=renderTestTemplate();expect(element.text()).toContain("");const directiveMock={directive_name:"theTestDirective",output_plugin_title:"a bar plugin"};grrOutputPluginsDirectivesRegistryService.registerDirective("Foo",
directiveMock);element=renderTestTemplate();expect(element.text()).toContain("a bar plugin")});it("shows plugin descriptor name if not registered",()=>{const element=renderTestTemplate();expect(element.text()).toContain("Foo")});it("delegates rendering to grr-output-plugin-note-body",()=>{const element=renderTestTemplate();const body=element.find("grr-output-plugin-note-body");expect(body.scope().$eval(body.attr("output-plugin"))).toEqual(defaultOutputPlugin)});it("delegates logs info rendering to grr-output-plugin-logs",
()=>{const element=renderTestTemplate();const logs=element.find("grr-output-plugin-logs:nth(0)");expect(logs.scope().$eval(logs.attr("url"))).toEqual("/foo/bar/42/logs")});it("delegates errors info rendering to grr-output-plugin-logs",()=>{const element=renderTestTemplate();const errors=element.find("grr-output-plugin-logs:nth(1)");expect(errors.scope().$eval(errors.attr("url"))).toEqual("/foo/bar/42/errors")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.outputPlugins.outputPluginsNotesDirectiveTest");goog.setTestOnly();const {outputPluginsModule}=goog.require("grrUi.outputPlugins.outputPlugins");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("output plugins notes list directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/output-plugins/"+"output-plugins-notes.html"));beforeEach(module(outputPluginsModule.name));
beforeEach(module(testsModule.name));stubDirective("grrOutputPluginNote");beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=()=>{$rootScope.outputPluginsUrl="/foo/bar/plugins";const template="<grr-output-plugins-notes "+'output-plugins-url="outputPluginsUrl" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("requests output plugins metadata via API service",
()=>{const deferred=$q.defer();spyOn(grrApiService,"get").and.returnValue(deferred.promise);renderTestTemplate();expect(grrApiService.get).toHaveBeenCalledWith("/foo/bar/plugins")});it("shows an error when API request fails",()=>{const deferred=$q.defer();spyOn(grrApiService,"get").and.returnValue(deferred.promise);deferred.reject({data:{message:"FAIL"}});const element=renderTestTemplate();expect(element.text()).toContain("Can't fetch output plugins list: "+"FAIL")});it("delegates every plugin display to grr-output-plugin-note",
()=>{const deferred=$q.defer();spyOn(grrApiService,"get").and.returnValue(deferred.promise);const plugin1={value:"foo"};const plugin2={value:"bar"};deferred.resolve({data:{items:[plugin1,plugin2]}});const element=renderTestTemplate();expect(element.find("grr-output-plugin-note").length).toBe(2);let directive=element.find("grr-output-plugin-note:nth(0)");expect(directive.scope().$eval(directive.attr("output-plugin"))).toEqual(plugin1);directive=element.find("grr-output-plugin-note:nth(1)");expect(directive.scope().$eval(directive.attr("output-plugin"))).toEqual(plugin2)})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.routing.aff4UrnToUrlTest");goog.setTestOnly();const {aff4UrnToUrl}=goog.require("grrUi.routing.aff4UrnToUrl");describe("aff4UrnToUrl()",()=>{it("doesn't convert random string",()=>{expect(aff4UrnToUrl("aff4:/foo/bar")).toBe(null)});it("converts non-flow and non-vfs URN in client scope to the client link",()=>{expect(aff4UrnToUrl("aff4:/C.0001000200030004/foo/bar")).toEqual({state:"client",params:{clientId:"C.0001000200030004"}})});
it("converts client-scoped fs/os-prefixed URN to VFS link",()=>{expect(aff4UrnToUrl("aff4:/C.0001000200030004/fs/os/foo/bar")).toEqual({state:"client.vfs",params:{clientId:"C.0001000200030004",path:"fs/os/foo/bar"}})});it("converts client-scoped flow URN to a flow link",()=>{expect(aff4UrnToUrl("aff4:/C.0001000200030004/flows/F:123456")).toEqual({state:"client.flows",params:{clientId:"C.0001000200030004",flowId:"F:123456"}})});it("converts hunt URN to a hunt link",()=>{expect(aff4UrnToUrl("aff4:/hunts/H:123456")).toEqual({state:"hunts",
params:{huntId:"H:123456"}})});it("converts cron job URN to a cron job link",()=>{expect(aff4UrnToUrl("aff4:/cron/SomeCronJob")).toEqual({state:"crons",params:{cronJobId:"SomeCronJob"}})});it("converts client approval URN to a client approval link",()=>{expect(aff4UrnToUrl("aff4:/ACL/C.0001000200030004/test/approval_id")).toEqual({state:"clientApproval",params:{clientId:"C.0001000200030004",username:"test",approvalId:"approval_id"}})});it("converts hunt approval URN to a hunt approval link",()=>{expect(aff4UrnToUrl("aff4:/ACL/hunts/H:123456/test/approval_id")).toEqual({state:"huntApproval",
params:{huntId:"H:123456",username:"test",approvalId:"approval_id"}})});it("converts cron job approval URN to a cron job approval link",()=>{expect(aff4UrnToUrl("aff4:/ACL/cron/SomeCronJob/test/approval_id")).toEqual({state:"cronJobApproval",params:{cronJobId:"SomeCronJob",username:"test",approvalId:"approval_id"}})});it("handles non-URL-friendly characters correctly",()=>{expect(aff4UrnToUrl("aff4:/C.0001000200030004/fs/os/_f$o/bA%")).toEqual({state:"client.vfs",params:{clientId:"C.0001000200030004",
path:"fs/os/_f$o/bA%"}})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.routing.rewriteUrlTest");goog.setTestOnly();const {rewriteUrl}=goog.require("grrUi.routing.rewriteUrl");describe("rewriteUrl()",()=>{const mapping={};mapping["main=ManageCron"]="/crons/";mapping["main=ManageCron&cron_job_urn=aff4:/cron/CleanTemp"]="/crons/CleanTemp";mapping["main=ManageHunts"]="/hunts/";mapping["main=ManageHunts&hunt_id=aff4:/hunts/H:123456"]="/hunts/H:123456";mapping["main=VirtualFileSystemView&c=C.dc1a70ddaaba407a&tag=AFF4Stats"+
"&t=_fs-tsk-_5C_5C_3F_5CVolume_7B649ac6fa_2D9ab4_"+"2D11e5_2Db332_2D806e6f6e6963_7D"]="/clients/C.dc1a70ddaaba407a/vfs/fs/tsk/"+"%5C%5C%3F%5CVolume%7B649ac6fa-9ab4-11e5-b332-806e6f6e6963%7D/";mapping["main=GlobalLaunchFlows"]="/global-flows";mapping["main=ServerLoadView"]="/server-load";mapping["main=BinaryConfigurationView"]="/manage-binaries";mapping["main=ConfigManager"]="/config";mapping["main=ArtifactManagerView"]="/artifacts";mapping["main=ApiDocumentation"]="/api-docs";mapping["main=GrantAccess&acl="+
"aff4%3A%2FACL%2Fhunts%2FH%3A55AAAA70%2Ftest%2Fapproval%3A6AFF3CC9"]="/users/test/approvals/hunt/H:55AAAA70/approval:6AFF3CC9";mapping["main=GrantAccess&acl="+"aff4%3A%2FACL%2FC.833c593a0fe6aca0%2Ftest%2Fapproval%3A8935BE23"]="/users/test/approvals/client/C.833c593a0fe6aca0/approval:8935BE23";mapping["main=CanaryTestRenderer"]="/canary-test";mapping["main=HostTable"]="/search?q=";mapping["main=HostTable&q=test"]="/search?q=test";it("should map legacy URLs to correct sane URLs",()=>{angular.forEach(mapping,
(targetUrl,legacyUrl)=>{expect(rewriteUrl(legacyUrl)).toEqual(targetUrl)})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.byteSizeDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("grrByteSize directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/semantic/byte-size.html"));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");
$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-byte-size value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('shows "-" when value is empty',()=>{const value={type:"ByteSize",value:null};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("-")});it("shows 0 if value is 0",()=>{const value={type:"ByteSize",value:0};const element=renderTestTemplate(value);
expect(element.text().trim()).toBe("0")});it("shows value in bytes if it is less than 1024",()=>{const value={type:"ByteSize",value:42};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("42B")});it("shows value in kibibytes if it is less than 1024**2",()=>{const value={type:"ByteSize",value:1124};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("1.1KiB")});it("shows value in mebibytes if it is less than 1024**3",()=>{const value={type:"ByteSize",
value:44040192};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("42MiB")});it("shows value in gibibytes if it is more than 1024**3",()=>{const value={type:"ByteSize",value:1610612736};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("1.5GiB")});it("shows value in bytes in the tooltip",()=>{const value={type:"ByteSize",value:1610612736};const element=renderTestTemplate(value);expect(element.find("span").attr("title")).toBe("1610612736 bytes")})});
exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.bytesDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {semanticModule}=goog.require("grrUi.semantic.semantic");describe("bytes directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/semantic/bytes.html"));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");
$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-bytes value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing when value is empty",()=>{const value={type:"RDFBytes",value:null};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("")});it("shows error message if value is incorrectly base64-encoded",()=>{const value={type:"RDFBytes",value:"--"};
const element=renderTestTemplate(value);expect(element.text().trim()).toMatch(/base64decodeerror.*:--/)});it("converts base64-encoded value into a hex-encoded string",()=>{const macAddress={type:"MacAddress",value:"Zm9vDcg="};const element=renderTestTemplate(macAddress);expect(element.text()).toContain("foo\\x0d\\xc8")});it("hides content behind a link if its longer than 1024 bytes",()=>{const value={type:"RDFBytes",value:Array(1025).join("-")};const element=renderTestTemplate(value);expect(element.text()).not.toMatch(/base64decodeerror.*:--/);
expect(element.text()).toContain("Show bytes...");browserTriggerEvent($("a",element),"click");expect(element.text()).toMatch(/base64decodeerror.*:--/);expect(element.text()).not.toContain("Show bytes...")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.clientUrnDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {semanticModule}=goog.require("grrUi.semantic.semantic");describe("client urn directive",()=>{let $compile;let $q;let $rootScope;let $timeout;let grrApiService;beforeEach(module("/static/angular-components/semantic/client-urn.html"));beforeEach(module("/static/angular-components/semantic/client-urn-modal.html"));
beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$timeout=$injector.get("$timeout");grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-client-urn value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("does not show anything when value is empty",
()=>{const element=renderTestTemplate(null);expect(element.text().trim()).toBe("")});it("shows string value",()=>{const element=renderTestTemplate("aff4:/C.0000000000000001");expect(element.text()).toContain("C.0000000000000001")});it("shows value with type information",()=>{const clientUrn={age:0,type:"ClientURN",value:"aff4:/C.0000000000000001"};const element=renderTestTemplate(clientUrn);expect(element.text()).toContain("C.0000000000000001")});it("has a proper href",()=>{const clientUrn={age:0,
type:"ClientURN",value:"aff4:/C.0000000000000001"};const element=renderTestTemplate(clientUrn);expect(element.find("a").attr("href")).toBe("#!/clients/C.0000000000000001/host-info")});describe("client urn summary modal dialog",()=>{beforeEach(()=>{grrApiService.get=(urn,params)=>{expect(urn).toBe("clients/C.0000000000000001");return $q((resolve,reject)=>{resolve({data:"This is a summary"})})}});afterEach(()=>{$(document.body).html("")});it("is shown when info button is clicked",()=>{const element=
renderTestTemplate("aff4:/C.0000000000000001");browserTriggerEvent($("button",element),"click");expect($(document.body).text()).toContain("Client C.0000000000000001")});it('is shown when info button is clicked and value has no "aff4" prefix',()=>{const element=renderTestTemplate("C.0000000000000001");browserTriggerEvent($("button",element),"click");expect($(document.body).text()).toContain("Client C.0000000000000001")});it("closed when close button is clicked",()=>{const element=renderTestTemplate("aff4:/C.0000000000000001");
browserTriggerEvent($("button",element),"click");expect($(document.body).text()).toContain("Client C.0000000000000001");browserTriggerEvent($("button.close"),"click");$timeout.flush();expect($(document.body).text()).not.toContain("Client C.0000000000000001")})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.dataObjectDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("data object semantic directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/semantic/data-object.html"));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));stubDirective("grrSemanticValue");
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-data-object value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows empty table when value is empty",()=>{const element=renderTestTemplate({type:"ApiDataObject",value:{}});expect(element.find("table").length).toBe(1);expect(element.find("tr").length).toBe(0)});
it("shows 2 rows for a data object with two key-value pairs",()=>{const element=renderTestTemplate({type:"ApiDataObject",value:{items:[{type:"ApiDataObjectKeyValuePair",value:{key:{type:"unicode",value:"Test Integer Value"},value:{type:"RDFInteger",value:1E3}}},{type:"ApiDataObjectKeyValuePair",value:{key:{type:"unicode",value:"Test String Value"},value:{type:"RDFString",value:"<some value>"}}}]}});expect(element.find("table").length).toBe(1);expect(element.find("tr").length).toBe(2);expect(element.text()).toContain("Test Integer Value");
expect(element.text()).toContain("Test String Value");expect(element.find("grr-semantic-value").length).toBe(2)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.dictDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("dict semantic directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/semantic/dict.html"));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));stubDirective("grrSemanticValue");beforeEach(inject(($injector)=>
{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-dict value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows empty table when value is empty",()=>{const element=renderTestTemplate({type:"dict",value:{}});expect(element.find("table").length).toBe(1);expect(element.find("tr").length).toBe(0)});it("shows 2 keys and corresponding values for value with 2 keys",
()=>{const element=renderTestTemplate({type:"dict",value:{fooKey:{type:"Foo"},barKey:{type:"Bar"}}});expect(element.find("table").length).toBe(1);expect(element.find("tr").length).toBe(2);expect(element.text()).toContain("fooKey");expect(element.text()).toContain("barKey");expect(element.find("grr-semantic-value").length).toBe(2)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.durationDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("duration directive",()=>{let $compile;let $rootScope;beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=
(value)=>{$rootScope.value=value;const template='<grr-duration value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('shows "-" when value is empty',()=>{const value={type:"Duration",value:null};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("-")});it("shows 0 if duration value is 0",()=>{const value={type:"Duration",value:0};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("0")});it("shows duration in seconds if it's not divisible by 60",
()=>{const value={type:"Duration",value:122};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("122s")});it("shows duration in minutes if possible",()=>{const value={type:"Duration",value:120};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("2m")});it("shows duration in hours if possible",()=>{const value={type:"Duration",value:7200};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("2h")});it("shows duration in days if possible",
()=>{const value={type:"Duration",value:172800};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("2d")});it("shows duration in weeks if possible",()=>{const value={type:"Duration",value:1209600};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("2w")});it("shows duration in days if not divisible by 7",()=>{const value={type:"Duration",value:1036800};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("12d")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.encryptionKeyDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {stringifyEncryptionKey}=goog.require("grrUi.semantic.encryptionKeyDirective");const {testsModule}=goog.require("grrUi.tests");describe("encryption key directive",()=>{describe("stringifyEncryptionKey()",()=>{it("converts base64 encoded string of zeroes to a hex-string",()=>{expect(stringifyEncryptionKey("AAAAAA==")).toBe("00000000")});
it("converts sample base64 encoded string to a hex-string",()=>{expect(stringifyEncryptionKey("AAABAgMEBQYHCAkKCwwNDg8Q")).toBe("00000102030405060708090a0b0c0d0e0f10")})});let $compile;let $rootScope;beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-encryption-key value="value" />';const element=
$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing when value is empty",()=>{const element=renderTestTemplate(undefined);expect(element.text().trim()).toBe("")});it("shows hex-stringified bytes when value is not empty",()=>{const element=renderTestTemplate({type:"EncryptionKey",value:"AAABAgMEBQYHCAkKCwwNDg8Q"});expect(element.text().trim()).toBe("00000102030405060708090a0b0c0d0e0f10")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.exactDurationDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("exact duration directive",()=>{let $compile;let $rootScope;beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderExactDuration=
(value)=>{$rootScope.value=value;const template='<grr-exact-duration value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('shows "-" when value is empty',()=>{const value={type:"Duration",value:null};const element=renderExactDuration(value);expect(element.text().trim()).toBe("-")});it("handles zero-values correctly",()=>{const value={type:"Duration",value:0};const element=renderExactDuration(value);expect(element.text().trim()).toBe("0s")});it("correctly renders whole seconds",
()=>{const value={type:"Duration",value:42};const element=renderExactDuration(value);expect(element.text().trim()).toBe("42s")});it("correctly renders whole minutes",()=>{const value={type:"Duration",value:120};const element=renderExactDuration(value);expect(element.text().trim()).toBe("2m")});it("correctly renders whole hours",()=>{const value={type:"Duration",value:3600};const element=renderExactDuration(value);expect(element.text().trim()).toBe("1h")});it("correctly renders compound values",()=>
{const value={type:"Duration",value:131+(new Date("2000-01-20")-new Date("2000-01-01"))/1E3};const element=renderExactDuration(value);expect(element.text().trim()).toBe("2w 5d 2m 11s")});it("rounds to nearest seconds",()=>{const value={type:"Duration",value:62.5};const element=renderExactDuration(value);expect(element.text().trim()).toBe("1m 3s")});it("raises on negative duration values",()=>{const value={type:"Duration",value:-11};expect(()=>renderExactDuration(value)).toThrow()})});return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.flowIdDirectiveTest");goog.setTestOnly();const {clientModule}=goog.require("grrUi.client.client");const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("grr-flow-id directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/semantic/flow-id.html"));beforeEach(module(clientModule.name));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value,clientId)=>{$rootScope.value=value;let template='<grr-flow-id value="value"></grr-flow-id>';if(clientId){$rootScope.clientId=clientId;template='<grr-client-context client-id="clientId">'+template+"</grr-client-context>"}const element=$compile(template)($rootScope);$rootScope.$apply();return element};const sampleValue={value:"F:112233",type:"ApiFlowId"};describe("without client context",
()=>{it("renders flow id as a string",()=>{const element=renderTestTemplate(sampleValue);expect(element.find('span:contains("F:112233")').length).toBe(1);expect(element.find('a:contains("F:112233")').length).toBe(0)})});describe("with client context",()=>{it("renders flow id as a link",()=>{const element=renderTestTemplate(sampleValue,"C.1111222233334444");expect(element.find('span:contains("F:112233")').length).toBe(0);const aRef=element.find('a:contains("F:112233")');expect(aRef.length).toBe(1);
expect(aRef.attr("href")).toBe("#!/clients/C.1111222233334444/flows/F%3A112233")});it("renders a tooltip with a client id",()=>{const element=renderTestTemplate(sampleValue,"C.1111222233334444");const aref=element.find('a:contains("F:112233")');expect(aref.attr("title")).toBe("Flow F:112233 ran on client C.1111222233334444")})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.hashDigestDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("hash digest directive",()=>{let $compile;let $rootScope;beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=
(value)=>{$rootScope.value=value;const template='<grr-hash-digest value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing when value is empty",()=>{const value={type:"HashDigest",value:null};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("")});it("shows error message if value is incorrectly base64-encoded",()=>{const value={type:"HashDigest",value:"--"};const element=renderTestTemplate(value);expect(element.text().trim()).toMatch(/base64decodeerror.*:--/)});
it("converts base64-encoded value into a hex-encoded string",()=>{const base64EncodedHash={type:"HashDigest",value:"dGVzdA=="};const element=renderTestTemplate(base64EncodedHash);expect(element.text()).toContain("74657374")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.hashListDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("hash list directive",()=>{let $compile;let $rootScope;beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));stubDirective("grrSemanticValue");beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));
const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-hash-list value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing when value is empty",()=>{const value={type:"HashList",value:null};const element=renderTestTemplate(value);expect(element.find("grr-hash-digest").length).toBe(0)});it("delegates single item to grr-semantic-value",()=>{const base64EncodedHashList={type:"HashList",value:"MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE="};
const element=renderTestTemplate(base64EncodedHashList);const directive=element.find("grr-semantic-value");expect(angular.equals(directive.scope().$eval(directive.attr("value"))),[{type:"HashDigest",value:"MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE="}])});it("delegates two items to grr-hash-digest",()=>{const base64EncodedHashList={type:"HashList",value:"MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE"+"yMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMg=="};const element=renderTestTemplate(base64EncodedHashList);
const directive=element.find("grr-semantic-value");expect(angular.equals(directive.scope().$eval(directive.attr("value"))),[{type:"HashDigest",value:"MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE="},{type:"HashDigest",value:"MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI="}])})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.jsonDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {semanticModule}=goog.require("grrUi.semantic.semantic");describe("json directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/semantic/json.html"));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");
$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-json value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing when value is empty",()=>{const value={type:"ZippedJSONBytes",value:null};const element=renderTestTemplate(value);expect(element.text().trim()).toBe("")});it("shows error message if value is not correct json",()=>{const value={type:"ZippedJSONBytes",value:"--"};
const element=renderTestTemplate(value);expect(element.text().trim()).toMatch(/jsonerror.*:--/)});it("shows json string when it's a correct json string",()=>{const value={type:"ZippedJSONBytes",value:'[{"foo": 42}]'};const element=renderTestTemplate(value);expect(element.text()).toContain('"foo": 42')});it("hides content behind a link if its longer than 1024 bytes",()=>{const value={type:"ZippedJSONBytes",value:Array(1025).join("-")};const element=renderTestTemplate(value);expect(element.text()).not.toMatch(/base64decodeerror.*:--/);
expect(element.text()).toContain("Show JSON...");browserTriggerEvent($("a",element),"click");expect(element.text()).toMatch(/jsonerror.*:--/);expect(element.text()).not.toContain("Show JSON...")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.macAddressDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("mac address directive",()=>{let $compile;let $rootScope;beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=
(value)=>{$rootScope.value=value;const template='<grr-mac-address value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('shows "-" when value is empty',()=>{const macAddress={type:"MacAddress",value:null};const element=renderTestTemplate(macAddress);expect(element.text().trim()).toBe("-")});it("expands base64-encoded value into a human-readable string",()=>{const macAddress={type:"MacAddress",value:"+BZUBnli"};const element=renderTestTemplate(macAddress);
expect(element.text()).toContain("f8:16:54:06:79:62")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.networkAddressDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("mac address directive",()=>{let $compile;let $rootScope;beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=
(value)=>{$rootScope.value=value;const template='<grr-network-address value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('shows "-" when value is null',()=>{const element=renderTestTemplate(null);expect(element.text().trim()).toBe("-")});it("shows IPv4 value for IPv4 address without metadata",()=>{const element=renderTestTemplate({packed_bytes:"+BZUBn",address_type:"INET"});expect(element.text()).toContain("248.22.84.06")});it("shows IPv4 value for IPv4 address with metadata",
()=>{const element=renderTestTemplate({value:{packed_bytes:{value:"+BZUBn"},address_type:{value:"INET"}}});expect(element.text()).toContain("248.22.84.06")});it("shows IPv6 value for IPv6 address without metadata",()=>{const element=renderTestTemplate({packed_bytes:"+BZUBnliBnl",address_type:"INET6"});expect(element.text()).toContain("f816:5406:7962:0679")});it("shows IPv6 value for IPv6 address with metadata",()=>{const element=renderTestTemplate({value:{packed_bytes:{value:"+BZUBnliBnl"},address_type:{value:"INET6"}}});
expect(element.text()).toContain("f816:5406:7962:0679")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.semanticDiffAnnotatedProtoDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("grr-semantic-diff-annotated-proto directive",()=>{let $compile;let $q;let $rootScope;let grrReflectionService;beforeEach(module("/static/angular-components/semantic/semantic-diff-annotated-proto.html"));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrReflectionService=$injector.get("grrReflectionService");spyOn(grrReflectionService,"getRDFValueDescriptor");const descriptors={"Bar":{},"Foo":{fields:[{name:"a"},{name:"foo"},{name:"bar"}]}};grrReflectionService.getRDFValueDescriptor.and.callFake((typeName)=>{const deferred=$q.defer();deferred.resolve(descriptors[typeName]);return deferred.promise})}));const renderTestTemplate=
(value)=>{$rootScope.value=value;const template='<grr-semantic-diff-annotated-proto value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('renders only after the "value" binding is set',()=>{const element=renderTestTemplate(undefined);expect(element.find('td:contains("foo")').length).toBe(0);$rootScope.value={type:"Foo",value:{foo:{type:"Bar",value:42}}};$rootScope.$apply();expect(element.find('td:contains("foo")').length).toBe(1)});it('"value" binding is effectively a one-time binding',
()=>{const value={type:"Foo",value:{foo:{type:"Bar",value:42}}};const element=renderTestTemplate(value);expect(element.find('td:contains("bar")').length).toBe(0);const newValue=angular.copy(value);newValue["value"]["bar"]={type:"Bar",value:43};$rootScope.value=newValue;$rootScope.$apply();expect(element.find('td:contains("bar")').length).toBe(0)});angular.forEach(["added","changed","removed"],(annotation)=>{it(`renders "${annotation}" annotation on the value itself correctly`,()=>{const value={type:"Foo",
value:42,_diff:annotation};const element=renderTestTemplate(value);expect(element.find(`table.diff-${annotation}`).length).toBe(1)});it(`renders "${annotation}"-annotated non-repeated field correctly`,()=>{const value={type:"Foo",value:{a:{type:"Bar",value:42,_diff:annotation}}};const element=renderTestTemplate(value);expect(element.find(`tr.diff-${annotation}`).length).toBe(1)});it(`renders "${annotation}"-annotated repeated field correctly`,()=>{const value={type:"Foo",value:{a:[{type:"Bar",value:42,
_diff:annotation}]}};const element=renderTestTemplate(value);expect(element.find(`div.repeated.diff-${annotation}`).length).toBe(1)})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.semanticProtoDirectiveTest");goog.setTestOnly();const {buildItems,buildNonUnionItems,buildUnionItems,getUnionFieldValue}=goog.require("grrUi.semantic.semanticProtoDirective");const {semanticModule}=goog.require("grrUi.semantic.semantic");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("semantic proto directive",()=>{describe("getUnionFieldValue()",()=>{it("throws if descriptor doesn't have union_field",
()=>{expect(()=>{getUnionFieldValue({},{})}).toThrow()});it("returns union field value when it's set",()=>{const value={type:"FooType",value:{action_type:{type:"unicode",value:"DOWNLOAD"}}};const descriptor={union_field:"action_type"};expect(getUnionFieldValue(value,descriptor)).toBe("download")});it("returns union field value default if it's not set",()=>{const value={type:"FooType",value:{}};const descriptor={union_field:"action_type",fields:[{name:"action_type",default:{type:"unicode",value:"DOWNLOAD"}}]};
expect(getUnionFieldValue(value,descriptor)).toBe("download")})});describe("buildUnionItems()",()=>{const descriptor={union_field:"action_type",fields:[{name:"action_type",default:{type:"unicode",value:"SEND_TO_SOCKET"}},{name:"download",default:{type:"unicode",value:"defaultFoo"}},{name:"send_to_socket",default:{type:"unicode",value:"defaultBar"}}]};const valueWithSetFields={type:"FooType",value:{action_type:{type:"unicode",value:"DOWNLOAD"},download:{type:"unicode",value:"foo"},send_to_socket:{type:"unicode",
value:"bar"}}};const valueWithUnsetFields={type:"FooType",value:{}};it("excludes fields not pointed by set union field value",()=>{const items=buildUnionItems(valueWithSetFields,descriptor);for(let i=0;i<items.length;++i)expect(items[i].key).not.toBe("send_to_socket")});it("excludes fields not pointed by default union field value",()=>{const items=buildUnionItems(valueWithUnsetFields,descriptor);for(let i=0;i<items.length;++i)expect(items[i].key).not.toBe("download")});it("includes union field when it's set",
()=>{const items=buildUnionItems(valueWithSetFields,descriptor);expect(items[0]["key"]).toBe("action_type");expect(items[0]["value"]["value"]).toBe("DOWNLOAD")});it("includes union field value when it's set",()=>{const items=buildUnionItems(valueWithSetFields,descriptor);expect(items[1]["key"]).toBe("download");expect(items[1]["value"]["value"]).toBe("foo")});it("includes union field default when it's not set",()=>{const items=buildUnionItems(valueWithUnsetFields,descriptor);expect(items[0]["key"]).toBe("action_type");
expect(items[0]["value"]["value"]).toBe("SEND_TO_SOCKET")});it("includes union field value default when it's not set",()=>{const items=buildUnionItems(valueWithUnsetFields,descriptor);expect(items[1]["key"]).toBe("send_to_socket");expect(items[1]["value"]["value"]).toBe("defaultBar")})});describe("buildNonUnionItems()",()=>{const descriptor={fields:[{name:"foo",default:{type:"unicode",value:"defaultFoo"}},{name:"bar",default:{type:"unicode",value:"defaultBar"}}]};const value={type:"Struct",value:{foo:{type:"unicode",
value:"theFoo"}}};it("includes set fields only",()=>{const items=buildNonUnionItems(value,descriptor);expect(items.length).toBe(1);expect(items[0]["key"]).toBe("foo");expect(items[0]["value"]["value"]).toBe("theFoo")})});describe("buildItems()",()=>{it("builds items for a non-union-type value",()=>{const descriptor={fields:[{name:"foo"}]};const value={type:"Struct",value:{foo:{type:"unicode",value:"theFoo"}}};const items=buildItems(value,descriptor);expect(items.length).toBe(1);expect(items[0]["key"]).toBe("foo");
expect(items[0]["value"]["value"]).toBe("theFoo")});it("builds items for a union-type value",()=>{const descriptor={union_field:"action_type",fields:[{name:"action_type"},{name:"send_to_socket"}]};const valueWithSetFields={type:"FooType",value:{action_type:{type:"unicode",value:"SEND_TO_SOCKET"},send_to_socket:{type:"unicode",value:"bar"}}};const items=buildItems(valueWithSetFields,descriptor);expect(items[0]["key"]).toBe("action_type");expect(items[0]["value"]["value"]).toBe("SEND_TO_SOCKET");expect(items[1]["key"]).toBe("send_to_socket");
expect(items[1]["value"]["value"]).toBe("bar")})});let $compile;let $q;let $rootScope;let grrReflectionService;beforeEach(module("/static/angular-components/semantic/semantic-proto.html"));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));stubDirective("grrSemanticValue");beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrReflectionService=$injector.get("grrReflectionService");spyOn(grrReflectionService,
"getRDFValueDescriptor")}));const renderTestTemplate=(value,descriptors)=>{$rootScope.value=value;if(descriptors)grrReflectionService.getRDFValueDescriptor.and.callFake((typeName)=>{const deferred=$q.defer();deferred.resolve(descriptors[typeName]);return deferred.promise});const template='<grr-semantic-proto value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('renders only after the "value" binding is set',()=>{const element=renderTestTemplate(undefined,
{"Struct":{fields:[{name:"foo"}]}});expect(element.find('td:contains("foo")').length).toBe(0);$rootScope.value={type:"Struct",value:{foo:{type:"unicode",value:"theFoo"}}};$rootScope.$apply();expect(element.find('td:contains("foo")').length).toBe(1)});it('"value" binding is effectively a one-time binding',()=>{const value={type:"Struct",value:{foo:{type:"unicode",value:"theFoo"}}};const element=renderTestTemplate(value,{"Struct":{fields:[{name:"foo",name:"bar"}]}});expect(element.find('td:contains("bar")').length).toBe(0);
const newValue=angular.copy(value);newValue["value"]["bar"]={type:"unicode",value:"theBar"};$rootScope.value=newValue;$rootScope.$apply();expect(element.find('td:contains("bar")').length).toBe(0)});describe("with non-union-type value",()=>{it("does not show anything when value is empty",()=>{const element=renderTestTemplate(null);expect(element.text().trim()).toBe("")});it("respects fields order",()=>{let element=renderTestTemplate({type:"RDFProtoStruct",value:{client_id:{type:"unicode",value:"client_id"},
system_info:{type:"unicode",value:"system_info"},client_info:{type:"unicode",value:"client_info"}}},{"unicode":{},"RDFProtoStruct":{fields:[{name:"client_id"},{name:"system_info"},{name:"client_info"}]}});expect($("tr:nth(0)",element).text()).toContain("client_id");expect($("tr:nth(1)",element).text()).toContain("system_info");expect($("tr:nth(2)",element).text()).toContain("client_info");element=renderTestTemplate({type:"RDFProtoStruct",value:{client_id:{type:"unicode",value:"client_id"},system_info:{type:"unicode",
value:"system_info"},client_info:{type:"unicode",value:"client_info"}}},{"RDFProtoStruct":{fields:[{name:"client_info"},{name:"system_info"},{name:"client_id"}]}});expect($("tr:nth(0)",element).text()).toContain("client_info");expect($("tr:nth(1)",element).text()).toContain("system_info");expect($("tr:nth(2)",element).text()).toContain("client_id")})});describe("with union-type values",()=>{const valueWithSetValues={type:"RDFProtoStruct",value:{action_type:{type:"unicode",value:"SEND_TO_SOCKET"},
download:{type:"unicode",value:"foo"},send_to_socket:{type:"unicode",value:"bar"}}};const valueWithUnsetValues={type:"RDFProtoStruct",value:{}};const descriptors={"unicode":{},"RDFProtoStruct":{union_field:"action_type",fields:[{name:"action_type",default:{type:"unicode",value:"DOWNLOAD"}},{name:"download",default:{type:"unicode",value:"foo"}},{name:"send_to_socket",default:{type:"unicode",value:"bar"}}]}};it("doesn't show inactive union fields",()=>{const element=renderTestTemplate(valueWithSetValues,
descriptors);expect($("tr",element).length).toBe(2);expect($("tr:nth(0)",element).text()).not.toContain("download");expect($("tr:nth(1)",element).text()).not.toContain("download")});it("shows action type when explicitly set",()=>{const element=renderTestTemplate(valueWithSetValues,descriptors);expect($("tr:nth(0)",element).text()).toContain("action_type")});it("shows active union field when explicitly set",()=>{const element=renderTestTemplate(valueWithSetValues,descriptors);expect($("tr:nth(1)",
element).text()).toContain("send_to_socket")});it("shows action type when not explicitly set",()=>{const element=renderTestTemplate(valueWithUnsetValues,descriptors);expect($("tr:nth(0)",element).text()).toContain("action_type")});it("shows active union field when not explicitly set",()=>{const element=renderTestTemplate(valueWithUnsetValues,descriptors);expect($("tr:nth(1)",element).text()).toContain("download")})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.semanticProtosDiffDirectiveTest");goog.setTestOnly();const {diffAnnotate}=goog.require("grrUi.semantic.semanticProtosDiffDirective");describe("grrSemanticProtosDiff directive",()=>{describe("diffAnnotate()",()=>{it("does nothing for 2 plain equal data structures",()=>{const value={type:"Foo",value:{a:{type:"RDFString",value:"foo"},b:{type:"RDFInteger",value:42}}};const originalValue=angular.copy(value);const newValue=angular.copy(value);
diffAnnotate(originalValue,newValue);expect(originalValue).toEqual(value);expect(newValue).toEqual(value)});it("marks changed primitive attribute as changed",()=>{const originalValue={type:"Foo",value:{a:{type:"RDFString",value:"foo"}}};const newValue={type:"Foo",value:{a:{type:"RDFString",value:"bar"}}};diffAnnotate(originalValue,newValue);expect(originalValue).toEqual({type:"Foo",value:{a:{type:"RDFString",value:"foo",_diff:"changed"}}});expect(newValue).toEqual({type:"Foo",value:{a:{type:"RDFString",
value:"bar",_diff:"changed"}}})});it("marks primitive attribute as changed on type change",()=>{const originalValue={type:"Foo",value:{a:{type:"RDFString",value:"foo"}}};const newValue={type:"Foo",value:{a:{type:"ClientURN",value:"foo"}}};diffAnnotate(originalValue,newValue);expect(originalValue).toEqual({type:"Foo",value:{a:{type:"RDFString",value:"foo",_diff:"changed"}}});expect(newValue).toEqual({type:"Foo",value:{a:{type:"ClientURN",value:"foo",_diff:"changed"}}})});it("marks added primitive attribute as added",
()=>{const originalValue={type:"Foo",value:{a:{type:"RDFString",value:"foo"}}};const newValue={type:"Foo",value:{a:{type:"RDFString",value:"foo"},b:{type:"RDFString",value:"bar"}}};diffAnnotate(originalValue,newValue);expect(originalValue).toEqual({type:"Foo",value:{a:{type:"RDFString",value:"foo"}}});expect(newValue).toEqual({type:"Foo",value:{a:{type:"RDFString",value:"foo"},b:{type:"RDFString",value:"bar",_diff:"added"}}})});it("marks removed primitive attribute as removed",()=>{const originalValue=
{type:"Foo",value:{a:{type:"RDFString",value:"foo"},b:{type:"RDFString",value:"bar"}}};const newValue={type:"Foo",value:{a:{type:"RDFString",value:"foo"}}};diffAnnotate(originalValue,newValue);expect(originalValue).toEqual({type:"Foo",value:{a:{type:"RDFString",value:"foo"},b:{type:"RDFString",value:"bar",_diff:"removed"}}});expect(newValue).toEqual({type:"Foo",value:{a:{type:"RDFString",value:"foo"}}})});it("marks added and removed primitive attributes in the same value",()=>{const originalValue=
{type:"Foo",value:{a:{type:"RDFString",value:"foo"},b:{type:"RDFString",value:"bar"}}};const newValue={type:"Foo",value:{a:{type:"RDFString",value:"foo"},c:{type:"RDFString",value:"aha"}}};diffAnnotate(originalValue,newValue);expect(originalValue).toEqual({type:"Foo",value:{a:{type:"RDFString",value:"foo"},b:{type:"RDFString",value:"bar",_diff:"removed"}}});expect(newValue).toEqual({type:"Foo",value:{a:{type:"RDFString",value:"foo"},c:{type:"RDFString",value:"aha",_diff:"added"}}})});it("marks primitive item added to a list as added",
()=>{const originalValue=[{type:"RDFString",value:"foo"}];const newValue=[{type:"RDFString",value:"foo"},{type:"RDFString",value:"bar"}];diffAnnotate(originalValue,newValue);expect(originalValue).toEqual([{type:"RDFString",value:"foo"}]);expect(newValue).toEqual([{type:"RDFString",value:"foo"},{type:"RDFString",value:"bar",_diff:"added"}])});it("marks primitive item removed from a list as removed",()=>{const originalValue=[{type:"RDFString",value:"foo"},{type:"RDFString",value:"bar"}];const newValue=
[{type:"RDFString",value:"foo"}];diffAnnotate(originalValue,newValue);expect(originalValue).toEqual([{type:"RDFString",value:"foo"},{type:"RDFString",value:"bar",_diff:"removed"}]);expect(newValue).toEqual([{type:"RDFString",value:"foo"}])});it("marks changed list item as added and removed",()=>{const originalValue=[{type:"RDFString",value:"foo"}];const newValue=[{type:"RDFString",value:"bar"}];diffAnnotate(originalValue,newValue);expect(originalValue).toEqual([{type:"RDFString",value:"foo",_diff:"removed"}]);
expect(newValue).toEqual([{type:"RDFString",value:"bar",_diff:"added"}])});it("treats lists as unchanged if the order of items changed",()=>{const originalValue=[{type:"RDFString",value:"foo"},{type:"RDFString",value:"bar"}];const savedOriginalValue=angular.copy(originalValue);const newValue=[{type:"RDFString",value:"bar"},{type:"RDFString",value:"foo"}];const savedNewValue=angular.copy(newValue);diffAnnotate(originalValue,newValue);expect(originalValue).toEqual(savedOriginalValue);expect(newValue).toEqual(savedNewValue)});
it("treats lists as unchanged if duplicate items were added",()=>{const originalValue=[{type:"RDFString",value:"foo"}];const savedOriginalValue=angular.copy(originalValue);const newValue=[{type:"RDFString",value:"foo"},{type:"RDFString",value:"foo"}];const savedNewValue=angular.copy(newValue);diffAnnotate(originalValue,newValue);expect(originalValue).toEqual(savedOriginalValue);expect(newValue).toEqual(savedNewValue)})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.semanticValueDirectiveTest");goog.setTestOnly();const {clearCaches,getCachedSingleValueTemplate}=goog.require("grrUi.semantic.semanticValueDirective");const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("semantic value directive",()=>{let $compile;let $q;let $rootScope;let grrSemanticValueDirectivesRegistryService;let grrReflectionService;beforeEach(module(semanticModule.name));
beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{clearCaches();$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrSemanticValueDirectivesRegistryService=$injector.get("grrSemanticValueDirectivesRegistryService");grrReflectionService=$injector.get("grrReflectionService");grrReflectionService.getRDFValueDescriptor=(valueType)=>{const deferred=$q.defer();deferred.resolve({name:valueType,mro:[valueType]});return deferred.promise}}));
const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-semantic-value value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("does not show anything when value is null",()=>{const element=renderTestTemplate(null);expect(element.text().trim()).toBe("")});it("does not show anything when value is undefined",()=>{const element=renderTestTemplate(undefined);expect(element.text().trim()).toBe("")});it("renders plain string values",()=>
{const element=renderTestTemplate("foobar");expect(element.text().trim()).toBe("foobar")});it("renders plain integer values",()=>{const element=renderTestTemplate(42);expect(element.text().trim()).toBe("42")});it("renders list of plain string values",()=>{const element=renderTestTemplate(["elem1","elem2","elem3"]);expect(element.text().trim()).toBe("elem1 elem2 elem3")});it("renders list of plain integer values",()=>{const element=renderTestTemplate([41,42,43]);expect(element.text().trim()).toBe("41 42 43")});
it("renders richly typed value with a registered directive",()=>{const directiveMock={directive_name:"theTestDirective"};grrSemanticValueDirectivesRegistryService.registerDirective("NonExistentType",directiveMock);const element=renderTestTemplate({type:"NonExistentType",value:42});expect($("the-test-directive",element).length).toBe(1);expect($('the-test-directive[value="::value"]',element).length).toBe(1)});it("renders list of typed values with registered directives",()=>{const directiveMock1={directive_name:"theTestDirective1"};
grrSemanticValueDirectivesRegistryService.registerDirective("NonExistentType1",directiveMock1);const directiveMock2={directive_name:"theTestDirective2"};grrSemanticValueDirectivesRegistryService.registerDirective("NonExistentType2",directiveMock2);const directiveMock3={directive_name:"theTestDirective3"};grrSemanticValueDirectivesRegistryService.registerDirective("NonExistentType3",directiveMock3);const element=renderTestTemplate([{type:"NonExistentType1",value:41},{type:"NonExistentType2",value:42},
{type:"NonExistentType3",value:43}]);expect($("the-test-directive1",element).length).toBe(1);expect($("the-test-directive2",element).length).toBe(1);expect($("the-test-directive3",element).length).toBe(1)});it("renders typed values as strings when there's no handler",()=>{const element=renderTestTemplate({type:"NonExistentType",value:42});expect(element.text().trim()).toBe("42")});it("respects type override done with grr-semantic-value-registry-override",()=>{const directiveMock={directive_name:"theTestDirective"};
grrSemanticValueDirectivesRegistryService.registerDirective("SomeType",directiveMock);const overrideDirectiveMock={directive_name:"theTestDirectiveOverride"};$rootScope.override=overrideDirectiveMock;$rootScope.value={type:"SomeType",value:42};const template="<grr-semantic-value-registry-override "+"map=\"{'SomeType': override}\">"+'<grr-semantic-value value="value"></grr-semantic-value>'+"</grr-semantic-value-registry-override>";const element=$compile(template)($rootScope);$rootScope.$apply();expect($("the-test-directive-override",
element).length).toBe(1)});it("respects the override even if an RDF type was rendered once before",()=>{const directiveMock={directive_name:"theTestDirective"};grrSemanticValueDirectivesRegistryService.registerDirective("SomeType",directiveMock);let element=renderTestTemplate({type:"SomeType",value:42});expect($("the-test-directive",element).length).toBe(1);const overrideDirectiveMock={directive_name:"theTestDirectiveOverride"};$rootScope.override=overrideDirectiveMock;const template="<grr-semantic-value-registry-override "+
"map=\"{'SomeType': override}\">"+'<grr-semantic-value value="value"></grr-semantic-value>'+"</grr-semantic-value-registry-override>";element=$compile(template)($rootScope);$rootScope.$apply();expect($("the-test-directive-override",element).length).toBe(1)});it("caches templates for overrides using unique keys",()=>{const directiveMock={directive_name:"theTestDirective"};grrSemanticValueDirectivesRegistryService.registerDirective("SomeType",directiveMock);let element=renderTestTemplate({type:"SomeType",
value:42});expect($("the-test-directive",element).length).toBe(1);const overrideDirectiveMock={directive_name:"theTestDirectiveOverride"};$rootScope.override=overrideDirectiveMock;const template="<grr-semantic-value-registry-override "+"map=\"{'SomeType': override, 'AnotherType': override}\">"+'<grr-semantic-value value="value"></grr-semantic-value>'+"</grr-semantic-value-registry-override>";element=$compile(template)($rootScope);$rootScope.$apply();expect(getCachedSingleValueTemplate("SomeType")).toBeDefined();
expect(getCachedSingleValueTemplate("SomeType:AnotherType_theTestDirectiveOverride:"+"SomeType_theTestDirectiveOverride")).toBeDefined()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.semanticVersionedProtoDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,stubDirective,testsModule}=goog.require("grrUi.tests");const {semanticModule}=goog.require("grrUi.semantic.semantic");describe("semantic versioned proto directive",()=>{let $compile;let $q;let $rootScope;let grrReflectionService;beforeEach(module("/static/angular-components/semantic/"+"semantic-versioned-proto.html"));beforeEach(module(semanticModule.name));
beforeEach(module(testsModule.name));stubDirective("grrSemanticValue");beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrReflectionService=$injector.get("grrReflectionService");const deferred=$q.defer();deferred.resolve({"TheType":{kind:"struct",fields:[{name:"field",type:"TheType"},{name:"foo",type:"RDFString"}],default:{}},"RDFString":{kind:"primitive",default:""}});grrReflectionService.getRDFValueDescriptor=jasmine.createSpy("getRDFValueDescriptor").and.returnValue(deferred.promise)}));
const renderTestTemplate=(value,callback,depth)=>{$rootScope.value=value;$rootScope.callback=callback;$rootScope.depth=depth;const template="<grr-semantic-versioned-proto "+'value="value" history-depth="depth" '+'on-field-click="callback(fieldPath)" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};const oneLevelValue={type:"TheType",value:{foo:{type:"RDFString",value:"blah"}}};const twoLevelValue={type:"TheType",value:{field:{type:"TheType",value:{foo:{type:"RDFString",
value:"bar"}}},foo:{type:"RDFString",value:"blah"}}};it('renders only after the "value" binding is set',()=>{const element=renderTestTemplate(undefined,()=>{},1);expect(element.find(".proto_history button").length).toBe(0);$rootScope.value=oneLevelValue;$rootScope.$apply();expect(element.find(".proto_history button").length).toBe(1)});it('"value" binding is effectively a one-time binding',()=>{const element=renderTestTemplate(oneLevelValue,()=>{},1);expect(element.find(".proto_history button").length).toBe(1);
const newValue=angular.copy(oneLevelValue);newValue["value"]={};$rootScope.value=newValue;$rootScope.$apply();expect(element.find(".proto_history button").length).toBe(1)});it("adds history button to 1st-level field",()=>{const element=renderTestTemplate(oneLevelValue,()=>{},1);expect(element.find(".proto_history button").length).toBe(1)});it("passes a correct field path for a 1st-level field",()=>{const callback=jasmine.createSpy();const element=renderTestTemplate(oneLevelValue,callback,1);browserTriggerEvent(element.find(".proto_history button"),
"click");expect(callback.calls.count()).toBe(1);expect(callback.calls.first().args).toEqual(["foo"])});it("adds history button to 2nd-level field",()=>{const element=renderTestTemplate(twoLevelValue,()=>{},2);expect(element.find("td.proto_value .proto_history button").length).toBe(1)});it("passes a correct field path for a 2nd-level field",()=>{const callback=jasmine.createSpy();const element=renderTestTemplate(twoLevelValue,callback,2);browserTriggerEvent(element.find("td.proto_value .proto_history button"),
"click");expect(callback.calls.count()).toBe(1);expect(callback.calls.first().args).toEqual(["field.foo"])});it("does not add history button outside history-depth",()=>{const element=renderTestTemplate(twoLevelValue,()=>{},1);expect(element.find("td.proto_value .proto_history button").length).toBe(0)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.statExtFlagsLinuxDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");const HTML_TEMPLATE_PATH="/static/angular-components/semantic/stat-ext-flags-linux.html";describe("stat ext-flags for Linux directive",()=>{let $compile;let $rootScope;beforeEach(module(HTML_TEMPLATE_PATH));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const render=(value)=>{$rootScope.value=value;const template='<grr-stat-ext-flags-linux value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("handles empty values",()=>{const element=render(undefined);expect(element.text().trim()).toBe("none")});it("handles incorrect input type",()=>{const element=render({value:"foo"});expect(element.text().trim()).toBe("malformed")});
it("handles negative values",()=>{const element=render({value:-1});expect(element.text().trim()).toBe("malformed")});it("handles non-integer values",()=>{const element=render({value:5.13});expect(element.text().trim()).toBe("malformed")});it("indicates files without special flags",()=>{const element=render({value:0});expect(element.text().replace(/\s/g,"")).toBe("--------------------")});it("indicates regular files",()=>{const element=render({value:524288});expect(element.text().replace(/\s/g,"")).toBe("-----------------e--")});
it("indicates immutable files",()=>{const element=render({value:524304});expect(element.text().replace(/\s/g,"")).toBe("----i------------e--")});it("indicates files non-dumpable support",()=>{const element=render({value:524352});expect(element.text().replace(/\s/g,"")).toBe("------d----------e--")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.statExtFlagsOsxDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");const HTML_TEMPLATE_URL="/static/angular-components/semantic/stat-ext-flags-osx.html";describe("stat ext-flags for Mac directive",()=>{let $compile;let $rootScope;beforeEach(module(HTML_TEMPLATE_URL));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const render=(value)=>{$rootScope.value=value;const template='<grr-stat-ext-flags-osx value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("handles empty values",()=>{const element=render(undefined);expect(element.text().trim()).toBe("none")});it("handles incorrect input type",()=>{const element=render({value:"foo"});expect(element.text().trim()).toBe("malformed")});
it("handles negative values",()=>{const element=render({vaue:-42});expect(element.text().trim()).toBe("malformed")});it("handles non-integer values",()=>{const element=render({value:3.14});expect(element.text().trim()).toBe("malformed")});it("indicates regular files",()=>{const element=render({value:0});expect(element.text().trim()).toBe("")});it("indicates immutable files",()=>{const element=render({value:2});expect(element.text().trim()).toBe("uimmutable")});it("indicates files with nodump flag",
()=>{const element=render({value:1});expect(element.text().trim()).toBe("nodump")});it("indicates files with multiple flags",()=>{const element=render({value:196616});const text=element.text().trim();expect(text).toContain("opaque");expect(text).toContain("archived");expect(text).toContain("simmutable")});it("ignores flags with unknown keywords",()=>{const element=render({value:32});expect(element.text().trim()).toBe("")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.statModeDirectiveTest");goog.setTestOnly();const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("stat mode directive",()=>{let $compile;let $rootScope;beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const render=(value)=>
{$rootScope.value=value;const template='<grr-stat-mode value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("does not show anything when value is null",()=>{const element=render(null);expect(element.text().trim()).toBe("-")});it("does not show anything when value is empty",()=>{const element=render({});expect(element.text().trim()).toBe("-")});it("indicates regular files",()=>{const element=render({value:33188});expect(element.text().trim()).toBe("-rw-r--r--")});
it("indicates directories",()=>{const element=render({value:16832});expect(element.text().trim()).toBe("drwx------")});it("indicates character devices",()=>{const element=render({value:8592});expect(element.text().trim()).toBe("crw--w----")});it("indicates symbolic links",()=>{const element=render({value:41325});expect(element.text().trim()).toBe("lr-xr-xr-x")});it("indicates block devices",()=>{const element=render({value:24960});expect(element.text().trim()).toBe("brw-------")});it("indicates FIFO pipes",
()=>{const element=render({value:4516});expect(element.text().trim()).toBe("prw-r--r--")});it("indicates sockets",()=>{const element=render({value:50668});expect(element.text().trim()).toBe("srwxr-sr--")});it("considers the S_ISUID flag",()=>{let element=render({value:35300});expect(element.text().trim()).toBe("-rwsr--r--");element=render({value:35236});expect(element.text().trim()).toBe("-rwSr--r--")});it("considers the S_ISGID flag",()=>{let element=render({value:36332});expect(element.text().trim()).toBe("-rwsr-sr--");
element=render({value:36324});expect(element.text().trim()).toBe("-rwsr-Sr--")});it("considers the S_ISVTX flag",()=>{let element=render({value:35812});expect(element.text().trim()).toBe("-rwsr--r-T");element=render({value:35813});expect(element.text().trim()).toBe("-rwsr--r-t")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.timestampDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {semanticModule}=goog.require("grrUi.semantic.semantic");describe("timestamp directive",()=>{const MICRO_IN_MILLI=1E3;const MILLI_IN_UNIT=1E3;const SECONDS=MICRO_IN_MILLI*MILLI_IN_UNIT;const MINUTES=60*SECONDS;let $compile;let $rootScope;beforeEach(module("/static/angular-components/semantic/timestamp.html"));
beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-timestamp value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("does not show anything when value is undefined",()=>{const element=renderTestTemplate(undefined);expect(element.text().trim()).toBe("")});
it("does not show anything when value is null",()=>{const element=renderTestTemplate(null);expect(element.text().trim()).toBe("-")});it('shows "-" when value is 0',()=>{const element=renderTestTemplate(0);expect(element.text().trim()).toBe("-")});it("shows integer value",()=>{const element=renderTestTemplate(42*SECONDS);expect(element.text()).toContain("1970-01-01 00:00:42")});it("shows value with type information",()=>{const timestamp={"mro":["RDFDatetime","RDFInteger","RDFString","RDFBytes","RDFValue",
"object"],"value":42*SECONDS,"age":0,"type":"RDFDatetime"};const element=renderTestTemplate(timestamp);expect(element.text()).toContain("1970-01-01 00:00:42")});it("includes a human-readable diff when hovered",()=>{function assertTimestampRendersDiff(timestamp,diff){const element=renderTestTemplate(timestamp);const span=$(element).find("> span");browserTriggerEvent($(element).find("> span"),"mouseenter");expect(span.attr("title")).toContain(diff)}const now=(new Date-0)*MICRO_IN_MILLI;assertTimestampRendersDiff(now+
5*SECONDS,"now");assertTimestampRendersDiff(now-5*SECONDS,"now");assertTimestampRendersDiff(now-2*MINUTES-2*SECONDS,"2 minutes ago")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.timestampSecondsDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {semanticModule}=goog.require("grrUi.semantic.semantic");describe("timestamp seconds directive",()=>{const MILLI_IN_UNIT=1E3;let $compile;let $rootScope;beforeEach(module("/static/angular-components/semantic/timestamp.html"));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-timestamp-seconds value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("does not show anything when value is undefined",()=>{const element=renderTestTemplate(undefined);expect(element.text().trim()).toBe("")});it("does not show anything when value is null",()=>{const element=
renderTestTemplate(null);expect(element.text().trim()).toBe("-")});it('shows "-" when value is 0',()=>{const element=renderTestTemplate(0);expect(element.text().trim()).toBe("-")});it("shows integer value",()=>{const element=renderTestTemplate(42);expect(element.text()).toContain("1970-01-01 00:00:42")});it("shows value with type information",()=>{const timestamp={"mro":["RDFDatetimeSeconds","RDFDatetime","RDFInteger","RDFString","RDFBytes","RDFValue","object"],"value":42,"age":0,"type":"RDFDatetimeSeconds"};
const element=renderTestTemplate(timestamp);expect(element.text()).toContain("1970-01-01 00:00:42")});it("includes a human-readable diff when hovered",()=>{function assertTimestampRendersDiff(timestamp,diff){const element=renderTestTemplate(timestamp);const span=$(element).find("span");browserTriggerEvent($(element).find("span"),"mouseenter");expect(span.attr("title")).toContain(diff)}const now=(new Date-0)/MILLI_IN_UNIT;assertTimestampRendersDiff(now,"now")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.urnDirectiveTest");goog.setTestOnly();const aff4UrnToUrl=goog.require("grrUi.routing.aff4UrnToUrl");const {semanticModule}=goog.require("grrUi.semantic.semantic");const {testsModule}=goog.require("grrUi.tests");describe("urn directive",()=>{let $compile;let $rootScope;let grrRoutingService;beforeEach(module("/static/angular-components/semantic/urn.html"));beforeEach(module(semanticModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrRoutingService=$injector.get("grrRoutingService")}));const renderTestTemplate=(value)=>{$rootScope.value=value;const template='<grr-urn value="value" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("does not show anything when value is empty",()=>{const element=renderTestTemplate(null);expect(element.text().trim()).toBe("")});it("shows plain string if grrRoutingService can't convert URN",
()=>{spyOn(aff4UrnToUrl,"aff4UrnToUrl").and.returnValue(undefined);const element=renderTestTemplate("aff4:/foo/bar");expect(element.text().trim()).toBe("aff4:/foo/bar");expect(element.find("a").length).toBe(0)});it("shows a link if grrRoutingService can convert URN",()=>{spyOn(aff4UrnToUrl,"aff4UrnToUrl").and.returnValue({state:"someState",params:{}});spyOn(grrRoutingService,"href").and.returnValue("/some/real/link");const element=renderTestTemplate("aff4:/C.0001000200030004/fs/os/foo/bar");expect(element.find("a").text().trim()).toBe("aff4:/C.0001000200030004/fs/os/foo/bar");
expect(element.find("a").attr("href")).toBe("/some/real/link")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.core.clientWarningsDirectiveTest");goog.setTestOnly();const {sidebarModule}=goog.require("grrUi.sidebar.sidebar");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("grr-client-warnings directive",()=>{let $q;let $compile;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/sidebar/client-warnings.html"));beforeEach(module(sidebarModule.name));beforeEach(module(testsModule.name));stubDirective("grrMarkdown");
beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=(configOption,client)=>{$rootScope.client=client||{type:"ApiClient",value:{labels:[{type:"ApiClientLabel",value:{name:{type:"RDFString",value:"foo"}}},{type:"ApiClientLabel",value:{name:{type:"RDFString",value:"bar"}}}]}};spyOn(grrApiService,"getV2Cached").and.callFake(()=>{const deferred=$q.defer();
const promise=deferred.promise;deferred.resolve({data:configOption});return promise});const template='<grr-client-warnings client="client" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("does not render anything on empty config option",()=>{const element=renderTestTemplate({});expect(element.find("grr-markdown").length).toBe(0)});it("does not render anything on empty rules list",()=>{const element=renderTestTemplate({value:{rules:[]}});expect(element.find("grr-markdown").length).toBe(0)});
it("shows a single warning when one rule matches a single label",()=>{const element=renderTestTemplate({value:{rules:[{withLabels:["foo"],message:"blah"}]}});expect(element.find("grr-markdown").length).toBe(1);const markdownElement=element.find("grr-markdown:nth(0)");const source=markdownElement.scope().$eval(markdownElement.attr("source"));expect(source).toBe("blah")});it("matches labels in a case-insensitive way",()=>{const element=renderTestTemplate({value:{rules:[{withLabels:["FOO"],message:"blah"}]}});
expect(element.find("grr-markdown").length).toBe(1);const markdownElement=element.find("grr-markdown:nth(0)");const source=markdownElement.scope().$eval(markdownElement.attr("source"));expect(source).toBe("blah")});it("shows a single warning when one rule matches two labels",()=>{const element=renderTestTemplate({value:{rules:[{withLabels:["foo","bar"],message:"blah"}]}});expect(element.find("grr-markdown").length).toBe(1);const markdownElement=element.find("grr-markdown:nth(0)");const source=markdownElement.scope().$eval(markdownElement.attr("source"));
expect(source).toBe("blah")});it("shows two warnings when two rules match",()=>{const element=renderTestTemplate({value:{rules:[{withLabels:["foo"],message:"blah1"},{withLabels:["bar"],message:"blah2"}]}});expect(element.find("grr-markdown").length).toBe(2);let markdownElement=element.find("grr-markdown:nth(0)");let source=markdownElement.scope().$eval(markdownElement.attr("source"));expect(source).toBe("blah1");markdownElement=element.find("grr-markdown:nth(1)");source=markdownElement.scope().$eval(markdownElement.attr("source"));
expect(source).toBe("blah2")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.stats.auditChartDirectiveTest");goog.setTestOnly();const {statsModule}=goog.require("grrUi.stats.stats");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("audit chart directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/stats/audit-chart.html"));beforeEach(module(statsModule.name));beforeEach(module(testsModule.name));stubDirective("grrSemanticValue");beforeEach(inject(($injector)=>
{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(typedData)=>{$rootScope.typedData=typedData;const template='<grr-audit-chart typed-data="typedData">'+"</grr-audit-chart>";const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing if the given data is undefined",()=>{const element=renderTestTemplate(undefined);expect(element.find("th").length).toBe(0);expect(element.find("td").length).toBe(0)});it("shows the given data",
()=>{const element=renderTestTemplate({"value":{"audit_chart":{"value":{"rows":[{"value":{"action":{"value":"HUNT_CREATED","type":"EnumNamedValue"},"user":{"value":"GRRWorker","type":"unicode"},"id":{"value":123,"type":"long"},"timestamp":{"value":1485174411E6,"type":"RDFDatetime"},"description":{"value":"Description of the hunt.","type":"unicode"},"flow_name":{"value":"Flow Foo.","type":"unicode"},"urn":{"value":"aff4:/hunts/H:12345678","type":"RDFURN"}},"type":"AuditEvent"},{"value":{"action":{"value":"HUNT_STARTED",
"type":"EnumNamedValue"},"user":{"value":"GRRWorker","type":"unicode"},"id":{"value":456,"type":"long"},"timestamp":{"value":1485174502E6,"type":"RDFDatetime"},"description":{"value":"Description of another hunt.","type":"unicode"},"urn":{"value":"aff4:/hunts/H:87654321","type":"RDFURN"}},"type":"AuditEvent"}],"used_fields":[{"value":"action","type":"unicode"},{"value":"description","type":"unicode"},{"value":"flow_name","type":"unicode"},{"value":"timestamp","type":"unicode"},{"value":"urn","type":"unicode"},
{"value":"user","type":"unicode"}]},"type":"ApiAuditChartReportData"},"representation_type":{"value":"AUDIT_CHART","type":"EnumNamedValue"}},"type":"ApiReportData"});const ths=element.find("th");expect(ths.length).toBe(6);expect(ths[0].innerText).toContain("Action");expect(ths[1].innerText).toContain("Description");expect(ths[2].innerText).toContain("Flow name");expect(ths[3].innerText).toContain("Timestamp");expect(ths[4].innerText).toContain("Urn");expect(ths[5].innerText).toContain("User");const tbodyTrs=
element.find("tbody tr");expect(tbodyTrs.length).toBe(2);const getCellValue=(td)=>{const semVal=$(td).find("grr-semantic-value");return semVal.scope().$eval(semVal.attr("value"))};const row0Tds=$(tbodyTrs[0]).find("td");expect(row0Tds.length).toBe(6);expect(getCellValue(row0Tds[0])).toEqual({"value":"HUNT_CREATED","type":"EnumNamedValue"});expect(getCellValue(row0Tds[1])).toEqual({"value":"Description of the hunt.","type":"unicode"});expect(getCellValue(row0Tds[2])).toEqual({"value":"Flow Foo.","type":"unicode"});
expect(getCellValue(row0Tds[3])).toEqual({"value":1485174411E6,"type":"RDFDatetime"});expect(getCellValue(row0Tds[4])).toEqual({"value":"aff4:/hunts/H:12345678","type":"RDFURN"});expect(getCellValue(row0Tds[5])).toEqual({"value":"GRRWorker","type":"unicode"});const row1Tds=$(tbodyTrs[1]).find("td");expect(row1Tds.length).toBe(6);expect(getCellValue(row1Tds[0])).toEqual({"value":"HUNT_STARTED","type":"EnumNamedValue"});expect(getCellValue(row1Tds[1])).toEqual({"value":"Description of another hunt.",
"type":"unicode"});expect(getCellValue(row1Tds[2])).toBe(undefined);expect(getCellValue(row1Tds[3])).toEqual({"value":1485174502E6,"type":"RDFDatetime"});expect(getCellValue(row1Tds[4])).toEqual({"value":"aff4:/hunts/H:87654321","type":"RDFURN"});expect(getCellValue(row1Tds[5])).toEqual({"value":"GRRWorker","type":"unicode"})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.stats.reportDirectiveTest");goog.setTestOnly();const {statsModule}=goog.require("grrUi.stats.stats");const {stripTypeInfo}=goog.require("grrUi.core.apiService");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("report directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;let grrTimeService;beforeEach(module("/static/angular-components/stats/report.html"));beforeEach(module(statsModule.name));beforeEach(module(testsModule.name));
stubDirective("grrFormClientLabel");stubDirective("grrFormTimerange");stubDirective("grrChart");beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService");grrTimeService=$injector.get("grrTimeService");let clock=grrTimeService.getCurrentTimeMs();grrTimeService.getCurrentTimeMs=()=>{clock+=42;return clock}}));const renderTestTemplate=(name)=>{$rootScope.name=name;const template='<grr-report name="name">'+
"</grr-report>";const element=$compile(template)($rootScope);$rootScope.$apply();return element};const mockGrrApiService=()=>{const deferredWork={};spyOn(grrApiService,"get").and.callFake((path)=>{const deferred=$q.defer();const promise=deferred.promise;if(path==="stats/reports"){const response={"reports":[{"type":"ApiReport","value":{"desc":{"type":"ApiReportDescriptor","value":{"name":{"type":"unicode","value":"FooReportPlugin"},"summary":{"type":"unicode","value":"Foo's summary."},"type":{"type":"EnumNamedValue",
"value":"FOO_TYPE"},"requires_time_range":{"type":"RDFBool","value":false},"title":{"type":"unicode","value":"Foo Report"}}}}},{"type":"ApiReport","value":{"desc":{"type":"ApiReportDescriptor","value":{"name":{"type":"unicode","value":"BarReportPlugin"},"summary":{"type":"unicode","value":"Bar's summary."},"type":{"type":"EnumNamedValue","value":"BAR_TYPE"},"requires_time_range":{"type":"RDFBool","value":false},"title":{"type":"unicode","value":"Bar Report"}}}}}]};deferred.resolve({data:response})}else{const response=
{data:{data:{value:{representation_type:{value:"STACK_CHART"},stack_chart:{value:{data:[{value:{label:path,points:[]}}]}}}}}};deferredWork[path].promise.then(()=>{deferred.resolve({data:response})})}return promise});return deferredWork};it("drops responses to old requests",()=>{const deferredWork=mockGrrApiService();deferredWork["stats/reports/FooReportPlugin"]=$q.defer();deferredWork["stats/reports/BarReportPlugin"]=$q.defer();const element=renderTestTemplate("FooReportPlugin");$rootScope.name="BarReportPlugin";
$rootScope.$apply();expect(element.find("grr-chart").length).toBe(0);deferredWork["stats/reports/FooReportPlugin"].resolve();$rootScope.$apply();expect(element.find("grr-chart").length).toBe(0);deferredWork["stats/reports/BarReportPlugin"].resolve();$rootScope.$apply();const chart=element.find("grr-chart");expect(chart.length).toBe(1);const attribute=chart.attr("typed-data");const typedData=chart.scope().$eval(attribute);const data=stripTypeInfo(typedData["data"]);expect(data["stack_chart"]["data"][0]["label"]).toBe("stats/reports/BarReportPlugin");
expect(JSON.stringify(typedData)).not.toContain("FooReportPlugin")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.stats.reportListingDirectiveTest");goog.setTestOnly();const {parseStatsReportsApiResponse}=goog.require("grrUi.stats.reportListingDirective");describe("stats.reportListingDirective.parseStatsReportsApiResponse",()=>{it("Parses the response into a jsTree-compatible format.",()=>{const reports=[{desc:{name:"FooReportPlugin",title:"Foos' Activity",type:"SERVER"}},{desc:{name:"BarReportPlugin",title:"Bars Reported Over Time",type:"SERVER"}},
{desc:{name:"BazReportPlugin",title:"Baz Statistics",type:"CLIENT"}}];const ret=parseStatsReportsApiResponse(reports);expect(ret).toEqual([{children:[{desc:{name:"FooReportPlugin",title:"Foos' Activity",type:"SERVER"},id:"FooReportPlugin",text:"Foos' Activity"},{desc:{name:"BarReportPlugin",title:"Bars Reported Over Time",type:"SERVER"},id:"BarReportPlugin",text:"Bars Reported Over Time"}],state:{disabled:true,opened:true},text:"Server"},{children:[{desc:{name:"BazReportPlugin",title:"Baz Statistics",
type:"CLIENT"},id:"BazReportPlugin",text:"Baz Statistics"}],state:{disabled:true,opened:true},text:"Client"}])})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.stats.serverLoadDirectiveTest");goog.setTestOnly();const {ServerLoadIndicatorService}=goog.require("grrUi.stats.serverLoadDirective");const {statsModule}=goog.require("grrUi.stats.stats");describe("server load indicator service",()=>{let $compile;let $q;let $rootScope;let grrApiServiceMock;beforeEach(module(statsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");
grrApiServiceMock={get:function(){}}}));describe("ratio health indicators",()=>{const getService=(numeratorPath,numeratorResponse,denominatorPath,denominatorResponse)=>{let service;inject(($injector)=>{service=$injector.instantiate(ServerLoadIndicatorService,{"$q":$q,"grrApiService":grrApiServiceMock})});const deferredNumerator=$q.defer();deferredNumerator.resolve(numeratorResponse);const deferredDenominator=$q.defer();deferredDenominator.resolve(denominatorResponse);spyOn(grrApiServiceMock,"get").and.callFake((path)=>
{if(path==="stats/store/FRONTEND/metrics/metric1")return deferredNumerator.promise;else if(path==="stats/store/FRONTEND/metrics/metric2")return deferredDenominator.promise;else throw new Error(`Unexpected path: ${path}`);});$rootScope.$apply();return service};it("sets unknown status when no data received",()=>{const service=getService("FRONTEND/metrics/metric1",{data:{metric_name:"metric1",data_points:[]}},"FRONTEND/metrics/metric2",{data:{metric_name:"metric2",data_points:[]}});const status=service.fetchRatioIndicator("FRONTEND",
"metric1","metric2",1.5,3);let resolvedStatus;status.then((value)=>{resolvedStatus=value});$rootScope.$apply();expect(resolvedStatus).toBeDefined();expect(resolvedStatus).toEqual("unknown")});it("sets unknown when denominator is zero",()=>{const service=getService("FRONTEND/metrics/metric1",{data:{metric_name:"metric1",data_points:[[0,1]]}},"FRONTEND/metrics/metric2",{data:{metric_name:"metric2",data_points:[[0,0]]}});const status=service.fetchRatioIndicator("FRONTEND","metric1","metric2",1.5,3);
let resolvedStatus;status.then((value)=>{resolvedStatus=value});$rootScope.$apply();expect(resolvedStatus).toBeDefined();expect(resolvedStatus).toEqual("unknown")});it("sets warning status when ratio level is above threshold",()=>{const service=getService("FRONTEND/metrics/metric1",{data:{metric_name:"metric1",data_points:[[0,4]]}},"FRONTEND/metrics/metric2",{data:{metric_name:"metric2",data_points:[[0,2]]}});const status=service.fetchRatioIndicator("FRONTEND","metric1","metric2",1.5,3);let resolvedStatus;
status.then((value)=>{resolvedStatus=value});$rootScope.$apply();expect(resolvedStatus).toBeDefined();expect(resolvedStatus).toEqual("warning")});it("sets warning status when mean ratio is above threshold",()=>{const service=getService("FRONTEND/metrics/metric1",{data:{metric_name:"metric1",data_points:[[0,3],[10,5]]}},"FRONTEND/metrics/metric2",{data:{metric_name:"metric2",data_points:[[0,1],[10,3]]}});const status=service.fetchRatioIndicator("FRONTEND","metric1","metric2",1.5,3);let resolvedStatus;
status.then((value)=>{resolvedStatus=value});$rootScope.$apply();expect(resolvedStatus).toBeDefined();expect(resolvedStatus).toEqual("warning")});it("sets danger status when ratio level is above threshold",()=>{const service=getService("FRONTEND/metrics/metric1",{data:{metric_name:"metric1",data_points:[[0,7]]}},"FRONTEND/metrics/metric2",{data:{metric_name:"metric2",data_points:[[0,2]]}});const status=service.fetchRatioIndicator("FRONTEND","metric1","metric2",1.5,3);let resolvedStatus;status.then((value)=>
{resolvedStatus=value});$rootScope.$apply();expect(resolvedStatus).toBeDefined();expect(resolvedStatus).toEqual("danger")});it("sets normal status when ratio level is below threshold",()=>{const service=getService("FRONTEND/metrics/metric1",{data:{metric_name:"metric1",data_points:[[0,2]]}},"FRONTEND/metrics/metric2",{data:{metric_name:"metric2",data_points:[[0,2]]}});const status=service.fetchRatioIndicator("FRONTEND","metric1","metric2",1.5,3);let resolvedStatus;status.then((value)=>{resolvedStatus=
value});$rootScope.$apply();expect(resolvedStatus).toBeDefined();expect(resolvedStatus).toEqual("normal")})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.user.approverInputDirectiveTest");goog.setTestOnly();const {testsModule}=goog.require("grrUi.tests");const {userModule}=goog.require("grrUi.user.user");describe("approver input",()=>{let $compile;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/user/approver-input.html"));beforeEach(module(userModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{const $q=$injector.get("$q");
$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService");const approverSuggestions=[{value:{username:{value:"sanchezmorty",type:"unicode"}},type:"ApproverSuggestion"},{value:{username:{value:"sanchezrick",type:"unicode"}},type:"ApproverSuggestion"},{value:{username:{value:"sanchezsummer",type:"unicode"}},type:"ApproverSuggestion"}];spyOn(grrApiService,"get").and.callFake((url,params)=>{const deferred=$q.defer();const suggestions=approverSuggestions.filter((sugg)=>
sugg.value.username.value.startsWith(params.username_query));deferred.resolve({data:{suggestions}});return deferred.promise})}));function renderTestTemplate(initialValue=""){const template='<grr-approver-input ng-model="value"/>';$rootScope.value=initialValue;const element=$compile(template)($rootScope);$rootScope.$apply();return element}function type(element,text){$("input",element).val(text).trigger("input").trigger("change")}it("renders a text input",()=>{const element=renderTestTemplate();expect($("input",
element).length).toBe(1)});it("calls API for username input",()=>{const element=renderTestTemplate();type(element,"sanchezsu");expect(grrApiService.get).toHaveBeenCalledWith("/users/approver-suggestions",{username_query:"sanchezsu"})});it("calls API for rightmost username",()=>{const element=renderTestTemplate();type(element,"foo,bar");expect(grrApiService.get).toHaveBeenCalledWith("/users/approver-suggestions",{username_query:"bar"});type(element,"bar,foo");expect(grrApiService.get).toHaveBeenCalledWith("/users/approver-suggestions",
{username_query:"foo"});type(element,"foo , bar , baz");expect(grrApiService.get).toHaveBeenCalledWith("/users/approver-suggestions",{username_query:"baz"})});it("shows autocomplete for single suggestion",()=>{const element=renderTestTemplate();type(element,"sanchezsu");expect($("[uib-typeahead-popup] li").length).toBe(1);expect($("[uib-typeahead-popup] li:eq(0)").text().trim()).toBe("sanchezsummer")});it("shows autocomplete for multiple suggestions",()=>{const element=renderTestTemplate();type(element,
"san");expect($("[uib-typeahead-popup] li").length).toBe(3);expect($("[uib-typeahead-popup] li:eq(0)").text().trim()).toBe("sanchezmorty");expect($("[uib-typeahead-popup] li:eq(1)").text().trim()).toBe("sanchezrick");expect($("[uib-typeahead-popup] li:eq(2)").text().trim()).toBe("sanchezsummer")});it("does not show previous usernames in autocomplete",()=>{const element=renderTestTemplate();type(element,"sanchezsummer, san");expect($("[uib-typeahead-popup] li").length).toBe(2);expect($("[uib-typeahead-popup] li:eq(0)").text().trim()).toBe("sanchezmorty");
expect($("[uib-typeahead-popup] li:eq(1)").text().trim()).toBe("sanchezrick")});it("does not show autocomplete for empty input",()=>{const element=renderTestTemplate();type(element,"");expect(grrApiService.get).not.toHaveBeenCalled();expect($("[uib-typeahead-popup] li").length).toBe(0)});it("does not show autocomplete for empty search",()=>{const element=renderTestTemplate();type(element,"sanchez, ");expect(grrApiService.get).not.toHaveBeenCalled();expect($("[uib-typeahead-popup] li").length).toBe(0)});
it("uses value from ng-model",()=>{const element=renderTestTemplate("foo");expect($("input",element).val()).toBe("foo")});it("correctly assigns ng-model",()=>{const element=renderTestTemplate();type(element,"sanchez, foo, ");expect(element.scope().value).toBe("sanchez, foo, ")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.user.userDesktopNotificationsDirectiveTest");goog.setTestOnly();const {UserNotificationButtonDirective}=goog.require("grrUi.user.userNotificationButtonDirective");const {testsModule}=goog.require("grrUi.tests");const {userModule}=goog.require("grrUi.user.user");describe("User desktop notifications directive",()=>{let $compile;let $interval;let $q;let $rootScope;let $location;let grrApiService;const FETCH_INTERVAL=UserNotificationButtonDirective.fetch_interval;
beforeEach(module(userModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$location=$injector.get("$location");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$interval=$injector.get("$interval");grrApiService=$injector.get("grrApiService");window.Notification=function(){this.close=()=>{}};spyOn(window,"Notification").and.callThrough()}));const render=()=>{const template="<grr-user-desktop-notifications />";const element=
$compile(template)($rootScope);$rootScope.$apply();return element};const mockApiServiceResponse=(value)=>{spyOn(grrApiService,"get").and.callFake(()=>{const deferred=$q.defer();deferred.resolve({data:{items:value}});return deferred.promise})};it("fetches a single pending notification and displays it as a desktop "+"notification",()=>{mockApiServiceResponse([{"type":"ApiNotification","value":{"is_pending":{"type":"RDFBool","value":true},"message":{"type":"unicode","value":"Host-0: <some message>"},
"reference":{"type":"ApiNotificationReference","value":{"client":{"type":"ApiNotificationClientReference","value":{"client_id":{"type":"ClientURN","value":"aff4:/C.1000000000000000"}}},"type":{"type":"EnumNamedValue","value":"CLIENT"}}},"timestamp":{"type":"RDFDatetime","value":42E6}}}]);render();$interval.flush(FETCH_INTERVAL);expect(grrApiService.get).toHaveBeenCalled();expect(Notification.calls.count()).toBe(1);expect(Notification).toHaveBeenCalledWith("GRR",{"body":"Host-0: <some message>","icon":"static/images/grr_logo_notification.png",
"tag":"GRR42000000"})});it("provides a relevant onclick callback for the desktop notification",()=>{mockApiServiceResponse([{"type":"ApiNotification","value":{"is_pending":{"type":"RDFBool","value":true},"message":{"type":"unicode","value":"Host-0: <some message>"},"reference":{"type":"ApiNotificationReference","value":{"client":{"type":"ApiNotificationClientReference","value":{"client_id":{"type":"ClientURN","value":"aff4:/C.1000000000000000"}}},"type":{"type":"EnumNamedValue","value":"CLIENT"}}},
"timestamp":{"type":"RDFDatetime","value":42E6}}}]);spyOn(grrApiService,"delete");spyOn($location,"path");render();$interval.flush(FETCH_INTERVAL);Notification.calls.mostRecent().object.onclick();expect(grrApiService.delete).toHaveBeenCalledWith("users/me/notifications/pending/42000000");expect($location.path).toHaveBeenCalledWith("clients/C.1000000000000000")});it("fetches pending notifications and displays the last two of them as "+"desktop notifications",()=>{mockApiServiceResponse([{"type":"ApiNotification",
"value":{"is_pending":{"type":"RDFBool","value":true},"message":{"type":"unicode","value":"Host-0: <another message>"},"reference":{"type":"ApiNotificationReference","value":{"type":{"type":"EnumNamedValue","value":"VFS"},"vfs":{"type":"ApiNotificationVfsReference","value":{"client_id":{"type":"ClientURN","value":"aff4:/C.1000000000000000"},"vfs_path":{"type":"RDFURN","value":"aff4:/C.1000000000000000"}}}}},"timestamp":{"type":"RDFDatetime","value":48E6}}},{"type":"ApiNotification","value":{"is_pending":{"type":"RDFBool",
"value":true},"message":{"type":"unicode","value":"Host-0: <some message>"},"reference":{"type":"ApiNotificationReference","value":{"client":{"type":"ApiNotificationClientReference","value":{"client_id":{"type":"ClientURN","value":"aff4:/C.1000000000000000"}}},"type":{"type":"EnumNamedValue","value":"CLIENT"}}},"timestamp":{"type":"RDFDatetime","value":42E6}}},{"type":"ApiNotification","value":{"is_pending":{"type":"RDFBool","value":true},"message":{"type":"unicode","value":"Host-0: <some other message>"},
"reference":{"type":"ApiNotificationReference","value":{"type":{"type":"EnumNamedValue","value":"VFS"},"vfs":{"type":"ApiNotificationVfsReference","value":{"client_id":{"type":"ClientURN","value":"aff4:/C.1000000000000000"},"vfs_path":{"type":"RDFURN","value":"aff4:/C.1000000000000000"}}}}},"timestamp":{"type":"RDFDatetime","value":44E6}}}]);render();$interval.flush(FETCH_INTERVAL);expect(grrApiService.get).toHaveBeenCalled();expect(Notification.calls.count()).toBe(2);const firstCallArgs=Notification.calls.all()[0]["args"];
const secondCallArgs=Notification.calls.all()[1]["args"];expect(firstCallArgs).toEqual(["GRR",{"body":"Host-0: <some other message>","icon":"static/images/grr_logo_notification.png","tag":"GRR44000000"}]);expect(secondCallArgs).toEqual(["GRR",{"body":"Host-0: <another message>","icon":"static/images/grr_logo_notification.png","tag":"GRR48000000"}])})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.user.userLabelDirectiveTest");goog.setTestOnly();const {testsModule}=goog.require("grrUi.tests");const {userModule}=goog.require("grrUi.user.user");describe("User label directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/user/user-label.html"));beforeEach(module(userModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");
$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService")}));const render=()=>{const template="<grr-user-label />";const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("fetches username and shows it",()=>{const mockUserName="Test Username";spyOn(grrApiService,"getCached").and.callFake(()=>{const deferred=$q.defer();deferred.resolve({data:{value:{username:{value:mockUserName}}}});return deferred.promise});const element=
render(mockUserName);expect(element.text().trim()).toBe(`User: ${mockUserName}`)});it("shows special message in case of 403 error",()=>{spyOn(grrApiService,"getCached").and.callFake(()=>{const deferred=$q.defer();deferred.reject({status:403,statusText:"Unauthorized"});return deferred.promise});const element=render();expect(element.text().trim()).toBe("User: Authentication Error")});it("shows status text in case of a non-403 error",()=>{spyOn(grrApiService,"getCached").and.callFake(()=>{const deferred=
$q.defer();deferred.reject({status:500,statusText:"Error"});return deferred.promise});const element=render();expect(element.text().trim()).toBe("User: Error")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.user.userNotificationButtonDirectiveTest");goog.setTestOnly();const {UserNotificationButtonDirective}=goog.require("grrUi.user.userNotificationButtonDirective");const {testsModule}=goog.require("grrUi.tests");const {userModule}=goog.require("grrUi.user.user");describe("User notification button directive",()=>{let $compile;let $interval;let $q;let $rootScope;let grrApiService;const FETCH_INTERVAL=UserNotificationButtonDirective.fetch_interval;
beforeEach(module("/static/angular-components/user/user-notification-button.html"));beforeEach(module(userModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$interval=$injector.get("$interval");grrApiService=$injector.get("grrApiService")}));const render=()=>{const template="<grr-user-notification-button />";const element=$compile(template)($rootScope);$rootScope.$apply();
return element};const mockApiServiceResponse=(value)=>{spyOn(grrApiService,"get").and.callFake(()=>{const deferred=$q.defer();deferred.resolve({data:{count:value}});return deferred.promise})};it("fetches pending notifications count and displays an info-styled button on 0",()=>{mockApiServiceResponse(0);const element=render();$interval.flush(FETCH_INTERVAL);expect(grrApiService.get).toHaveBeenCalled();expect(element.text().trim()).toBe("0");expect(element.find("button").hasClass("btn-info")).toBe(true)});
it("non-zero notifications count is shown as danger-styled button",()=>{mockApiServiceResponse(5);const element=render();$interval.flush(FETCH_INTERVAL);expect(grrApiService.get).toHaveBeenCalled();expect(element.text().trim()).toBe("5");expect(element.find("button").hasClass("btn-danger")).toBe(true)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.user.userNotificationItemDirectiveTest");goog.setTestOnly();const {annotateApiNotification}=goog.require("grrUi.user.userNotificationItemDirective");describe("User notification item directive",()=>{describe("annotateApiNotification()",()=>{const buildNotification=(reference)=>({value:{is_pending:{value:true},message:{value:"Recursive Directory Listing complete 0 nodes, 0 dirs"},reference:reference,timestamp:{value:0x530e9972fd28f}}});
it("annotates CLIENT notification correctly",()=>{const notification=buildNotification({value:{type:{value:"CLIENT"},client:{value:{client_id:{value:"aff4:/C.0000000000000001"}}}}});annotateApiNotification(notification);expect(notification.link).toEqual("clients/C.0000000000000001");expect(notification.refType).toEqual("CLIENT")});it("annotates HUNT notification correctly",()=>{const notification=buildNotification({value:{type:{value:"HUNT"},hunt:{value:{hunt_id:{value:"H:123456"}}}}});annotateApiNotification(notification);
expect(notification.link).toEqual("hunts/H:123456");expect(notification.refType).toEqual("HUNT")});it("annotates CRON notification correctly",()=>{const notification=buildNotification({value:{type:{value:"CRON"},cron:{value:{cron_job_id:{value:"FooBar"}}}}});annotateApiNotification(notification);expect(notification.link).toEqual("crons/FooBar");expect(notification.refType).toEqual("CRON")});it("annotates FLOW notification correctly",()=>{const notification=buildNotification({value:{type:{value:"FLOW"},
flow:{value:{client_id:{value:"aff4:/C.0001000200030004"},flow_id:{value:"F:123456"}}}}});annotateApiNotification(notification);expect(notification.link).toEqual("clients/C.0001000200030004/flows/F:123456");expect(notification.refType).toEqual("FLOW")});it("annotates CLIENT_APPROVAL notification correctly",()=>{const notification=buildNotification({value:{type:{value:"CLIENT_APPROVAL"},client_approval:{value:{client_id:{value:"aff4:/C.0001000200030004"},approval_id:{value:"foo-bar"},username:{value:"test"}}}}});
annotateApiNotification(notification);expect(notification.link).toEqual("users/test/approvals/client/C.0001000200030004/foo-bar");expect(notification.refType).toEqual("CLIENT_APPROVAL")});it("annotates HUNT_APPROVAL notification correctly",()=>{const notification=buildNotification({value:{type:{value:"HUNT_APPROVAL"},hunt_approval:{value:{hunt_id:{value:"H:123456"},approval_id:{value:"foo-bar"},username:{value:"test"}}}}});annotateApiNotification(notification);expect(notification.link).toEqual("users/test/approvals/hunt/H:123456/foo-bar");
expect(notification.refType).toEqual("HUNT_APPROVAL")});it("annotates CRON_JOB_APPROVAL notification correctly",()=>{const notification=buildNotification({value:{type:{value:"CRON_JOB_APPROVAL"},cron_job_approval:{value:{cron_job_id:{value:"FooBar"},approval_id:{value:"foo-bar"},username:{value:"test"}}}}});annotateApiNotification(notification);expect(notification.link).toEqual("users/test/approvals/cron-job/FooBar/foo-bar");expect(notification.refType).toEqual("CRON_JOB_APPROVAL")});it("annotates UNKNOWN notification correctly",
()=>{const notification=buildNotification({value:{type:{value:"UNKNOWN"},unknown:{value:{source_urn:{value:"aff4:/foo/bar"},subject_urn:{value:"aff4:/blah/blah"}}}}});annotateApiNotification(notification);expect(notification.link).toBe(null);expect(notification.refType).toEqual("UNKNOWN")});it("handles missing references correctly",()=>{const notification={value:{is_pending:{value:false},message:{value:"Recursive Directory Listing complete 0 nodes, 0 dirs"},timestamp:{value:0x530e9972fd28f}}};annotateApiNotification(notification);
expect(notification.isPending).toBe(false);expect(notification.link).toBeUndefined();expect(notification.refType).toBeUndefined()})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.virtualFileSystem.breadcrumbsDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {clientModule}=goog.require("grrUi.client.client");describe("breadcrums directive",()=>{let $compile;let $rootScope;let $scope;beforeEach(module("/static/angular-components/client/virtual-file-system/breadcrumbs.html"));beforeEach(module(clientModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$scope=$rootScope.$new()}));const render=(path,stripEndingSlash)=>{$scope.obj={path:path,stripEndingSlash:stripEndingSlash};const template='<grr-breadcrumbs strip-ending-slash="obj.stripEndingSlash" '+'path="obj.path" />';const element=$compile(template)($scope);$scope.$apply();return element};it("should show the path components as links",()=>{const element=render("path/to/some/resource");expect(element.find("a").length).toBe(2);
expect(element.find("li.active").text().trim()).toBe("some")});it("strips ending slash if strip-ending-slash is true",()=>{const element=render("path/to/some/resource/",true);expect(element.find("a").length).toBe(2);expect(element.find("li.active").text().trim()).toBe("some")});it("should change the path when a link is clicked",()=>{const element=render("path/to/some/resource");const links=element.find("a");expect(links.length).toBe(2);browserTriggerEvent(links[1],"click");$scope.$apply();expect(element.find("li.active").text().trim()).toBe("to");
expect($scope.obj.path).toBe("path/to/")});it("should change the links when the scope changes",()=>{const element=render("path/to/some/resource");expect(element.find("a").length).toBe(2);expect(element.find("li.active").text().trim()).toBe("some");$scope.obj.path="a/path/to/another/file";$scope.$apply();expect(element.find("a").length).toBe(3);expect(element.find("li.active").text().trim()).toBe("another")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.virtualFileSystem.encodingsDropdownDirectiveTest");goog.setTestOnly();const {clientModule}=goog.require("grrUi.client.client");const {testsModule}=goog.require("grrUi.tests");describe("encodings dropdown directive",()=>{let $compile;let $q;let $rootScope;let $scope;let grrApiService;beforeEach(module("/static/angular-components/client/virtual-file-system/encodings-dropdown.html"));beforeEach(module(clientModule.name));beforeEach(module(testsModule.name));
beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$q=$injector.get("$q");grrApiService=$injector.get("grrApiService");$scope=$rootScope.$new()}));const mockApiService=(responses)=>{spyOn(grrApiService,"get").and.callFake((path)=>{const response={encodings:responses[path]};return $q.when({data:response})})};const render=(encoding)=>{$scope.obj={encoding:encoding};const template='<grr-encodings-dropdown encoding="obj.encoding" />';const element=
$compile(template)($scope);$scope.$apply();return element};it("should select the scope value",()=>{const encodings=[{value:"ENC1"},{value:"ENC2"},{value:"ENC99"},{value:"UTF_8"}];mockApiService({"reflection/file-encodings":encodings});const element=render("ENC1");expect(element.find("option").length).toBe(4);expect(element.find("option[selected]").text().trim()).toBe("ENC1");expect(grrApiService.get).toHaveBeenCalled()});it("should change the selection when the scope changes",()=>{const encodings=
[{value:"ENC1"},{value:"ENC2"},{value:"ENC99"},{value:"UTF_8"}];mockApiService({"reflection/file-encodings":encodings});const element=render("ENC1");expect(element.find("option[selected]").text().trim()).toBe("ENC1");$scope.obj.encoding="UTF_8";$scope.$apply();expect(element.find("option[selected]").text().trim()).toBe("UTF_8")});it("should be disabled when no options are available",()=>{mockApiService({"some/url":[]});const element=render("UTF_8");expect(element.find("select[disabled]").length).toBe(1);
expect(element.find("option").text().trim()).toBe("No encodings available.");expect($scope.obj.encoding).toBe("UTF_8")})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.virtualFileSystem.fileContextDirectiveTest");goog.setTestOnly();const {FileContextController}=goog.require("grrUi.client.virtualFileSystem.fileContextDirective");describe("file context directive",()=>{let $rootScope;beforeEach(inject(($injector)=>{$rootScope=$injector.get("$rootScope")}));const getController=()=>{let controller;inject(($injector)=>{controller=$injector.instantiate(FileContextController,{"$scope":$rootScope})});
$rootScope.controller=controller;$rootScope.$apply();return controller};it("changes the controller values when the scope values change",()=>{const controller=getController();expect(controller.clientId).toBeUndefined();expect(controller.selectedFilePath).toBeUndefined();expect(controller.selectedFileVersion).toBeUndefined();$rootScope.clientId=42;$rootScope.selectedFilePath="some/path/test.txt";$rootScope.selectedFileVersion=1337;$rootScope.$apply();expect(controller.clientId).toEqual(42);expect(controller.selectedFilePath).toEqual("some/path/test.txt");
expect(controller.selectedFileVersion).toEqual(1337)});it("changes the scope whenever the controller values change",()=>{const controller=getController();controller.clientId=42;controller.selectedFilePath="some/path/test.txt";controller.selectedFileVersion=1337;$rootScope.$apply();expect($rootScope.clientId).toEqual(42);expect($rootScope.selectedFilePath).toEqual("some/path/test.txt");expect($rootScope.selectedFileVersion).toEqual(1337)});it("allows settings the selected file via selectFile",()=>
{const controller=getController();controller.selectFile("some/path/test.txt");$rootScope.$apply();expect($rootScope.selectedFilePath).toEqual("some/path/test.txt");expect($rootScope.selectedFileVersion).toBeUndefined();controller.selectFile("some/other/path/test.txt",1337);$rootScope.$apply();expect($rootScope.selectedFilePath).toEqual("some/other/path/test.txt");expect($rootScope.selectedFileVersion).toEqual(1337)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.virtualFileSystem.fileHexViewDirectiveTest");goog.setTestOnly();const {testsModule}=goog.require("grrUi.tests");const {virtualFileSystemModule}=goog.require("grrUi.client.virtualFileSystem.virtualFileSystem");describe("file hex view directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/client/virtual-file-system/file-hex-view.html"));beforeEach(module(virtualFileSystemModule.name));
beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService")}));const render=(clientId,filePath)=>{$rootScope.clientId=clientId;$rootScope.selectedFilePath=filePath;const template="<grr-file-context"+'    client-id="clientId"'+'    selected-file-path="selectedFilePath">'+"  <grr-file-hex-view />"+"</grr-file-context>";const element=$compile(template)($rootScope);
$rootScope.$apply();return element};it("shows proper hex values",()=>{spyOn(grrApiService,"head").and.callFake(()=>$q.when({headers:function(){return 100}}));spyOn(grrApiService,"get").and.callFake(()=>$q.when({data:"some text"}));const element=render("C.0000111122223333","fs/os/c/test.txt");expect(grrApiService.get).toHaveBeenCalled();expect(element.find("table.offset-area tr:first-child td").text().trim()).toEqual("0x00000000");expect(element.find("table.offset-area tr:last-child td").text().trim()).toEqual("0x00000300");
expect(element.find("table.hex-area tr:first-child td").text().trim()).toEqual("736f6d652074657874");expect(element.find("table.content-area tr:first-child td").text().trim()).toEqual("some text")});it("shows a hint when the file is not available",()=>{spyOn(grrApiService,"head").and.callFake(()=>$q.reject("Some Error Message"));const element=render("C.0000111122223333","fs/os/c/test.txt");expect(grrApiService.head).toHaveBeenCalled();expect(element.find(".no-content").length).toEqual(1)})});exports=
{};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.virtualFileSystem.fileTreeDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {virtualFileSystemModule}=goog.require("grrUi.client.virtualFileSystem.virtualFileSystem");describe("file tree view directive",()=>{let $compile;let $q;let $rootScope;let grrApiService;beforeEach(module("/static/angular-components/client/virtual-file-system/file-tree.html"));beforeEach(module(virtualFileSystemModule.name));
beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");grrApiService=$injector.get("grrApiService")}));const render=(clientId,filePath)=>{$rootScope.clientId=clientId;$rootScope.selectedFolderPath=filePath;$rootScope.selectedFilePath=filePath;const template="<grr-file-context"+'    client-id="clientId"'+'    selected-folder-path="selectedFolderPath"'+'    selected-file-path="selectedFilePath"'+
'    selected-file-version="selectedFileVersion">'+"  <grr-file-tree />"+"</grr-file-context>";const element=$compile(template)($rootScope);$rootScope.$apply();return element};const mockApiService=(responses)=>{spyOn(grrApiService,"get").and.callFake((path)=>{const response={items:responses[path]};return $q.when({data:response})})};const getChildNodeTexts=(jsTree,nodeId)=>{const treeItems=jsTree.find(nodeId).find("[role=treeitem]");const texts=[];angular.forEach(treeItems,(item)=>{texts.push($(item).text())});
return texts};it("shows correct nested folder structure",(done)=>{const responses={};responses["clients/C.0000111122223333/vfs-index/"]=[{value:{name:{value:"fs"},path:{value:"fs"}}}];responses["clients/C.0000111122223333/vfs-index/fs"]=[{value:{name:{value:"os"},path:{value:"fs/os"}}},{value:{name:{value:"tsk"},path:{value:"fs/tsk"}}}];responses["clients/C.0000111122223333/vfs-index/fs/os"]=[{value:{name:{value:"dir1"},path:{value:"fs/os/dir1"}}},{value:{name:{value:"dir2"},path:{value:"fs/os/dir2"}}},
{value:{name:{value:"dir3"},path:{value:"fs/os/dir3"}}}];mockApiService(responses);const element=render("C.0000111122223333","fs");const jsTree=element.find("#file-tree");jsTree.one("load_node.jstree",()=>{expect(jsTree.find("[role=treeitem]").length).toBe(1);expect(jsTree.find("[role=treeitem]").attr("id")).toBe("_fs");browserTriggerEvent(jsTree.find("#_fs a"),"click");jsTree.one("open_node.jstree",()=>{expect(getChildNodeTexts(jsTree,"li#_fs")).toEqual(["os","tsk"]);browserTriggerEvent(jsTree.find("#_fs-os a"),
"click");jsTree.one("open_node.jstree",()=>{expect(getChildNodeTexts(jsTree,"li#_fs-os")).toEqual(["dir1","dir2","dir3"]);expect(jsTree.find("[role=treeitem]").length).toBe(6);done()});$rootScope.$apply()});$rootScope.$apply()})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.virtualFileSystem.fileViewDirectiveTest");goog.setTestOnly();const {getFileId,getFilePathFromId}=goog.require("grrUi.client.virtualFileSystem.fileViewDirective");describe("file view directive",()=>{describe("getFileId()",()=>{it("returns the file id for any given path",()=>{expect(getFileId("some/regular/path")).toEqual("_some-regular-path");expect(getFileId("some/$peci&l/path")).toEqual("_some-_24peci_26l-path");expect(getFileId("s0me/numb3r5/p4th")).toEqual("_s0me-numb3r5-p4th");
expect(getFileId("a slightly/weird_/path")).toEqual("_a_20slightly-weird_5F-path");expect(getFileId("")).toEqual("_")});it("replaces characters with char code > 255 with more than a two-digit hex number",()=>{expect(getFileId("some/sp\u20accial/path")).toEqual("_some-sp_20ACcial-path");expect(getFileId("fs/os/c/\u4e2d\u56fd\u65b0\u95fb\u7f51\u65b0\u95fb\u4e2d")).toEqual("_fs-os-c-_4E2D_56FD_65B0_95FB_7F51_65B0_95FB_4E2D")})});describe("getFilePathFromId()",()=>{it("returns the path for any given id",
()=>{expect(getFilePathFromId("_some-regular-path")).toEqual("some/regular/path");expect(getFilePathFromId("_some-_24peci_26l-path")).toEqual("some/$peci&l/path");expect(getFilePathFromId("_s0me-numb3r5-p4th")).toEqual("s0me/numb3r5/p4th");expect(getFilePathFromId("_a_20slightly-weird_5F-path")).toEqual("a slightly/weird_/path");expect(getFilePathFromId("_")).toEqual("")});it("does not decode chars encoded with more than two hex-digits",()=>{expect(getFilePathFromId("_some-sp_20ACcial-path")).not.toEqual("some/sp\u20accial/path");
expect(getFilePathFromId("_fs-os-c-_4E2D_56FD_65B0_95FB_7F51_65B0_95FB_4E2D")).not.toEqual("fs/os/c/\u4e2d\u56fd\u65b0\u95fb\u7f51\u65b0\u95fb\u4e2d")})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.virtualFileSystem.recursiveListButtonDirectiveTest");goog.setTestOnly();const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {virtualFileSystemModule}=goog.require("grrUi.client.virtualFileSystem.virtualFileSystem");describe('"recursive list directory" button',()=>{let $compile;let $q;let $rootScope;let $timeout;let grrApiService;let grrReflectionService;beforeEach(module("/static/angular-components/client/virtual-file-system/recursive-list-button.html"));
beforeEach(module("/static/angular-components/client/virtual-file-system/recursive-list-button-modal.html"));beforeEach(module(virtualFileSystemModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$timeout=$injector.get("$timeout");grrReflectionService=$injector.get("grrReflectionService");grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=(clientId,
filePath)=>{$rootScope.clientId=clientId||"C.0000111122223333";$rootScope.filePath=filePath||"fs/os/c/";const template="<grr-recursive-list-button "+'client-id="clientId" file-path="filePath" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("fetches descriptors on click",()=>{const deferred=$q.defer();spyOn(grrReflectionService,"getRDFValueDescriptor").and.returnValue(deferred.promise);const element=renderTestTemplate();browserTriggerEvent(element.find("button"),
"click");expect(grrReflectionService.getRDFValueDescriptor).toHaveBeenCalledWith("ApiCreateVfsRefreshOperationArgs",true)});describe("modal dialog",()=>{beforeEach(()=>{const deferred=$q.defer();spyOn(grrReflectionService,"getRDFValueDescriptor").and.returnValue(deferred.promise);deferred.resolve({"ApiCreateVfsRefreshOperationArgs":{default:{type:"ApiCreateVfsRefreshOperationArgs",value:{}}},"RDFInteger":{default:{type:"RDFInteger",value:0}},"RDFString":{default:{type:"RDFString",value:""}},"ClientURN":{default:{type:"ClientURN",
value:""}}})});afterEach(()=>{$(document.body).html("")});it("is shown when button clicked and descriptors fetched",()=>{const element=renderTestTemplate();browserTriggerEvent(element.find("button"),"click");expect($(document.body).text()).toContain("Recursive Directory Refresh")});it("is closed when close button is clicked",()=>{const element=renderTestTemplate();browserTriggerEvent($("button",element),"click");browserTriggerEvent($("button.close"),"click");$timeout.flush();expect($(document.body).text()).not.toContain("Recursive Directory Refresh")});
it("is closed when cancel button is clicked",()=>{const element=renderTestTemplate();browserTriggerEvent($("button",element),"click");browserTriggerEvent($("button[name=Cancel]"),"click");$timeout.flush();expect($(document.body).text()).not.toContain("Recursive Directory Refresh")});it('sends an API request when "refresh" is clicked',()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=renderTestTemplate();browserTriggerEvent(element.find("button"),
"click");browserTriggerEvent($("button[name=Proceed]"),"click");expect(grrApiService.post).toHaveBeenCalledWith("clients/C.0000111122223333/vfs-refresh-operations",{type:"ApiCreateVfsRefreshOperationArgs",value:{file_path:{type:"RDFString",value:"fs/os/c"},max_depth:{type:"RDFInteger",value:5},notify_user:true}},true)});it('strips "aff4:/" prefix from client id',()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=renderTestTemplate("aff4:/C.0000111122223333");
browserTriggerEvent(element.find("button"),"click");browserTriggerEvent($("button[name=Proceed]"),"click");expect(grrApiService.post).toHaveBeenCalled();expect(grrApiService.post.calls.mostRecent().args[0]).toBe("clients/C.0000111122223333/vfs-refresh-operations")});it("disables the button when API request is sent",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);const element=renderTestTemplate();browserTriggerEvent(element.find("button"),"click");expect(element.find("button[disabled]").length).toBe(0);
browserTriggerEvent($("button[name=Proceed]"),"click");expect(element.find("button[disabled]").length).toBe(1)});it("shows success message when API request is successful",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);deferred.resolve({data:{status:"OK"}});spyOn(grrApiService,"get").and.returnValue($q.defer().promise);const element=renderTestTemplate();browserTriggerEvent(element.find("button"),"click");browserTriggerEvent($("button[name=Proceed]"),"click");
expect($(document.body).text()).toContain("Refresh started successfully!")});it("shows failure message when API request fails",()=>{const deferred=$q.defer();spyOn(grrApiService,"post").and.returnValue(deferred.promise);deferred.reject({data:{message:"Oh no!"}});const element=renderTestTemplate();browserTriggerEvent(element.find("button"),"click");browserTriggerEvent($("button[name=Proceed]"),"click");expect($(document.body).text()).toContain("Oh no!")})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.virtualFileSystem.utilsTest");goog.setTestOnly();const {ensurePathIsFolder,getFolderFromPath}=goog.require("grrUi.client.virtualFileSystem.utils");describe("client virtual file system utils",()=>{describe("ensurePathIsFolder()",()=>{it('does nothing if path ends with "/"',()=>{expect(ensurePathIsFolder("/")).toBe("/");expect(ensurePathIsFolder("a/b/c/")).toBe("a/b/c/")});it('adds "/" if path does not end with it',()=>{expect(ensurePathIsFolder("")).toBe("/");
expect(ensurePathIsFolder("a/b/c")).toBe("a/b/c/")})});describe("getFolderFromPath()",()=>{it("does nothing for falsey values",()=>{expect(getFolderFromPath(null)).toBe("");expect(getFolderFromPath(undefined)).toBe("");expect(getFolderFromPath("")).toBe("")});it("strips last component from path with no trailing slash",()=>{expect(getFolderFromPath("a/b/c")).toBe("a/b")});it("strips trailing slash only, if there is one",()=>{expect(getFolderFromPath("a/b/c/")).toBe("a/b/c")})})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.client.virtualFileSystem.vfsFilesArchiveButtonDirectiveTest");goog.setTestOnly();const {DOWNLOAD_EVERYTHING_REENABLE_DELAY}=goog.require("grrUi.client.virtualFileSystem.vfsFilesArchiveButtonDirective");const {ServerErrorButtonDirective}=goog.require("grrUi.core.serverErrorButtonDirective");const {browserTriggerEvent,testsModule}=goog.require("grrUi.tests");const {virtualFileSystemModule}=goog.require("grrUi.client.virtualFileSystem.virtualFileSystem");
describe('"download vfs archive" button',()=>{let $compile;let $q;let $rootScope;let $timeout;let grrApiService;const ERROR_EVENT_NAME=ServerErrorButtonDirective.error_event_name;beforeEach(module("/static/angular-components/client/virtual-file-system/vfs-files-archive-button.html"));beforeEach(module(virtualFileSystemModule.name));beforeEach(module(testsModule.name));beforeEach(inject(($injector)=>{$q=$injector.get("$q");$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope");$timeout=
$injector.get("$timeout");grrApiService=$injector.get("grrApiService")}));const renderTestTemplate=(clientId,filePath)=>{$rootScope.clientId=clientId||"C.0000111122223333";$rootScope.filePath=filePath||"fs/os/c/";const template="<grr-vfs-files-archive-button "+'client-id="clientId" file-path="filePath" />';const element=$compile(template)($rootScope);$rootScope.$apply();return element};it('sends correct request when "download everything" option is chosen',()=>{const deferred=$q.defer();spyOn(grrApiService,
"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();browserTriggerEvent(element.find("a[name=downloadEverything]"),"click");expect(grrApiService.downloadFile).toHaveBeenCalledWith("clients/C.0000111122223333/vfs-files-archive/")});it('sends correct request when "download current folder" option is chosen',()=>{const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();browserTriggerEvent(element.find("a[name=downloadCurrentFolder]"),
"click");expect(grrApiService.downloadFile).toHaveBeenCalledWith("clients/C.0000111122223333/vfs-files-archive/fs/os/c")});it('disables "download everything" option after the click for 30 seconds',()=>{const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();browserTriggerEvent(element.find("a[name=downloadEverything]"),"click");$timeout.flush(DOWNLOAD_EVERYTHING_REENABLE_DELAY-1E3);let items=element.find("li:has(a[name=downloadEverything]).disabled");
expect(items.length).toBe(1);$timeout.flush(1001);items=element.find("li:has(a[name=downloadEverything]):not(.disabled)");expect(items.length).toBe(1)});it('disables "download current folder" option after the click until folder is changed',()=>{const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();browserTriggerEvent(element.find("a[name=downloadCurrentFolder]"),"click");let items=element.find("li:has(a[name=downloadCurrentFolder]).disabled");
expect(items.length).toBe(1);$rootScope.filePath="fs/os/c/d";$rootScope.$apply();items=element.find("li:has(a[name=downloadCurrentFolder]):not(.disabled)");expect(items.length).toBe(1)});it("broadcasts error event on failure",(done)=>{const deferred=$q.defer();spyOn(grrApiService,"downloadFile").and.returnValue(deferred.promise);const element=renderTestTemplate();browserTriggerEvent(element.find("a[name=downloadCurrentFolder]"),"click");$rootScope.$on(ERROR_EVENT_NAME,done);deferred.reject({data:{message:"FAIL"}});
$rootScope.$apply()})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.rekall.rekallJsonDirectiveTest");goog.setTestOnly();const {rekallModule}=goog.require("grrUi.semantic.rekall.rekall");const {stubDirective,testsModule}=goog.require("grrUi.tests");describe("Rekall JSON directive",()=>{let $compile;let $rootScope;beforeEach(module("/static/angular-components/semantic/rekall/rekall-json.html"));beforeEach(module(rekallModule.name));beforeEach(module(testsModule.name));stubDirective("grrRekallLog");
stubDirective("grrRekallMetadata");stubDirective("grrRekallTable");beforeEach(inject(($injector)=>{$compile=$injector.get("$compile");$rootScope=$injector.get("$rootScope")}));const renderTestTemplate=(jsonContextMessages,compressedJsonMessages)=>{$rootScope.jsonContextMessages={"value":jsonContextMessages};$rootScope.compressedJsonMessages={"value":compressedJsonMessages};const template="<grr-rekall-json "+'    json-context-messages="jsonContextMessages" '+'    compressed-json-messages="compressedJsonMessages">'+
"</grr-rekall-json>";const element=$compile(template)($rootScope);$rootScope.$apply();return element};it("shows nothing when the input is empty",()=>{const element=renderTestTemplate("[]","[]");expect(element.find("div").length).toBe(0)});it("shows messages of known types.",()=>{const element=renderTestTemplate('[["t", {}]]','[["L", {}], ["m", {}], ["r", {}]]');expect(element.find("div").length).toBe(3);expect(element.find("grr-rekall-log").length).toBe(1);expect(element.find("grr-rekall-metadata").length).toBe(1);
expect(element.find("grr-rekall-table").length).toBe(1)});it('shows EOM for messages of type "x".',()=>{const element=renderTestTemplate("[]",'[["x", {}]]');expect(element.find("div").length).toBe(1);expect(element.text()).toContain("EOM")});it("shows its input for messages of unknown type.",()=>{const element=renderTestTemplate("[]",'[["?", {}]]');expect(element.find("div").length).toBe(1);expect(element.text()).toContain('["?",{}]')})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.rekall.rekallRegistryServiceTest");goog.setTestOnly();const {RekallRegistryService}=goog.require("grrUi.semantic.rekall.rekallRegistryService");const {rekallModule}=goog.require("grrUi.semantic.rekall.rekall");describe("Rekall registry",()=>{let testRegistry;beforeEach(module(rekallModule.name));beforeEach(inject(($injector)=>{testRegistry=$injector.instantiate(RekallRegistryService,{})}));it("finds previously registered directive",
()=>{testRegistry.registerDirective("SomeType",Object);const foundDirective=testRegistry.findDirectiveForMro("SomeType");expect(foundDirective).toBe(Object)});it("returns undefined when searching for not registered directive",()=>{const foundDirective=testRegistry.findDirectiveForMro("SomeType");expect(foundDirective).toBeUndefined()});it("returns more specific directive when multiple directives match",()=>{const directive1=Object();const directive2=Object();testRegistry.registerDirective("SomeChildType",
directive1);testRegistry.registerDirective("SomeParentType",directive2);const foundDirective=testRegistry.findDirectiveForMro("SomeChildType:SomeParentType");expect(foundDirective).toBe(directive1)})});exports={};return exports});goog.loadModule(function(exports){"use strict";goog.module("grrUi.semantic.rekall.utilsTest");goog.setTestOnly();const {cropRekallJson,stackRekallTables}=goog.require("grrUi.semantic.rekall.utils");describe("semantic.rekall.utils.cropRekallJson",()=>{it("crops Rekall Json messages.",()=>{const jsonStr='[["L",{"msg":"foo"}],["L",{"msg":"bar"}],["m",{"se'+'ssion":{}}]]';const targetLen=50;const croppedJsonStr=cropRekallJson(jsonStr,targetLen);expect(croppedJsonStr).toBe('[["L",{"msg":"foo"}],["L",{"msg":"bar"}]]')});
it("ignores brackets inside strings.",()=>{const jsonStr='[["L",{"msg":"]]]]]]]]][[][][]["}],["L",{"msg":"ba'+'r"}],["m",{"session":{}}]]';const targetLen=50;const croppedJsonStr=cropRekallJson(jsonStr,targetLen);expect(croppedJsonStr).toBe('[["L",{"msg":"]]]]]]]]][[][][]["}]]')});it('ignores escaped "s and \\s inside strings.',()=>{const jsonStr='[["L",{"msg":"]]\\"]\\"\\"\\"]]\\\\\\\\\\"]]]\\\\\\\\"}],["L",{'+'"msg":"bar"}],["m",{"session":{}}]]';const targetLen=50;const croppedJsonStr=cropRekallJson(jsonStr,
targetLen);expect(croppedJsonStr).toBe('[["L",{"msg":"]]\\"]\\"\\"\\"]]\\\\\\\\\\"]]]\\\\\\\\"}]]')})});describe("semantic.rekall.utils.stackRekallTables",()=>{it("Stacks rekall tables correctly.",()=>{const parsedMessages=[["r",{"ip":"::1"}],["t",[{"cname":"ip","name":"IP Address"}]],["r",{"ip":"::2"}],["r",{"ip":"::3"}],["r",{"ip":"::4"}]];const stackedMessages=stackRekallTables(parsedMessages);expect(stackedMessages).toEqual([["t",{"header":undefined,"rows":[{"ip":"::1"}]}],["t",{"header":[{"cname":"ip",
"name":"IP Address"}],"rows":[{"ip":"::2"},{"ip":"::3"},{"ip":"::4"}]}]])})});exports={};return exports});
//# sourceMappingURL=grr-ui-test.bundle.js.map