Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Test fixture for utility.js. | 6 * Test fixture for utility.js. |
| 7 * @constructor | 7 * @constructor |
| 8 * @extends {testing.Test} | 8 * @extends {testing.Test} |
| 9 */ | 9 */ |
| 10 function GoogleNowUtilityUnitTest () { | 10 function GoogleNowUtilityUnitTest () { |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 172 this.mockGlobals.expects(once()). | 172 this.mockGlobals.expects(once()). |
| 173 buildErrorWithMessageForServer('Not in instrumented callback'). | 173 buildErrorWithMessageForServer('Not in instrumented callback'). |
| 174 will(returnValue(testError)); | 174 will(returnValue(testError)); |
| 175 this.mockGlobals.expects(once()). | 175 this.mockGlobals.expects(once()). |
| 176 reportError(eqJSON(testError)); | 176 reportError(eqJSON(testError)); |
| 177 | 177 |
| 178 // Invocation. | 178 // Invocation. |
| 179 wrapper.checkInWrappedCallback(); | 179 wrapper.checkInWrappedCallback(); |
| 180 | 180 |
| 181 // Step 4. Check that there won't be errors whe the page unloads. | 181 // Step 4. Check that there won't be errors whe the page unloads. |
| 182 assertTrue(onSuspendHandlerContainer.length == 1, | 182 assertEquals(1, onSuspendHandlerContainer.length); |
| 183 'onSuspendHandlerContainer.length must be 1'); | |
| 184 onSuspendHandlerContainer[0](); | 183 onSuspendHandlerContainer[0](); |
| 185 }); | 184 }); |
| 186 | 185 |
| 187 TEST_F('GoogleNowUtilityUnitTest', 'WrapperWrapCallbackPlugin', function() { | 186 TEST_F('GoogleNowUtilityUnitTest', 'WrapperWrapCallbackPlugin', function() { |
| 188 // Tests calling plugin's prologue and epilogue. | 187 // Tests calling plugin's prologue and epilogue. |
| 189 | 188 |
| 190 // Setup. | 189 // Setup. |
| 191 this.makeMockLocalFunctions([ | 190 this.makeMockLocalFunctions([ |
| 192 'callback', | 191 'callback', |
| 193 'pluginFactory', | 192 'pluginFactory', |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 374 // Step 3. Firing runtime.onSuspend event. | 373 // Step 3. Firing runtime.onSuspend event. |
| 375 // Expectations. | 374 // Expectations. |
| 376 this.mockGlobals.expects(once()). | 375 this.mockGlobals.expects(once()). |
| 377 buildErrorWithMessageForServer(stringContains( | 376 buildErrorWithMessageForServer(stringContains( |
| 378 'ASSERT: Pending callbacks when unloading event page')). | 377 'ASSERT: Pending callbacks when unloading event page')). |
| 379 will(returnValue(testError)); | 378 will(returnValue(testError)); |
| 380 this.mockGlobals.expects(once()). | 379 this.mockGlobals.expects(once()). |
| 381 reportError(eqJSON(testError)); | 380 reportError(eqJSON(testError)); |
| 382 | 381 |
| 383 // Invocation. | 382 // Invocation. |
| 384 assertTrue(onSuspendHandlerContainer.length == 1, | 383 assertEquals(1, onSuspendHandlerContainer.length); |
| 385 'onSuspendHandlerContainer.length must be 1'); | |
| 386 onSuspendHandlerContainer[0](); | 384 onSuspendHandlerContainer[0](); |
| 387 }); | 385 }); |
| 388 | 386 |
| 389 TEST_F('GoogleNowUtilityUnitTest', | 387 TEST_F('GoogleNowUtilityUnitTest', |
| 390 'WrapperOnSuspendListenerSuccess', | 388 'WrapperOnSuspendListenerSuccess', |
| 391 function() { | 389 function() { |
| 392 // Tests that upon unloading event page, we don't get an error if there are no | 390 // Tests that upon unloading event page, we don't get an error if there are no |
| 393 // pending required callbacks. | 391 // pending required callbacks. |
| 394 | 392 |
| 395 // Setup. | 393 // Setup. |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 417 Mock4JS.verifyAllMocks(); | 415 Mock4JS.verifyAllMocks(); |
| 418 | 416 |
| 419 // Step 3. Calling wrapped callback. | 417 // Step 3. Calling wrapped callback. |
| 420 // Expectations. | 418 // Expectations. |
| 421 this.mockLocalFunctions.expects(once()).callback(); | 419 this.mockLocalFunctions.expects(once()).callback(); |
| 422 | 420 |
| 423 // Invocation. | 421 // Invocation. |
| 424 wrappedCallback(); | 422 wrappedCallback(); |
| 425 | 423 |
| 426 // Step 4. Firing runtime.onSuspend event. | 424 // Step 4. Firing runtime.onSuspend event. |
| 427 assertTrue(onSuspendHandlerContainer.length == 1, | 425 assertEquals(1, onSuspendHandlerContainer.length); |
| 428 'onSuspendHandlerContainer.length must be 1'); | |
| 429 onSuspendHandlerContainer[0](); | 426 onSuspendHandlerContainer[0](); |
| 430 }); | 427 }); |
| 431 | 428 |
| 432 var taskNameA = 'TASK A'; | 429 var taskNameA = 'TASK A'; |
| 433 var taskNameB = 'TASK B'; | 430 var taskNameB = 'TASK B'; |
| 434 var taskNameC = 'TASK C'; | 431 var taskNameC = 'TASK C'; |
| 435 | 432 |
| 436 function areTasksConflicting(newTaskName, scheduledTaskName) { | 433 function areTasksConflicting(newTaskName, scheduledTaskName) { |
| 437 // Task B is conflicting with Task A. This means that if Task B is added when | 434 // Task B is conflicting with Task A. This means that if Task B is added when |
| 438 // Task A is running, Task B will be ignored (but not vice versa). No other | 435 // Task A is running, Task B will be ignored (but not vice versa). No other |
| 439 // pair is conflicting. | 436 // pair is conflicting. |
| 440 return newTaskName == taskNameB && scheduledTaskName == taskNameA; | 437 return newTaskName == taskNameB && scheduledTaskName == taskNameA; |
| 441 } | 438 } |
| 442 | 439 |
| 443 function setUpTaskManagerTest(fixture) { | 440 function setUpTaskManagerTest(fixture) { |
| 444 // We want to mock wrapper using makeAndRegisterMockApis(), which requires | |
| 445 // the mocked functions to not exist as a precondition. Resetting 'wrapper' to | |
| 446 // 'undefined'. | |
| 447 wrapper = undefined; | |
| 448 | |
| 449 fixture.makeAndRegisterMockApis([ | 441 fixture.makeAndRegisterMockApis([ |
| 450 'wrapper.checkInWrappedCallback', | 442 'wrapper.checkInWrappedCallback', |
| 451 'wrapper.registerWrapperPluginFactory', | 443 'wrapper.registerWrapperPluginFactory', |
| 452 'wrapper.debugGetStateString' | 444 'wrapper.debugGetStateString' |
| 453 ]); | 445 ]); |
| 454 fixture.makeMockLocalFunctions(['task1', 'task2', 'task3']); | 446 fixture.makeMockLocalFunctions(['task1', 'task2', 'task3']); |
| 455 fixture.makeAndRegisterMockGlobals(['reportError']); | 447 fixture.makeAndRegisterMockGlobals(['reportError']); |
| 456 | 448 |
| 457 fixture.mockApis.stubs().wrapper_checkInWrappedCallback(); | 449 fixture.mockApis.stubs().wrapper_checkInWrappedCallback(); |
| 458 fixture.mockApis.stubs().wrapper_debugGetStateString(). | 450 fixture.mockApis.stubs().wrapper_debugGetStateString(). |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 613 will(callFunction(function() { | 605 will(callFunction(function() { |
| 614 test.pluginFactory(); | 606 test.pluginFactory(); |
| 615 })); | 607 })); |
| 616 // Invocation. | 608 // Invocation. |
| 617 test.tasks.add(taskNameA, this.mockLocalFunctions.functions().task1); | 609 test.tasks.add(taskNameA, this.mockLocalFunctions.functions().task1); |
| 618 Mock4JS.verifyAllMocks(); | 610 Mock4JS.verifyAllMocks(); |
| 619 | 611 |
| 620 // Step 2. Invoke onSuspend event of the task manager. | 612 // Step 2. Invoke onSuspend event of the task manager. |
| 621 // Setup and expectations. The 2 callbacks in onSuspendHandlerContainer are | 613 // Setup and expectations. The 2 callbacks in onSuspendHandlerContainer are |
| 622 // from the wrapper and the task manager. | 614 // from the wrapper and the task manager. |
| 623 assertTrue(onSuspendHandlerContainer.length == 2, | 615 assertEquals(2, onSuspendHandlerContainer.length); |
| 624 'onSuspendHandlerContainer.length must be 2'); | |
| 625 this.mockGlobals.expects(once()).reportError(eqToString( | 616 this.mockGlobals.expects(once()).reportError(eqToString( |
| 626 'Error: ASSERT: Incomplete task when unloading event page,' + | 617 'Error: ASSERT: Incomplete task when unloading event page,' + |
| 627 ' queue = [{"name":"TASK A"}], testWrapperDebugState')); | 618 ' queue = [{"name":"TASK A"}], testWrapperDebugState')); |
| 628 // Invocation. | 619 // Invocation. |
| 629 onSuspendHandlerContainer[1](); | 620 onSuspendHandlerContainer[1](); |
| 630 }); | 621 }); |
| 631 | 622 |
| 632 TEST_F('GoogleNowUtilityUnitTest', 'TaskManagerSuspendSuccess', function() { | 623 TEST_F('GoogleNowUtilityUnitTest', 'TaskManagerSuspendSuccess', function() { |
| 633 // Tests that task manager's onSuspend method does not reports an error if all | 624 // Tests that task manager's onSuspend method does not reports an error if all |
| 634 // tasks completed. | 625 // tasks completed. |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 719 // finished despite the pending non-task callback. | 710 // finished despite the pending non-task callback. |
| 720 task1PluginInstance.prologue(); | 711 task1PluginInstance.prologue(); |
| 721 task1PluginInstance.epilogue(); | 712 task1PluginInstance.epilogue(); |
| 722 Mock4JS.verifyAllMocks(); | 713 Mock4JS.verifyAllMocks(); |
| 723 | 714 |
| 724 // Step 4. Checking that task1 is finished by submitting task2, which should | 715 // Step 4. Checking that task1 is finished by submitting task2, which should |
| 725 // be executed immediately. | 716 // be executed immediately. |
| 726 this.mockLocalFunctions.expects(once()).task2(ANYTHING); | 717 this.mockLocalFunctions.expects(once()).task2(ANYTHING); |
| 727 test.tasks.add(taskNameC, this.mockLocalFunctions.functions().task2); | 718 test.tasks.add(taskNameC, this.mockLocalFunctions.functions().task2); |
| 728 }); | 719 }); |
| 720 | |
| 721 var testAttemptAlarmName = 'attempt-scheduler-testAttempts'; | |
| 722 var testAttemptStorageKey = 'current-delay-testAttempts'; | |
| 723 var testInitialDelaySeconds = 239; | |
| 724 var testMaximumDelaySeconds = 2239; | |
| 725 // Value to be returned by mocked Math.random(). We want the value returned by | |
| 726 // Math.random() to be predictable to be able to check results against expected | |
| 727 // values. Random seeding won't work because it doesn't guarantee a specific | |
| 728 // result of Math.random(). | |
|
robliao
2013/09/05 00:09:39
Not exactly true. A fixed seed would be okay, but
vadimt
2013/09/05 00:30:00
Done.
| |
| 729 var testRandomValue = 0.31415926; | |
| 730 | |
| 731 function createTestAttempStorageEntry(delaySeconds) { | |
| 732 // Creates a test storage object that attempt manager uses to store current | |
| 733 // delay. | |
| 734 var storageObject = {}; | |
| 735 storageObject[testAttemptStorageKey] = delaySeconds; | |
| 736 return storageObject; | |
| 737 } | |
| 738 | |
| 739 function setupAttemptManagerTest(fixture) { | |
| 740 Math.random = function() { return testRandomValue; } | |
| 741 | |
| 742 fixture.makeMockLocalFunctions([ | |
| 743 'attempt', | |
| 744 'planForNextCallback', | |
| 745 'isRunningCallback' | |
| 746 ]); | |
| 747 fixture.makeAndRegisterMockApis([ | |
| 748 'chrome.alarms.clear', | |
| 749 'chrome.alarms.create', | |
| 750 'chrome.storage.local.remove', | |
| 751 'chrome.storage.local.set', | |
| 752 'instrumented.alarms.get', | |
| 753 'instrumented.storage.local.get' | |
| 754 ]); | |
| 755 | |
| 756 var testAttempts = buildAttemptManager( | |
| 757 'testAttempts', | |
| 758 fixture.mockLocalFunctions.functions().attempt, | |
| 759 testInitialDelaySeconds, | |
| 760 testMaximumDelaySeconds); | |
| 761 Mock4JS.verifyAllMocks(); | |
| 762 | |
| 763 return { | |
| 764 attempts: testAttempts | |
| 765 }; | |
| 766 } | |
| 767 | |
| 768 TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerStartStop', function() { | |
| 769 // Tests starting and stopping an attempt manager. | |
| 770 | |
| 771 // Setup. | |
| 772 var test = setupAttemptManagerTest(this); | |
| 773 | |
| 774 // Step 1. Checking that attempt manager is not running. | |
| 775 // Expectations. | |
| 776 var alarmsGetSavedArgs = new SaveMockArguments(); | |
| 777 this.mockApis.expects(once()). | |
| 778 instrumented_alarms_get( | |
| 779 alarmsGetSavedArgs.match(eq(testAttemptAlarmName)), | |
| 780 alarmsGetSavedArgs.match(ANYTHING)). | |
| 781 will(invokeCallback(alarmsGetSavedArgs, 1, undefined)); | |
| 782 this.mockLocalFunctions.expects(once()).isRunningCallback(false); | |
| 783 // Invocation. | |
| 784 test.attempts.isRunning( | |
| 785 this.mockLocalFunctions.functions().isRunningCallback); | |
| 786 Mock4JS.verifyAllMocks(); | |
| 787 | |
| 788 // Step 2. Starting attempt manager with no parameters. | |
| 789 // Expectations. | |
| 790 var expectedRetryDelaySeconds = | |
| 791 testInitialDelaySeconds * (1 + testRandomValue * 0.2); | |
| 792 this.mockApis.expects(once()).chrome_alarms_create( | |
| 793 testAttemptAlarmName, | |
| 794 eqJSON({ | |
| 795 delayInMinutes: expectedRetryDelaySeconds / 60, | |
| 796 periodInMinutes: testMaximumDelaySeconds / 60 | |
| 797 })); | |
| 798 this.mockApis.expects(once()).chrome_storage_local_set( | |
| 799 eqJSON(createTestAttempStorageEntry(expectedRetryDelaySeconds))); | |
| 800 // Invocation. | |
| 801 test.attempts.start(); | |
| 802 Mock4JS.verifyAllMocks(); | |
| 803 | |
| 804 // Step 3. Checking that attempt manager is running. | |
| 805 // Expectations. | |
| 806 alarmsGetSavedArgs = new SaveMockArguments(); | |
| 807 this.mockApis.expects(once()). | |
| 808 instrumented_alarms_get( | |
| 809 alarmsGetSavedArgs.match(eq(testAttemptAlarmName)), | |
| 810 alarmsGetSavedArgs.match(ANYTHING)). | |
| 811 will(invokeCallback(alarmsGetSavedArgs, 1, {testField: 'TEST VALUE'})); | |
| 812 this.mockLocalFunctions.expects(once()).isRunningCallback(true); | |
| 813 // Invocation. | |
| 814 test.attempts.isRunning( | |
| 815 this.mockLocalFunctions.functions().isRunningCallback); | |
| 816 Mock4JS.verifyAllMocks(); | |
| 817 | |
| 818 // Step 4. Stopping task manager. | |
| 819 // Expectations. | |
| 820 this.mockApis.expects(once()).chrome_alarms_clear(testAttemptAlarmName); | |
| 821 this.mockApis.expects(once()).chrome_storage_local_remove( | |
| 822 testAttemptStorageKey); | |
| 823 // Invocation. | |
| 824 test.attempts.stop(); | |
| 825 }); | |
| 826 | |
| 827 TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerStartWithParam', function() { | |
| 828 // Tests starting an attempt manager with a parameter. | |
| 829 | |
| 830 // Setup. | |
| 831 var test = setupAttemptManagerTest(this); | |
| 832 var testFirstDelaySeconds = 1039; | |
| 833 | |
| 834 // Starting attempt manager with a parameter specifying first delay. | |
| 835 // Expectations. | |
| 836 this.mockApis.expects(once()).chrome_alarms_create( | |
| 837 testAttemptAlarmName, | |
| 838 eqJSON({ | |
| 839 delayInMinutes: testFirstDelaySeconds / 60, | |
| 840 periodInMinutes: testMaximumDelaySeconds / 60 | |
| 841 })); | |
| 842 this.mockApis.expects(once()).chrome_storage_local_remove( | |
| 843 testAttemptStorageKey); | |
| 844 // Invocation. | |
| 845 test.attempts.start(testFirstDelaySeconds); | |
| 846 }); | |
| 847 | |
| 848 TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerExponGrowth', function() { | |
| 849 // Tests that retry time grows exponentially. | |
| 850 | |
| 851 // Setup. | |
| 852 var test = setupAttemptManagerTest(this); | |
| 853 var testStoredRetryDelay = 433; | |
| 854 | |
| 855 // Call planForNext, which prepares next attempt. Current retry time | |
| 856 // is less than 1/2 of the maximum delay. | |
| 857 // Expectations. | |
| 858 var expectedRetryDelaySeconds = | |
| 859 testStoredRetryDelay * 2 * (1 + testRandomValue * 0.2); | |
| 860 var storageGetSavedArgs = new SaveMockArguments(); | |
| 861 this.mockApis.expects(once()).instrumented_storage_local_get( | |
| 862 storageGetSavedArgs.match(eq(testAttemptStorageKey)), | |
| 863 storageGetSavedArgs.match(ANYTHING)). | |
| 864 will(invokeCallback( | |
| 865 storageGetSavedArgs, | |
| 866 1, | |
| 867 createTestAttempStorageEntry(testStoredRetryDelay))); | |
| 868 this.mockApis.expects(once()).chrome_alarms_create( | |
| 869 testAttemptAlarmName, | |
| 870 eqJSON({ | |
| 871 delayInMinutes: expectedRetryDelaySeconds / 60, | |
| 872 periodInMinutes: testMaximumDelaySeconds / 60})); | |
| 873 this.mockApis.expects(once()).chrome_storage_local_set( | |
| 874 eqJSON(createTestAttempStorageEntry(expectedRetryDelaySeconds))); | |
| 875 this.mockLocalFunctions.expects(once()).planForNextCallback(); | |
| 876 // Invocation. | |
| 877 test.attempts.planForNext( | |
| 878 this.mockLocalFunctions.functions().planForNextCallback); | |
| 879 }); | |
| 880 | |
| 881 TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerGrowthLimit', function() { | |
| 882 // Tests that retry time stops growing at the maximum value. | |
| 883 | |
| 884 // Setup. | |
| 885 var test = setupAttemptManagerTest(this); | |
| 886 var testStoredRetryDelay = 1500; | |
| 887 | |
| 888 // Call planForNext, which prepares next attempt. Current retry time | |
| 889 // is greater than 1/2 of the maximum delay. | |
| 890 // Expectations. | |
| 891 var expectedRetryDelaySeconds = testMaximumDelaySeconds; | |
| 892 var storageGetSavedArgs = new SaveMockArguments(); | |
| 893 this.mockApis.expects(once()). | |
| 894 instrumented_storage_local_get( | |
| 895 storageGetSavedArgs.match(eq(testAttemptStorageKey)), | |
| 896 storageGetSavedArgs.match(ANYTHING)). | |
| 897 will(invokeCallback( | |
| 898 storageGetSavedArgs, | |
| 899 1, | |
| 900 createTestAttempStorageEntry(testStoredRetryDelay))); | |
| 901 this.mockApis.expects(once()).chrome_alarms_create( | |
| 902 testAttemptAlarmName, | |
| 903 eqJSON({ | |
| 904 delayInMinutes: expectedRetryDelaySeconds / 60, | |
| 905 periodInMinutes: testMaximumDelaySeconds / 60 | |
| 906 })); | |
| 907 this.mockApis.expects(once()).chrome_storage_local_set( | |
| 908 eqJSON(createTestAttempStorageEntry(expectedRetryDelaySeconds))); | |
| 909 this.mockLocalFunctions.expects(once()).planForNextCallback(); | |
| 910 // Invocation. | |
| 911 test.attempts.planForNext( | |
| 912 this.mockLocalFunctions.functions().planForNextCallback); | |
| 913 }); | |
| 914 | |
| 915 TEST_F('GoogleNowUtilityUnitTest', 'AttemptManagerAlarm', function() { | |
| 916 // Tests that firing the alarm invokes the attempt. | |
| 917 | |
| 918 // Setup. | |
| 919 var test = setupAttemptManagerTest(this); | |
| 920 var onAlarmHandlerContainer = getMockHandlerContainer('alarms.onAlarm'); | |
| 921 assertEquals(1, onAlarmHandlerContainer.length); | |
| 922 | |
| 923 // Fire the alarm and check that this invokes the attemp callback. | |
| 924 // Expectations. | |
| 925 var alarmsGetSavedArgs = new SaveMockArguments(); | |
| 926 this.mockApis.expects(once()). | |
| 927 instrumented_alarms_get( | |
| 928 alarmsGetSavedArgs.match(eq(testAttemptAlarmName)), | |
| 929 alarmsGetSavedArgs.match(ANYTHING)). | |
| 930 will(invokeCallback(alarmsGetSavedArgs, 1, {testField: 'TEST VALUE'})); | |
| 931 this.mockLocalFunctions.expects(once()).attempt(); | |
| 932 // Invocation. | |
| 933 onAlarmHandlerContainer[0]({name: testAttemptAlarmName}); | |
| 934 }); | |
| OLD | NEW |