<!DOCTYPE HTML> <html> <!-- https://bugzilla.mozilla.org/show_bug.cgi?id=338583 --> <head> <meta http-equiv='Content-Type' content='text/html; charset=utf-8'> <title>Test for Bug 338583</title> <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> </head> <body bgColor=white> <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=338583">Mozilla Bug 338583</a> <p id="display"></p> <div id="content" style="display: none"> </div> <pre id="test"> <script class="testbody" type="text/javascript"> /** Tests for Bug 338583 **/ // we test: // 1) the EventSource behaviour // 2) if the events are trusted // 3) possible invalid eventsources // 4) the close method when the object is just been used // 5) access-control // 6) the data parameter // 7) delayed server responses // -- var gTestsHaveFinished = []; function setTestHasFinished(test_id) { if (gTestsHaveFinished[test_id]) { return; } gTestsHaveFinished[test_id] = true; for (var i=0; i < gTestsHaveFinished.length; ++i) { if (!gTestsHaveFinished[i]) { return; } } SimpleTest.finish(); } function runAllTests() { // these tests run asynchronously, and they will take 8000 ms var all_tests = [ doTest1, doTest1_e, doTest1_f, doTest2, doTest3, doTest3_b, doTest3_c, doTest3_d, doTest3_e, doTest3_f, doTest3_g, doTest3_h, doTest4, doTest4_b, doTest5, doTest5_b, doTest5_c, doTest5_e, doTest6, doTest7 ]; for (var test_id=0; test_id < all_tests.length; ++test_id) { gTestsHaveFinished[test_id] = false; var fn = all_tests[test_id]; fn(test_id); } setTimeout(function() { for (var test_id=0; test_id < all_tests.length; ++test_id) { if (!gTestsHaveFinished[test_id]) { ok(false, "Test " + test_id + " took too long"); setTestHasFinished(test_id); } } }, 60000 * stress_factor); // all tests together are supposed to take less than 1 minute } function fn_onmessage(e) { if (e.currentTarget == e.target && e.target.hits != null) e.target.hits['fn_onmessage']++; } function fn_event_listener_message(e) { if (e.currentTarget == e.target && e.target.hits != null) e.target.hits['fn_event_listener_message']++; } function fn_other_event_name(e) { if (e.currentTarget == e.target && e.target.hits != null) e.target.hits['fn_other_event_name']++; } var gEventSourceObj1 = null, gEventSourceObj1_e, gEventSourceObj1_f; var gEventSourceObj2 = null; var gEventSourceObj3_a = null, gEventSourceObj3_b = null, gEventSourceObj3_c = null, gEventSourceObj3_d = null, gEventSourceObj3_e = null, gEventSourceObj3_f = null, gEventSourceObj3_g = null, gEventSourceObj3_h = null; var gEventSourceObj4_a = null, gEventSourceObj4_b = null; var gEventSourceObj5_a = null, gEventSourceObj5_b = null, gEventSourceObj5_c = null, gEventSourceObj5_d = null, gEventSourceObj5_e = null, gEventSourceObj5_f = null; var gEventSourceObj6 = null; var gEventSourceObj7 = null; var stress_factor; // used in the setTimeouts in order to help // the test when running in slow machines function hasBeenHitFor1And2(obj, min) { if (obj.hits['fn_onmessage'] < min || obj.hits['fn_event_listener_message'] < min || obj.hits['fn_other_event_name'] < min) return false; return true; } // in order to test (1): // a) if the EventSource constructor parameter is equal to its url attribute // b) let its fn_onmessage, fn_event_listener_message, and fn_other_event_name functions listeners be hit four times each // c) the close method (we expect readyState == CLOSED) // d) the close method (we expect no message events anymore) // e) use the default for withCredentials when passing dictionary arguments that don't explicitly set it // f) if a 204 HTTP response closes (interrupts) connections. See bug 869432. function doTest1(test_id) { gEventSourceObj1 = new EventSource("eventsource.resource"); ok(gEventSourceObj1.url == "http://mochi.test:8888/tests/dom/base/test/eventsource.resource", "Test 1.a failed."); ok(gEventSourceObj1.readyState == 0 || gEventSourceObj1.readyState == 1, "Test 1.a failed."); doTest1_b(test_id); } function doTest1_b(test_id) { gEventSourceObj1.hits = []; gEventSourceObj1.hits['fn_onmessage'] = 0; gEventSourceObj1.onmessage = fn_onmessage; gEventSourceObj1.hits['fn_event_listener_message'] = 0; gEventSourceObj1.addEventListener('message', fn_event_listener_message, true); gEventSourceObj1.hits['fn_other_event_name'] = 0; gEventSourceObj1.addEventListener('other_event_name', fn_other_event_name, true); // the eventsources.res always use a retry of 0.5 second, so for four hits a timeout of 6 seconds is enough setTimeout(function(){ bhits = hasBeenHitFor1And2(gEventSourceObj1, 4); ok(bhits, "Test 1.b failed."); doTest1_c(test_id); }, parseInt(6000*stress_factor)); } function doTest1_c(test_id) { gEventSourceObj1.close(); ok(gEventSourceObj1.readyState == 2, "Test 1.c failed."); doTest1_d(test_id); } function doTest1_d(test_id) { gEventSourceObj1.hits['fn_onmessage'] = 0; gEventSourceObj1.hits['fn_event_listener_message'] = 0; gEventSourceObj1.hits['fn_other_event_name'] = 0; setTimeout(function(){ bhits = hasBeenHitFor1And2(gEventSourceObj1, 1); ok(!bhits, "Test 1.d failed."); gEventSourceObj1.close(); setTestHasFinished(test_id); }, parseInt(2000*stress_factor)); } function doTest1_e(test_id) { try { for (var options of [null, undefined, {}]) { gEventSourceObj1_e = new EventSource("eventsource.resource", options); is(gEventSourceObj1_e.withCredentials, false, "withCredentials should default to false"); gEventSourceObj1_e.close(); } } catch (e) { ok(false, "Test 1.e failed"); } setTestHasFinished(test_id); } function doTest1_f(test_id) { var called_on_error = false; gEventSourceObj1_f = new EventSource("file_bug869432.eventsource"); gEventSourceObj1_f.onopen = function(e) { ok(false, "Test 1.f failed: onopen was called"); }; gEventSourceObj1_f.onmessage = function(e) { ok(false, "Test 1.f failed: onmessage was called"); }; gEventSourceObj1_f.onerror = function(e) { if (called_on_error) { ok(false, "Test 1.f failed: onerror was called twice"); } called_on_error = true; ok(gEventSourceObj1_f.readyState == 2, "Test 1.f failed: onerror was called with readyState = " + gEventSourceObj1_f.readyState); }; setTimeout(function() { // just to clean... ok(called_on_error, "Test 1.f failed: onerror was not called"); setTestHasFinished(test_id); }, parseInt(5000*stress_factor)); } // in order to test (2) // a) set a eventsource that give the dom events messages // b) expect trusted events function doTest2(test_id) { var func = function(e) { ok(e.isTrusted, "Test 2 failed"); gEventSourceObj2.close(); }; gEventSourceObj2 = new EventSource("eventsource.resource"); gEventSourceObj2.onmessage = func; setTimeout(function() { // just to clean... gEventSourceObj2.close(); setTestHasFinished(test_id); }, parseInt(5000*stress_factor)); } // in order to test (3) // a) XSite domain error test // b) protocol file:// test // c) protocol javascript: test // d) wrong Content-Type test // e) bad http response code test // f) message eventsource without a data test // g) DNS error // h) EventSource which last message doesn't end with an empty line. See bug 710546 function doTest3(test_id) { gEventSourceObj3_a = new EventSource("http://example.org/tests/dom/base/test/eventsource.resource"); gEventSourceObj3_a.onmessage = fn_onmessage; gEventSourceObj3_a.hits = []; gEventSourceObj3_a.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj3_a.hits['fn_onmessage'] == 0, "Test 3.a failed"); gEventSourceObj3_a.close(); setTestHasFinished(test_id); }, parseInt(1500*stress_factor)); } function doTest3_b(test_id) { // currently no support yet for local files for b2g/Android mochitest, see bug 838726 if (navigator.appVersion.indexOf("Android") != -1 || SpecialPowers.Services.appinfo.name == "B2G") { setTestHasFinished(test_id); return; } var xhr = new XMLHttpRequest; xhr.open("GET", "/dynamic/getMyDirectory.sjs", false); xhr.send(); var basePath = xhr.responseText; gEventSourceObj3_b = new EventSource("file://" + basePath + "eventsource.resource"); gEventSourceObj3_b.onmessage = fn_onmessage; gEventSourceObj3_b.hits = []; gEventSourceObj3_b.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj3_b.hits['fn_onmessage'] == 0, "Test 3.b failed"); gEventSourceObj3_b.close(); setTestHasFinished(test_id); }, parseInt(1500*stress_factor)); } function jsEvtSource() { return "event: message\n" + "data: 1\n\n"; } function doTest3_c(test_id) { gEventSourceObj3_c = new EventSource("javascript: return jsEvtSource()"); gEventSourceObj3_c.onmessage = fn_onmessage; gEventSourceObj3_c.hits = []; gEventSourceObj3_c.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj3_c.hits['fn_onmessage'] == 0, "Test 3.c failed"); gEventSourceObj3_c.close(); setTestHasFinished(test_id); }, parseInt(1500*stress_factor)); } function doTest3_d(test_id) { gEventSourceObj3_d = new EventSource("badContentType.eventsource"); gEventSourceObj3_d.onmessage = fn_onmessage; gEventSourceObj3_d.hits = []; gEventSourceObj3_d.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj3_d.hits['fn_onmessage'] == 0, "Test 3.d failed"); gEventSourceObj3_d.close(); setTestHasFinished(test_id); }, parseInt(1500*stress_factor)); } function doTest3_e(test_id) { gEventSourceObj3_e = new EventSource("badHTTPResponseCode.eventsource"); gEventSourceObj3_e.onmessage = fn_onmessage; gEventSourceObj3_e.hits = []; gEventSourceObj3_e.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj3_e.hits['fn_onmessage'] == 0, "Test 3.e failed"); gEventSourceObj3_e.close(); setTestHasFinished(test_id); }, parseInt(1500*stress_factor)); } function doTest3_f(test_id) { gEventSourceObj3_f = new EventSource("badMessageEvent.eventsource"); gEventSourceObj3_f.onmessage = fn_onmessage; gEventSourceObj3_f.hits = []; gEventSourceObj3_f.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj3_f.hits['fn_onmessage'] == 0, "Test 3.f failed"); gEventSourceObj3_f.close(); setTestHasFinished(test_id); }, parseInt(1500*stress_factor)); } function fnInvalidNCName() { fnInvalidNCName.hits++; } function doTest3_g(test_id) { gEventSourceObj3_g = new EventSource("http://hdfskjghsbg.jtiyoejowe.dafsgbhjab.com"); gEventSourceObj3_g.onmessage = fn_onmessage; gEventSourceObj3_g.hits = []; gEventSourceObj3_g.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj3_g.hits['fn_onmessage'] == 0, "Test 3.g failed"); gEventSourceObj3_g.close(); setTestHasFinished(test_id); }, parseInt(1500*stress_factor)); } function fnMessageListenerTest3h(e) { fnMessageListenerTest3h.msg_ok = (fnMessageListenerTest3h.msg_ok && e.data == "ok"); fnMessageListenerTest3h.id_ok = (fnMessageListenerTest3h.id_ok && e.lastEventId == ""); } function doTest3_h(test_id) { gEventSourceObj3_h = new EventSource("badMessageEvent2.eventsource"); gEventSourceObj3_h.addEventListener('message', fnMessageListenerTest3h, true); fnMessageListenerTest3h.msg_ok = true; fnMessageListenerTest3h.id_ok = true; gEventSourceObj3_h.onmessage = fn_onmessage; gEventSourceObj3_h.hits = []; gEventSourceObj3_h.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj3_h.hits['fn_onmessage'] > 1, "Test 3.h.1 failed"); if (gEventSourceObj3_h.hits['fn_onmessage'] > 1) { ok(fnMessageListenerTest3h.msg_ok, "Test 3.h.2 failed"); ok(fnMessageListenerTest3h.id_ok, "Test 3.h.3 failed"); } gEventSourceObj3_h.close(); setTestHasFinished(test_id); }, parseInt(6000*stress_factor)); } // in order to test (4) // a) close the object when it is in use, which is being processed and that is expected // to dispatch more eventlisteners // b) remove an eventlistener in use function fn_onmessage4_a(e) { if (e.data > gEventSourceObj4_a.lastData) gEventSourceObj4_a.lastData = e.data; if (e.data == 2) gEventSourceObj4_a.close(); } function fn_onmessage4_b(e) { if (e.data > gEventSourceObj4_b.lastData) gEventSourceObj4_b.lastData = e.data; if (e.data == 2) gEventSourceObj4_b.removeEventListener('message', fn_onmessage4_b, true); } function doTest4(test_id) { gEventSourceObj4_a = new EventSource("forRemoval.resource"); gEventSourceObj4_a.lastData = 0; gEventSourceObj4_a.onmessage = fn_onmessage4_a; setTimeout(function() { ok(gEventSourceObj4_a.lastData == 2, "Test 4.a failed"); gEventSourceObj4_a.close(); setTestHasFinished(test_id); }, parseInt(3000*stress_factor)); } function doTest4_b(test_id) { gEventSourceObj4_b = new EventSource("forRemoval.resource"); gEventSourceObj4_b.lastData = 0; gEventSourceObj4_b.addEventListener('message', fn_onmessage4_b, true); setTimeout(function() { ok(gEventSourceObj4_b.lastData == 2, "Test 4.b failed"); gEventSourceObj4_b.close(); setTestHasFinished(test_id); }, parseInt(3000*stress_factor)); } // in order to test (5) // a) valid access-control xsite request // b) invalid access-control xsite request // c) valid access-control xsite request on a restricted page with credentials // d) valid access-control xsite request on a restricted page without credentials // e) valid access-control xsite request on a restricted page when the parameter withCredentials is a getter // f) valid access-control xsite request on a restricted page when the parameter withCredentials is missing function doTest5(test_id) { gEventSourceObj5_a = new EventSource("http://example.org/tests/dom/base/test/accesscontrol.resource"); gEventSourceObj5_a.onmessage = fn_onmessage; gEventSourceObj5_a.hits = []; gEventSourceObj5_a.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj5_a.hits['fn_onmessage'] != 0, "Test 5.a failed"); gEventSourceObj5_a.close(); setTestHasFinished(test_id); }, parseInt(3000*stress_factor)); } function doTest5_b(test_id) { gEventSourceObj5_b = new EventSource("http://example.org/tests/dom/base/test/invalid_accesscontrol.resource"); gEventSourceObj5_b.onmessage = fn_onmessage; gEventSourceObj5_b.hits = []; gEventSourceObj5_b.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj5_b.hits['fn_onmessage'] == 0, "Test 5.b failed"); gEventSourceObj5_b.close(); setTestHasFinished(test_id); }, parseInt(3000*stress_factor)); } function doTest5_c(test_id) { // credentials using the auth cache var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true}); // also, test mixed mode UI xhr.open("GET", "https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_xhr", true, "user 1", "password 1"); xhr.send(); xhr.onloadend = function() { ok(xhr.status == 200, "Failed to set credentials in test 5.c"); gEventSourceObj5_c = new EventSource("https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_evtsrc", { withCredentials: true } ); ok(gEventSourceObj5_c.withCredentials, "Wrong withCredentials in test 5.c"); gEventSourceObj5_c.onmessage = function(e) { ok(e.origin == "https://example.com", "Wrong Origin in test 5.c"); fn_onmessage(e); }; gEventSourceObj5_c.hits = []; gEventSourceObj5_c.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj5_c.hits['fn_onmessage'] > 0, "Test 5.c failed"); gEventSourceObj5_c.close(); doTest5_d(test_id); }, parseInt(3000*stress_factor)); }; } function doTest5_d(test_id) { var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true}); xhr.open("GET", "https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_xhr", true, "user 2", "password 2"); xhr.send(); xhr.onloadend = function() { ok(xhr.status == 200, "Failed to set credentials in test 5.d"); gEventSourceObj5_d = new EventSource("https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_evtsrc"); ok(!gEventSourceObj5_d.withCredentials, "Wrong withCredentials in test 5.d"); gEventSourceObj5_d.onmessage = function(e) { ok(e.origin == "https://example.com", "Wrong Origin in test 5.d"); fn_onmessage(e); }; gEventSourceObj5_d.hits = []; gEventSourceObj5_d.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj5_d.hits['fn_onmessage'] == 0, "Test 5.d failed"); gEventSourceObj5_d.close(); setTestHasFinished(test_id); }, parseInt(3000*stress_factor)); }; } function doTest5_e(test_id) { // credentials using the auth cache var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true}); xhr.open("GET", "http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_xhr", true, "user 1", "password 1"); xhr.send(); xhr.onloadend = function() { ok(xhr.status == 200, "Failed to set credentials in test 5.e"); gEventSourceObj5_e = new EventSource("http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_evtsrc", { get withCredentials() { return true; } } ); ok(gEventSourceObj5_e.withCredentials, "Wrong withCredentials in test 5.e"); gEventSourceObj5_e.onmessage = function(e) { ok(e.origin == "http://example.org", "Wrong Origin in test 5.e"); fn_onmessage(e); }; gEventSourceObj5_e.hits = []; gEventSourceObj5_e.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj5_e.hits['fn_onmessage'] > 0, "Test 5.e failed"); gEventSourceObj5_e.close(); doTest5_f(test_id); }, parseInt(5000*stress_factor)); }; } function doTest5_f(test_id) { var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true}); xhr.open("GET", "http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_xhr", true, "user 2", "password 2"); xhr.send(); xhr.onloadend = function() { ok(xhr.status == 200, "Failed to set credentials in test 5.f"); gEventSourceObj5_f = new EventSource("http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_evtsrc", { }); ok(!gEventSourceObj5_f.withCredentials, "Wrong withCredentials in test 5.f"); gEventSourceObj5_f.onmessage = function(e) { ok(e.origin == "http://example.org", "Wrong Origin in test 5.f"); fn_onmessage(e); }; gEventSourceObj5_f.hits = []; gEventSourceObj5_f.hits['fn_onmessage'] = 0; setTimeout(function() { ok(gEventSourceObj5_f.hits['fn_onmessage'] == 0, "Test 5.f failed"); gEventSourceObj5_f.close(); setTestHasFinished(test_id); }, parseInt(3000*stress_factor)); }; } function doTest6(test_id) { gEventSourceObj6 = new EventSource("somedatas.resource"); var fn_somedata = function(e) { if (fn_somedata.expected == 0) { ok(e.data == "123456789\n123456789123456789\n123456789123456789123456789123456789\n 123456789123456789123456789123456789123456789123456789123456789123456789\nçãá\"\'@`~Ý Ḿyyyy", "Test 6.a failed"); } else if (fn_somedata.expected == 1) { ok(e.data == " :xxabcdefghij\nçãá\"\'@`~Ý Ḿyyyy : zz", "Test 6.b failed"); gEventSourceObj6.close(); } else { ok(false, "Test 6 failed (unexpected message event)"); } fn_somedata.expected++; } fn_somedata.expected = 0; gEventSourceObj6.onmessage = fn_somedata; setTimeout(function() { gEventSourceObj6.close(); setTestHasFinished(test_id); }, parseInt(2500*stress_factor)); } function doTest7(test_id) { gEventSourceObj7 = new EventSource("delayedServerEvents.sjs"); gEventSourceObj7.msg_received = []; gEventSourceObj7.onmessage = function(e) { e.target.msg_received.push(e.data); } setTimeout(function() { gEventSourceObj7.close(); ok(gEventSourceObj7.msg_received[0] == "" && gEventSourceObj7.msg_received[1] == "delayed1" && gEventSourceObj7.msg_received[2] == "delayed2", "Test 7 failed"); document.getElementById('waitSpan').innerHTML = ''; setTestHasFinished(test_id); }, parseInt(8000*stress_factor)); } function doTest() { // Allow all cookies, then run the actual test SpecialPowers.pushPrefEnv({"set": [["network.cookie.cookieBehavior", 0]]}, function() { SpecialPowers.pushPermissions([{'type': 'systemXHR', 'allow': true, 'context': document}], doTestCallback); }); } function doTestCallback() { // we get a good stress_factor by testing 10 setTimeouts and some float // arithmetic taking my machine as stress_factor==1 (time=589) var begin_time = (new Date()).getTime(); var f = function() { for (var j=0; j<f.i; ++j) eval("Math.log(Math.atan(Math.sqrt(Math.pow(3.1415, 13.1415))/0.0007))"); if (f.i < 10) { f.i++; setTimeout(f, 10 + 10*f.i); } else { stress_factor = ((new Date()).getTime()-begin_time)*1/589; stress_factor *= 1.50; // also, a margin of 50% runAllTests(); } } f.i = 0; setTimeout(f, 10); } SimpleTest.waitForExplicitFinish(); SimpleTest.requestFlakyTimeout("untriaged"); addLoadEvent(doTest); </script> </pre> <span id=waitSpan>Wait please...</span> </body> </html>