I have a bug in the ICE Code Editor. That is nothing new, all projects have bugs in them. But this particular bug has been tough to isolate and I suspect that it is because of varying latencies when used on a production system.
The problem manifests itself when a new user of the ICE Code Editor follows a shared link. Shared links in ICE are Gzip encoded strings of the content in a code project. The Gzip string is encoded with base64 and jammed into a URL hash like so:
http://gamingjs.com/ice/#B/88gvT6nUUXDKT1IEAA==. ICE tries to decode this, but—sometimes—will get the following error:
Uncaught Error: NoSuchMethodError : method not found: 'RawDeflate'The missing
RawDeflate. My guess is that latency between me and the gamingjs.com site is to blame. Only I cannot reproduce the problem locally.
Well, of course I cannot reproduce locally—there is no latency on a local system, right? Actually, I can use the Linux traffic control utility
tcto add any latency to the loopback device:
$ sudo tc qdisc add dev lo root netem delay 200msWith that, the round-trip time for packets to and from
➜ ~ ping localhost PING localhost (127.0.0.1) 56(84) bytes of data. 64 bytes from localhost (127.0.0.1): icmp_req=1 ttl=64 time=400 ms 64 bytes from localhost (127.0.0.1): icmp_req=2 ttl=64 time=400 msThat ought to be more than enough to reproduce latency issues. But it is not.
I am eventually able to get this to work fairly reliably—but still not regularly—going against the gamingjs.com site. I add latency to my wireless network device:
sudo tc qdisc add dev eth1 root netem delay 200msAnd can see the problem more often than not in Firefox. And when I do reproduce, I find that my hypothesis was correct. The
RawDeflate.jslibrary is not loading in time:
Last night I added a future that completes when Rawdeflate loads, meaning that I can delay URL hash parsing until Rawdeflate is available. But how do I test this to make sure that I have really solved my problem?
I could add latency to my Dart unittests, but even that may not be enough. I cannot reproduce the error in Chrome. It seems that Chrome's pipes are a bit warmer than Firefox's:
I think the main problem is that Chrome's warmest pipe (yes, I'm serious about warm pipes—read SPDY Book!) is used for the source map file. The remaining colder pipes are used for ACE and the deflate libraries. Since ACE is loaded over a cold pipe and because it is large, it does not finish loading until after the smaller Rawdeflate. In Firefox on the other hand, the hot pipe is used for ace, which means that the ace library loads, triggering all those futures, before rawdeflate can load over that cold pipe.
So I am out of luck, right? Nope!
I can borrow a trick from gamingjs.com in order to fake the kind of latency behavior that I want. That trick is application cache. I add a
latency.appcachemanifest file to my local ICE page:
<!DOCTYPE html> <html manifest="editor.appcache"> <!-- Dart scripts as before --> </html>And in that manifest, I add a single file—the
ace.jsthat I need to load before Rawdeflate:
CACHE MANIFEST # 2013-09-04 CACHE: /packages/ice_code_editor/js/ace/ace.js NETWORK: *And that actually works:
The error is generated locally thanks to a combination of application cache and
tc-induced latency (and yes, the artificial latency is needed).
This will not quite work in my test suite. I use
content_shellto run browser-based Dart unittests. I verify that
content_shelldoes honor application cache and can reproduce my error:
➜ ice-code-editor git:(master) ✗ content_shell \ --dump-render-tree \ 'http://localhost:8080/full.html#B/88gvT6nUUXDKT1IEAA==' CONSOLE MESSAGE: Uncaught Error: NoSuchMethodError : method not found: 'RawDeflate' Receiver: top-level Arguments:  CONSOLE MESSAGE: Stack Trace: #0 Proxy._forward (package:js/js.dart:1038:20) #1 Proxy.noSuchMethod (package:js/js.dart:1027:20) #2 Gzip.decode (package:ice_code_editor/gzip.dart:12:23) #3 Full._openProject (package:ice_code_editor/full.dart:239:28) #4 Full.Full.<anonymous closure> (package:ice_code_editor/full.dart:25:32) ...The problem is that I usually run
file://URLs. Application cache directives are ignored unless the web page is served from a web server. So I will need to come up with a robust solution for regression testing of asynchronous script load issues tomorrow.
But as far as I can tell from my work tonight, it ought to be possible.