middleman 2.0.9.pre.2 → 2.0.9.pre.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/CHANGELOG +9 -0
  2. data/features/builder.feature +6 -0
  3. data/features/data.feature +16 -1
  4. data/features/fonts.feature +11 -0
  5. data/features/relative_assets.feature +8 -2
  6. data/features/step_definitions/middleman_steps.rb +9 -2
  7. data/fixtures/data-app/config.rb +3 -0
  8. data/fixtures/data-app/data/pages.yml +6 -0
  9. data/fixtures/data-app/source/index.html.haml +1 -0
  10. data/fixtures/data-app/source/layout.haml +3 -0
  11. data/fixtures/fonts-app/config.rb +0 -0
  12. data/fixtures/fonts-app/source/fonts/StMarie-Thin.otf +0 -0
  13. data/fixtures/fonts-app/source/stylesheets/fonts.css.sass +3 -0
  14. data/fixtures/glob-app/config.rb +1 -0
  15. data/fixtures/glob-app/source/index.html.haml +6 -0
  16. data/fixtures/glob-app/source/stylesheets/site.css.sass +1 -0
  17. data/fixtures/test-app/config.rb +1 -0
  18. data/fixtures/test-app/data/test2.json +4 -0
  19. data/fixtures/test-app/source/data3.html.erb +1 -0
  20. data/lib/middleman/base.rb +8 -3
  21. data/lib/middleman/builder.rb +61 -22
  22. data/lib/middleman/cli.rb +2 -1
  23. data/lib/middleman/core_extensions/assets.rb +1 -1
  24. data/lib/middleman/core_extensions/compass.rb +6 -2
  25. data/lib/middleman/core_extensions/data.rb +20 -3
  26. data/lib/middleman/templates/html5.rb +1 -0
  27. data/lib/middleman/templates/mobile.rb +17 -0
  28. data/lib/middleman/templates/mobile/source/404.html +38 -0
  29. data/lib/middleman/templates/mobile/source/README.markdown +64 -0
  30. data/lib/middleman/templates/mobile/source/crossdomain.xml +25 -0
  31. data/lib/middleman/templates/mobile/source/css/style.css +236 -0
  32. data/lib/middleman/templates/mobile/source/default.appcache +17 -0
  33. data/lib/middleman/templates/mobile/source/humans.txt +43 -0
  34. data/lib/middleman/templates/mobile/source/img/h/apple-touch-icon.png +0 -0
  35. data/lib/middleman/templates/mobile/source/img/h/splash.png +0 -0
  36. data/lib/middleman/templates/mobile/source/img/l/apple-touch-icon-precomposed.png +0 -0
  37. data/lib/middleman/templates/mobile/source/img/l/apple-touch-icon.png +0 -0
  38. data/lib/middleman/templates/mobile/source/img/l/splash.png +0 -0
  39. data/lib/middleman/templates/mobile/source/img/m/apple-touch-icon.png +0 -0
  40. data/lib/middleman/templates/mobile/source/index.html +95 -0
  41. data/lib/middleman/templates/mobile/source/js/libs/jquery-1.5.1.js +8316 -0
  42. data/lib/middleman/templates/mobile/source/js/libs/jquery-1.5.1.min.js +16 -0
  43. data/lib/middleman/templates/mobile/source/js/libs/modernizr-custom.js +14 -0
  44. data/lib/middleman/templates/mobile/source/js/libs/respond.min.js +7 -0
  45. data/lib/middleman/templates/mobile/source/js/mylibs/helper.js +147 -0
  46. data/lib/middleman/templates/mobile/source/js/script.js +0 -0
  47. data/lib/middleman/templates/mobile/source/robots.txt +5 -0
  48. data/lib/middleman/templates/mobile/source/sitemap.xml +10 -0
  49. data/lib/middleman/templates/mobile/source/test/index.html +31 -0
  50. data/lib/middleman/templates/mobile/source/test/qunit/qunit.css +148 -0
  51. data/lib/middleman/templates/mobile/source/test/qunit/qunit.js +1265 -0
  52. data/lib/middleman/templates/mobile/source/test/tests.js +26 -0
  53. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/Readme.PDF +0 -0
  54. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/aspx/aspx1.snippet +31 -0
  55. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/aspx/aspx2.snippet +2 -0
  56. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/aspx/ga.aspx +195 -0
  57. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/aspx/sample.aspx +44 -0
  58. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/jsp/ga.jsp +225 -0
  59. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/jsp/jsp1.snippet +35 -0
  60. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/jsp/jsp2.snippet +2 -0
  61. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/jsp/sample.jsp +51 -0
  62. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/php/ga.php +176 -0
  63. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/php/php1.snippet +30 -0
  64. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/php/php2.snippet +4 -0
  65. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/php/sample.php +44 -0
  66. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/pl/ga.pl +195 -0
  67. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/pl/perl1.snippet +27 -0
  68. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/pl/perl2.snippet +1 -0
  69. data/lib/middleman/templates/mobile/source/tools/googleanalyticsformobile/pl/sample.pl +38 -0
  70. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/COPYING +202 -0
  71. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/bookmark_bubble.js +559 -0
  72. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/example/example.html +43 -0
  73. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/example/example.js +57 -0
  74. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/images/arrow.png +0 -0
  75. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/images/close.png +0 -0
  76. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/images/generate_base64_images +33 -0
  77. data/lib/middleman/templates/mobile/source/tools/mobile-bookmark-bubble/images/icon_calendar.png +0 -0
  78. data/lib/middleman/templates/mobile/source/tools/wspl/README +27 -0
  79. data/lib/middleman/templates/mobile/source/tools/wspl/databasefactory.js +45 -0
  80. data/lib/middleman/templates/mobile/source/tools/wspl/dbworker.js +324 -0
  81. data/lib/middleman/templates/mobile/source/tools/wspl/dbworker_test.html +393 -0
  82. data/lib/middleman/templates/mobile/source/tools/wspl/dbworkerstarter.js +32 -0
  83. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapper_gears.js +595 -0
  84. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapper_gears_test.html +404 -0
  85. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapper_html5.js +203 -0
  86. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapper_html5_test.html +468 -0
  87. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapperapi.js +202 -0
  88. data/lib/middleman/templates/mobile/source/tools/wspl/dbwrapperapi_test.html +51 -0
  89. data/lib/middleman/templates/mobile/source/tools/wspl/gears_resultset.js +71 -0
  90. data/lib/middleman/templates/mobile/source/tools/wspl/gears_resultset_test.html +86 -0
  91. data/lib/middleman/templates/mobile/source/tools/wspl/gears_transaction.js +196 -0
  92. data/lib/middleman/templates/mobile/source/tools/wspl/gears_transaction_test.html +221 -0
  93. data/lib/middleman/templates/mobile/source/tools/wspl/gearsutils.js +94 -0
  94. data/lib/middleman/templates/mobile/source/tools/wspl/gearsutils_test.html +84 -0
  95. data/lib/middleman/templates/mobile/source/tools/wspl/global_functions.js +72 -0
  96. data/lib/middleman/templates/mobile/source/tools/wspl/simplenotes/index.html +347 -0
  97. data/lib/middleman/templates/mobile/source/tools/wspl/simplenotes/simplenotes.js +503 -0
  98. data/lib/middleman/templates/mobile/source/tools/wspl/simplenotes/styles.css +66 -0
  99. data/lib/middleman/templates/mobile/source/tools/wspl/simplenotes/template.js +75 -0
  100. data/lib/middleman/version.rb +1 -1
  101. data/middleman-x86-mingw32.gemspec +0 -1
  102. data/middleman.gemspec +3 -2
  103. metadata +116 -51
  104. data/lib/middleman/config.ru +0 -2
  105. data/lib/middleman/features/tiny_src.rb +0 -11
@@ -0,0 +1,393 @@
1
+ <!DOCTYPE html>
2
+ <!--
3
+ Copyright 2009 Google Inc.
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
16
+ -->
17
+
18
+ <html>
19
+ <head>
20
+ <title>Gears worker tests</title>
21
+ <script type="text/javascript" src="../jsunit/app/jsUnitCore.js"></script>
22
+ <script type="text/javascript" src="jsmock.js"></script>
23
+ <script type="text/javascript" src="global_functions.js"></script>
24
+ <script type="text/javascript" src="gearsutils.js"></script>
25
+ <script type="text/javascript" src="dbworker.js"></script>
26
+ </head>
27
+ <body>
28
+ <script type='text/javascript'>
29
+
30
+ var mockControl;
31
+ var db;
32
+ var wp;
33
+ var factory;
34
+ var callbackId = 10;
35
+ var transactionId = 15;
36
+ var name = 'name';
37
+ var userId = 'userId';
38
+ var utils;
39
+
40
+ function setUp() {
41
+ mockControl = new MockControl();
42
+
43
+ // Mock the Gears factory.
44
+ factory = mockControl.createMock();
45
+ factory.addMockMethod('create');
46
+
47
+ // Mock Google Gears.
48
+ google.gears = {};
49
+ google.gears.factory = {};
50
+ google.gears.factory.create = factory.create;
51
+
52
+ // Mock the Gears workerpool object.
53
+ wp = mockControl.createMock({
54
+ allowCrossOrigin: function(){},
55
+ sendMessage: function(){}
56
+ });
57
+
58
+ // Mock the Gears database object.
59
+ db = mockControl.createMock({
60
+ execute: function(){},
61
+ open: function(){},
62
+ close: function(){},
63
+ remove: function(){}
64
+ });
65
+
66
+ // Mock the Gears utility classes
67
+ utils = mockControl.createMock({
68
+ openDatabase: function(){},
69
+ });
70
+
71
+ google.wspl = google.wspl || {};
72
+ google.wspl.GearsUtils = google.wspl.GearsUtils || {};
73
+ google.wspl.GearsUtils.openDatabase = utils.openDatabase;
74
+ google.wspl.GearsUtils.resultSetToObjectArray = function(rs) {
75
+ return rs;
76
+ };
77
+ }
78
+
79
+ function buildWorker() {
80
+ wp.expects().sendMessage(TypeOf.isA(Object), 0).andStub(
81
+ function() {
82
+ var msg = arguments[0];
83
+ assertEquals('Wrong message type.',
84
+ google.wspl.gears.DbWorker.ReplyTypes.STARTED, msg.type);
85
+ });
86
+ var worker = new google.wspl.gears.DbWorker(wp);
87
+ worker.db_ = db;
88
+ worker.log_ = function() {};
89
+
90
+ return worker;
91
+ }
92
+
93
+ function testConstruction() {
94
+ var worker = buildWorker();
95
+ mockControl.verify();
96
+ }
97
+
98
+ function testHandleExecute_success() {
99
+ var worker = buildWorker();
100
+ var stat1 = {sql: 'sql1', params: [1, 2]};
101
+ var stat2 = {sql: 'sql2', params: [3, 4]};
102
+ var statements = [stat1, stat2];
103
+ var type = google.wspl.gears.DbWorker.ReplyTypes.RESULT;
104
+
105
+ db.expects().execute(stat1.sql, stat1.params).andReturn('result1');
106
+ db.expects().execute(stat2.sql, stat2.params).andReturn('result2');
107
+ wp.expects().sendMessage(TypeOf.isA(Object), worker.senderId_).andStub(
108
+ function() {
109
+ var msg = arguments[0];
110
+ assertEquals('Wrong message type.', type, msg.type);
111
+ assertEquals('Wrong results.length', 2, msg.results.length);
112
+ assertEquals('Wrong results[0].', 'result1', msg.results[0]);
113
+ assertEquals('Wrong results[1].', 'result2', msg.results[1]);
114
+ assertEquals('Wrong callbackId.', callbackId, msg.callbackId);
115
+ assertEquals('Wrong transactionId.', transactionId, msg.transactionId);
116
+ });
117
+
118
+ worker.handleExecute_(statements, callbackId, transactionId);
119
+ mockControl.verify();
120
+ }
121
+
122
+ function testHandleExecute_failure() {
123
+ var worker = buildWorker();
124
+ var stat1 = {sql: 'sql1', params: [1, 2]};
125
+ var stat2 = {sql: 'sql2', params: [3, 4]};
126
+ var stat3 = {sql: 'sql3', params: [5, 6]};
127
+ var statements = [stat1, stat2, stat3];
128
+ var type1 = google.wspl.gears.DbWorker.ReplyTypes.RESULT;
129
+ var type2 = google.wspl.gears.DbWorker.ReplyTypes.FAILURE;
130
+ var error = 'sql error';
131
+
132
+ db.expects().execute(stat1.sql, stat1.params).andReturn('result1');
133
+ db.expects().execute(stat2.sql, stat2.params).andThrow(error);
134
+ wp.expects().sendMessage(TypeOf.isA(Object), worker.senderId_).andStub(
135
+ function() {
136
+ var msg = arguments[0];
137
+ assertEquals('Wrong message type.', type2, msg.type);
138
+ assertEquals('Wrong result.', error, msg.error.message);
139
+ assertEquals('Wrong callbackId.', callbackId, msg.callbackId);
140
+ assertEquals('Wrong transactionId.', transactionId, msg.transactionId);
141
+ });
142
+
143
+ worker.handleExecute_(statements, callbackId, transactionId);
144
+ mockControl.verify();
145
+ }
146
+
147
+ function testHandleBegin() {
148
+ var worker = buildWorker();
149
+
150
+ // Expecting two transactions to begin.
151
+ db.expects().execute('BEGIN IMMEDIATE');
152
+ db.expects().execute('BEGIN IMMEDIATE');
153
+
154
+ worker.handleBegin_(transactionId);
155
+ worker.handleBegin_(22);
156
+
157
+ assertEquals('Did not save first transaction id', transactionId,
158
+ worker.transactions_[0]);
159
+ assertEquals('Did not save second transaction id', 22,
160
+ worker.transactions_[1]);
161
+
162
+ mockControl.verify();
163
+ }
164
+
165
+ function testHandleCommit() {
166
+ var worker = buildWorker();
167
+ db.expects().execute('COMMIT');
168
+ worker.handleCommit_(transactionId);
169
+ mockControl.verify();
170
+ }
171
+
172
+ function testHandleRollback() {
173
+ var worker = buildWorker();
174
+ db.expects().execute('ROLLBACK');
175
+ worker.handleRollback_(transactionId);
176
+ mockControl.verify();
177
+ }
178
+
179
+ function testHandleOpen_success() {
180
+ var worker = buildWorker();
181
+ worker.db_ = null;
182
+
183
+ factory.expects().create('beta.database', '1.0').andReturn(db);
184
+ utils.expects().openDatabase(userId, name, db, worker.log_).andReturn(db);
185
+ wp.expects().sendMessage(TypeOf.isA(Object), worker.senderId_).andStub(
186
+ function(msg) {
187
+ assertEquals('Type not set correctly.',
188
+ google.wspl.gears.DbWorker.ReplyTypes.OPEN_SUCCESSFUL, msg.type);
189
+ });
190
+
191
+ worker.handleOpen_(userId, name);
192
+ assertEquals('Database wrongly set', db, worker.db_);
193
+ mockControl.verify();
194
+ }
195
+
196
+ function testHandleOpen_failure_gearsfactory() {
197
+ var worker = buildWorker();
198
+ worker.db_ = null;
199
+
200
+ factory.expects().create('beta.database', '1.0').andThrow('blah!');
201
+ wp.expects().sendMessage(TypeOf.isA(Object), worker.senderId_).andStub(
202
+ function(msg) {
203
+ assertEquals('Type not set correctly.',
204
+ google.wspl.gears.DbWorker.ReplyTypes.OPEN_FAILED, msg.type);
205
+ });
206
+
207
+ worker.handleOpen_(userId, name);
208
+ mockControl.verify();
209
+ }
210
+
211
+ function testHandleOpen_failure_dbopen() {
212
+ var worker = buildWorker();
213
+ worker.db_ = null;
214
+
215
+ factory.expects().create('beta.database', '1.0').andReturn(null);
216
+ utils.expects().openDatabase(userId, name, null, worker.log_).andThrow('blah!');
217
+ wp.expects().sendMessage(TypeOf.isA(Object), worker.senderId_).andStub(
218
+ function(msg) {
219
+ assertEquals('Type not set correctly.',
220
+ google.wspl.gears.DbWorker.ReplyTypes.OPEN_FAILED, msg.type);
221
+ });
222
+
223
+ worker.handleOpen_(userId, name);
224
+ mockControl.verify();
225
+ }
226
+
227
+ function testPostCommit() {
228
+ var worker = buildWorker();
229
+ worker.transactions_ = [4, 5];
230
+
231
+ wp.expects().sendMessage(TypeOf.isA(Object), worker.senderId_).andStub(
232
+ function() {
233
+ var msg = arguments[0];
234
+ assertEquals('Type not set correctly.',
235
+ google.wspl.gears.DbWorker.ReplyTypes.COMMIT, msg.type);
236
+ assertEquals('Transaction id not set correctly.',
237
+ 5, msg.transactionId);
238
+ });
239
+
240
+ wp.expects().sendMessage(TypeOf.isA(Object), worker.senderId_).andStub(
241
+ function() {
242
+ var msg = arguments[0];
243
+ assertEquals('Type not set correctly.',
244
+ google.wspl.gears.DbWorker.ReplyTypes.COMMIT, msg.type);
245
+ assertEquals('Transaction id not set correctly.',
246
+ 4, msg.transactionId);
247
+ });
248
+
249
+ worker.postCommit_();
250
+ assertEquals('Did not clear the transactions.', 0,
251
+ worker.transactions_.length);
252
+ mockControl.verify();
253
+ }
254
+
255
+ function testPostRollback() {
256
+ var worker = buildWorker();
257
+ worker.transactions_ = [4, 5];
258
+
259
+ wp.expects().sendMessage(TypeOf.isA(Object), worker.senderId_).andStub(
260
+ function() {
261
+ var msg = arguments[0];
262
+ assertEquals('Type not set correctly.',
263
+ google.wspl.gears.DbWorker.ReplyTypes.ROLLBACK, msg.type);
264
+ assertEquals('Transaction id not set correctly.',
265
+ 5, msg.transactionId);
266
+ });
267
+
268
+ wp.expects().sendMessage(TypeOf.isA(Object), worker.senderId_).andStub(
269
+ function() {
270
+ var msg = arguments[0];
271
+ assertEquals('Type not set correctly.',
272
+ google.wspl.gears.DbWorker.ReplyTypes.ROLLBACK, msg.type);
273
+ assertEquals('Transaction id not set correctly.',
274
+ 4, msg.transactionId);
275
+ });
276
+
277
+ worker.postRollback_();
278
+ assertEquals('Did not clear the transactions.', 0,
279
+ worker.transactions_.length);
280
+ mockControl.verify();
281
+ }
282
+
283
+ function testOnmessage() {
284
+ var messageObject = {sender: 123, body: {}};
285
+ var worker = buildWorker();
286
+ worker.onMessage_(null, null, messageObject);
287
+
288
+ assertEquals('Wrong sender ID.', 123, worker.senderId_);
289
+
290
+ mockControl.verify();
291
+ }
292
+
293
+ function testOnmessage_open() {
294
+ var messageObject = {sender: 123, body: {
295
+ type: google.wspl.gears.DbWorker.CommandTypes.OPEN,
296
+ name: name,
297
+ userId: userId
298
+ }};
299
+
300
+ var worker = buildWorker();
301
+ var handler = mockControl.createMock();
302
+ handler.addMockMethod('open');
303
+ worker.handleOpen_ = handler.open;
304
+ handler.expects().open(userId, name);
305
+
306
+ worker.onMessage_(null, null, messageObject);
307
+ mockControl.verify();
308
+ }
309
+
310
+ function testOnmessage_execute() {
311
+ var worker = buildWorker();
312
+ var statements = ['stat1', 'stat2'];
313
+ var messageObject = {sender: 123, body: {
314
+ type: google.wspl.gears.DbWorker.CommandTypes.EXECUTE,
315
+ statements: statements,
316
+ callbackId: callbackId,
317
+ transactionId: transactionId
318
+ }};
319
+ var called = false;
320
+
321
+ worker.handleExecute_ = function(stat, call, trans) {
322
+ called = true;
323
+ assertEquals('Wrong statements.', statements, stat);
324
+ assertEquals('Wrong callback id.', callbackId, call);
325
+ assertEquals('Wrong transaction id.', transactionId, trans);
326
+ };
327
+
328
+ worker.onMessage_(null, null, messageObject);
329
+ assertTrue('handleExecute_ not called.', called);
330
+
331
+ mockControl.verify();
332
+ }
333
+
334
+ function testOnmessage_begin() {
335
+ var worker = buildWorker();
336
+ var messageObject = {sender: 123, body: {
337
+ type: google.wspl.gears.DbWorker.CommandTypes.BEGIN,
338
+ transactionId: transactionId
339
+ }};
340
+ var called = false;
341
+
342
+ worker.handleBegin_ = function(trans) {
343
+ called = true;
344
+ assertEquals('Wrong transaction id.', transactionId, trans);
345
+ };
346
+
347
+ worker.onMessage_(null, null, messageObject);
348
+ assertTrue('handleBegin_ not called.', called);
349
+
350
+ mockControl.verify();
351
+ }
352
+
353
+ function testOnmessage_commit() {
354
+ var worker = buildWorker();
355
+ var messageObject = {sender: 123, body: {
356
+ type: google.wspl.gears.DbWorker.CommandTypes.COMMIT,
357
+ transactionId: transactionId
358
+ }};
359
+ var called = false;
360
+
361
+ worker.handleCommit_ = function(trans) {
362
+ called = true;
363
+ assertEquals('Wrong transaction id.', transactionId, trans);
364
+ };
365
+
366
+ worker.onMessage_(null, null, messageObject);
367
+ assertTrue('handleCommit_ not called.', called);
368
+
369
+ mockControl.verify();
370
+ }
371
+
372
+ function testOnmessage_rollback() {
373
+ var worker = buildWorker();
374
+ var messageObject = {sender: 123, body: {
375
+ type: google.wspl.gears.DbWorker.CommandTypes.ROLLBACK,
376
+ transactionId: transactionId
377
+ }};
378
+ var called = false;
379
+
380
+ worker.handleRollback_ = function(trans) {
381
+ called = true;
382
+ assertEquals('Wrong transaction id.', transactionId, trans);
383
+ };
384
+
385
+ worker.onMessage_(null, null, messageObject);
386
+ assertTrue('handleRollback_ not called.', called);
387
+
388
+ mockControl.verify();
389
+ }
390
+
391
+ </script>
392
+ </body>
393
+ </html>
@@ -0,0 +1,32 @@
1
+ /*
2
+ Copyright 2009 Google Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ /**
18
+ * @fileoverview Starts the dbworker.
19
+ *
20
+ * When constructing the worker for execution, this needs to be the last
21
+ * file. The worker consists of the following source files combined together.
22
+ *
23
+ * globalfunctions.js
24
+ * gearsutils.js
25
+ * dbworker.js
26
+ * dbworkerstarter.js
27
+ *
28
+ * and then loaded into a Gears worker process as implemented in
29
+ * databasefactory.js
30
+ */
31
+
32
+ google.wspl.gears.DbWorker.start();
@@ -0,0 +1,595 @@
1
+ /*
2
+ Copyright 2009 Google Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ /**
18
+ * @fileoverview A Gears implementation of dbwrapperapi Database.
19
+ *
20
+ * This implementation locks database access upon invoking the transaction's
21
+ * populate callback. Statements are then asynchronously sent to a worker
22
+ * thread for execution.
23
+ */
24
+
25
+ /**
26
+ * @see google.wspl.Database#Database
27
+ * @param {boolean} opt_sync Perform all callbacks synchronously.
28
+ * @constructor
29
+ * @extends google.wspl.Database
30
+ */
31
+ google.wspl.gears.Database = function(opt_sync) {
32
+ google.wspl.Database.call(this);
33
+
34
+ /**
35
+ * Begin transactions synchronously.
36
+ * @type {boolean}
37
+ * @private
38
+ */
39
+ this.synchronous_ = !!opt_sync;
40
+ };
41
+ google.inherits(google.wspl.gears.Database, google.wspl.Database);
42
+
43
+ /**
44
+ * The time to wait for the dbworker to reply with STARTED.
45
+ * @type {number}
46
+ */
47
+ google.wspl.gears.Database.TIMEOUT = 60000;
48
+
49
+ /**
50
+ * Whether the gears worker failed to reply with STARTED before TIMEOUT.
51
+ * @type {boolean}
52
+ * @private
53
+ */
54
+ google.wspl.gears.Database.prototype.workerTimeout_ = false;
55
+
56
+ /**
57
+ * Flag set when the worker is ready with an open database connection.
58
+ * @type {boolean}
59
+ * @private
60
+ */
61
+ google.wspl.gears.Database.prototype.workerReady_ = false;
62
+
63
+ /**
64
+ * Flag set when this database should use the worker to process transactions.
65
+ * @type {boolean}
66
+ * @private
67
+ */
68
+ google.wspl.gears.Database.prototype.useWorker_ = false;
69
+
70
+ /**
71
+ * The user for this database.
72
+ * @type {string}
73
+ * @private
74
+ */
75
+ google.wspl.gears.Database.prototype.userId_;
76
+
77
+ /**
78
+ * The name for this database.
79
+ * @type {string}
80
+ * @private
81
+ */
82
+ google.wspl.gears.Database.prototype.name_;
83
+
84
+ /**
85
+ * A map of open transactions and their callbacks.
86
+ * @type {Object}
87
+ * @private
88
+ */
89
+ google.wspl.gears.Database.prototype.transactions_ = {};
90
+
91
+ /**
92
+ * An array of transaction ids that should be executed in order as the lock
93
+ * becomes available.
94
+ * @type {Array.<number>}
95
+ * @private
96
+ */
97
+ google.wspl.gears.Database.prototype.queuedTransactions_ = [];
98
+
99
+ /**
100
+ * The transaction lock for this database.
101
+ * @type {boolean}
102
+ * @private
103
+ */
104
+ google.wspl.gears.Database.prototype.locked_ = false;
105
+
106
+ /**
107
+ * The number of transactions to be used as an index.
108
+ * @type {number}
109
+ * @private
110
+ */
111
+ google.wspl.gears.Database.prototype.transCount_ = 1;
112
+
113
+ /**
114
+ * The id of the transaction being executed.
115
+ * @type {number}
116
+ * @private
117
+ */
118
+ google.wspl.gears.Database.prototype.currentTransactionId_;
119
+
120
+ /**
121
+ * The Gears worker pool.
122
+ * @type {GearsWorkerPool}
123
+ * @private
124
+ */
125
+ google.wspl.gears.Database.prototype.wp_;
126
+
127
+ /**
128
+ * The worker ID.
129
+ * @type {number}
130
+ * @private
131
+ */
132
+ google.wspl.gears.Database.prototype.workerId_;
133
+
134
+ /**
135
+ * The Gears database object.
136
+ * @type {GearsDatabase}
137
+ * @private
138
+ */
139
+ google.wspl.gears.Database.prototype.db_;
140
+
141
+ /**
142
+ * Opens a new Gears database. This operation can only be performed once.
143
+ * @param {string} userId The user for this database.
144
+ * @param {string} name The name for this database.
145
+ * @param {GearsDatabase} gearsDb The gears database.
146
+ */
147
+ google.wspl.gears.Database.prototype.openDatabase = function(userId, name,
148
+ gearsDb) {
149
+ if (!this.db_) {
150
+ this.db_ = gearsDb;
151
+ this.userId_ = userId;
152
+ this.name_ = name;
153
+ google.wspl.GearsUtils.openDatabase(userId, name, this.db_,
154
+ google.logger);
155
+ } else {
156
+ google.logger('openDatabase already invoked.');
157
+ }
158
+ };
159
+
160
+ /**
161
+ * Starts a worker to handle the database interactions. The worker will be
162
+ * asynchronously started after the specified delay and will not be used until
163
+ * the completion of any pending transaction.
164
+ * @param {GearsWorkerPool} wp The Gears worker pool.
165
+ * @param {string} workerUrl The URL to find the gears database worker.
166
+ * @return {number} The worker ID.
167
+ */
168
+ google.wspl.gears.Database.prototype.startWorker = function(wp, workerUrl) {
169
+ this.wp_ = wp;
170
+
171
+ google.logger('Starting dbworker thread.');
172
+
173
+ this.workerId_ = wp.createWorkerFromUrl(workerUrl);
174
+
175
+ this.timeoutId_ = window.setTimeout(google.bind(this.handleTimeout_, this),
176
+ google.wspl.gears.Database.TIMEOUT);
177
+
178
+ return this.workerId_;
179
+ };
180
+
181
+ /**
182
+ * @see google.wspl.Transaction#createTransaction
183
+ * @inheritDoc
184
+ */
185
+ google.wspl.gears.Database.prototype.createTransaction = function(populate,
186
+ opt_callback) {
187
+ var transactionCallback = opt_callback || {
188
+ onSuccess : function() {},
189
+ onFailure : function() {}
190
+ };
191
+
192
+ var id = this.transCount_++;
193
+ var transaction = new google.wspl.gears.Transaction(id, this);
194
+
195
+ this.saveTransaction_(transaction, transactionCallback, populate);
196
+
197
+ this.queuedTransactions_.push(transaction.id_);
198
+ this.nextTransaction_();
199
+ };
200
+
201
+ /**
202
+ * Saves the transaction and transaction callback to be accessed later when a
203
+ * commit or rollback is performed.
204
+ *
205
+ * @param {google.wspl.gears.Transaction} transaction The transaction that the
206
+ * callback belongs to.
207
+ * @param {Object} callback A transaction callback with onSuccess and onFailure
208
+ * @private
209
+ */
210
+ google.wspl.gears.Database.prototype.saveTransaction_ = function(
211
+ transaction, callback, populate) {
212
+ this.transactions_[transaction.id_] = {
213
+ transaction: transaction,
214
+ callback: callback,
215
+ populate: populate
216
+ };
217
+ };
218
+
219
+ /**
220
+ * Handles incomming messages.
221
+ * @param {string} a Deprecated.
222
+ * @param {number} b Deprecated.
223
+ * @param {Object} messageObject The message object.
224
+ * @private
225
+ */
226
+ google.wspl.gears.Database.prototype.onMessage_ =
227
+ function(a, b, messageObject) {
228
+ var message = messageObject.body;
229
+
230
+ try {
231
+ switch(message['type']) {
232
+ case google.wspl.gears.DbWorker.ReplyTypes.RESULT:
233
+ this.handleResult_(message['results'], message['callbackId'],
234
+ message['transactionId']);
235
+ break;
236
+ case google.wspl.gears.DbWorker.ReplyTypes.FAILURE:
237
+ this.handleFailure_(message['error'], message['callbackId'],
238
+ message['transactionId']);
239
+ break;
240
+ case google.wspl.gears.DbWorker.ReplyTypes.COMMIT:
241
+ this.handleCommit_(message['transactionId']);
242
+ break;
243
+ case google.wspl.gears.DbWorker.ReplyTypes.ROLLBACK:
244
+ this.handleRollback_(message['transactionId']);
245
+ break;
246
+ case google.wspl.gears.DbWorker.ReplyTypes.STARTED:
247
+ this.handleStarted_();
248
+ break;
249
+ case google.wspl.gears.DbWorker.ReplyTypes.OPEN_SUCCESSFUL:
250
+ this.handleOpenSuccessful_();
251
+ break;
252
+ case google.wspl.gears.DbWorker.ReplyTypes.OPEN_FAILED:
253
+ this.handleOpenFailed_(message['error']);
254
+ break;
255
+ case google.wspl.gears.DbWorker.ReplyTypes.LOG:
256
+ google.logger(message['msg']);
257
+ break;
258
+ }
259
+ } catch (ex) {
260
+ google.logger('Gears database failed: ' + ex.message, ex);
261
+ }
262
+ };
263
+
264
+ /**
265
+ * Opens a new Gears database.
266
+ *
267
+ * @param {string} userId The user to which the database belongs.
268
+ * @param {string} name The name of the database.
269
+ */
270
+ google.wspl.gears.Database.prototype.doOpen = function(userId, name) {
271
+ this.sendMessageToWorker_({
272
+ 'type': google.wspl.gears.DbWorker.CommandTypes.OPEN,
273
+ 'name': name,
274
+ 'userId': userId
275
+ });
276
+ };
277
+
278
+ /**
279
+ * Begins a new transaction on the Gears database.
280
+ *
281
+ * @param {number} transactionId The id of the transaction being committed.
282
+ */
283
+ google.wspl.gears.Database.prototype.doBegin = function(transactionId) {
284
+ if (!this.useWorker_) {
285
+ this.db_.execute('BEGIN IMMEDIATE');
286
+ return;
287
+ }
288
+
289
+ this.sendMessageToWorker_({
290
+ 'type': google.wspl.gears.DbWorker.CommandTypes.BEGIN,
291
+ 'transactionId': transactionId
292
+ });
293
+ };
294
+
295
+ /**
296
+ * Commits the current transaction on the Gears database. The transactionId
297
+ * is used to invoke the callback associated with the transaction.
298
+ *
299
+ * @param {number} transactionId The id of the transaction being committed.
300
+ */
301
+ google.wspl.gears.Database.prototype.doCommit = function(transactionId) {
302
+ if (!this.useWorker_) {
303
+ this.db_.execute('COMMIT');
304
+ this.postCommit_();
305
+ return;
306
+ }
307
+
308
+ this.sendMessageToWorker_({
309
+ 'type': google.wspl.gears.DbWorker.CommandTypes.COMMIT,
310
+ 'transactionId': transactionId
311
+ });
312
+ };
313
+
314
+ /**
315
+ * Rolls the current transaction back on the Gears database. The transactionId
316
+ * is used to invoke the callback associated with the transaction.
317
+ *
318
+ * @param {number} transactionId The id of the transaction being rolled back.
319
+ */
320
+ google.wspl.gears.Database.prototype.doRollback = function(transactionId) {
321
+ if (!this.useWorker_) {
322
+ this.db_.execute('ROLLBACK');
323
+ this.postRollback_();
324
+ return;
325
+ }
326
+
327
+ this.sendMessageToWorker_({
328
+ 'type': google.wspl.gears.DbWorker.CommandTypes.ROLLBACK,
329
+ 'transactionId': transactionId
330
+ });
331
+ };
332
+
333
+ /**
334
+ * Executes an array of statements on the Gears database. The transactionId and
335
+ * callbackId are used to identify the callback that should be invoked when
336
+ * handleResult or handleFailure is called.
337
+ *
338
+ * @param {Array.<google.wspl.Statement>} statements The group of statements to
339
+ * execute
340
+ * @param {number} callbackId The callback to invoke for each statement
341
+ * @param {number} transactionId The transaction that the statements belong to
342
+ */
343
+ google.wspl.gears.Database.prototype.doExecute = function(statements,
344
+ callbackId,
345
+ transactionId) {
346
+ if (!this.useWorker_) {
347
+ this.doExecuteSynchronously_(statements, callbackId, transactionId);
348
+ return;
349
+ }
350
+
351
+ var newStatements = [];
352
+ for (var i = 0; i < statements.length; i++) {
353
+ newStatements[i] = {
354
+ 'sql': statements[i].sql,
355
+ 'params': statements[i].params
356
+ };
357
+ }
358
+
359
+ this.sendMessageToWorker_({
360
+ 'type': google.wspl.gears.DbWorker.CommandTypes.EXECUTE,
361
+ 'statements': newStatements,
362
+ 'callbackId': callbackId,
363
+ 'transactionId': transactionId
364
+ });
365
+ };
366
+
367
+ /**
368
+ * Executes an array of statements on the synchronous Gears databse.
369
+ * @param {Array.<google.wspl.Statement>} statements
370
+ * @param {number} callbackId
371
+ * @param {number} transactionId
372
+ * @private
373
+ */
374
+ google.wspl.gears.Database.prototype.doExecuteSynchronously_ =
375
+ function(statements, callbackId, transactionId) {
376
+ var db = this;
377
+ var results = [];
378
+ for (var i = 0; i < statements.length; i++) {
379
+ try {
380
+ var resultset = this.db_.execute(statements[i].sql, statements[i].params);
381
+ var result = google.wspl.GearsUtils.resultSetToObjectArray(resultset);
382
+ results.push(result);
383
+ } catch (e) {
384
+ var error = e;
385
+ function failureCallback() {
386
+ db.handleFailure_(error, callbackId, transactionId);
387
+ };
388
+ this.setTimeout_(failureCallback, 0);
389
+ return;
390
+ }
391
+ }
392
+
393
+ function resultCallback() {
394
+ db.handleResult_(results, callbackId, transactionId);
395
+ };
396
+ this.setTimeout_(resultCallback, 0);
397
+ };
398
+
399
+ /**
400
+ * Handles a RESULT message from the worker thread.
401
+ *
402
+ * @param {!Array.<!Array.<Object>>} results A Gears result set.
403
+ * @param {number} callbackId The callback to invoke.
404
+ * @param {number} transactionId The transaction that the statement is executing
405
+ * in.
406
+ * @private
407
+ */
408
+ google.wspl.gears.Database.prototype.handleResult_ = function(results,
409
+ callbackId, transactionId) {
410
+ var transInfo = this.transactions_[transactionId];
411
+ if (transInfo) {
412
+ for (var i = 0, l = results.length; i < l; i++) {
413
+ var resultSet = new google.wspl.gears.ResultSet(results[i]);
414
+ transInfo.transaction.success(resultSet, callbackId);
415
+ }
416
+ }
417
+ };
418
+
419
+ /**
420
+ * Handles a FAILURE message from the worker thread.
421
+ *
422
+ * @param {Error} error An error produced by the Gears database
423
+ * @param {number} callbackId The callback to invoke
424
+ * @param {number} transactionId The transaction that the statement is executing
425
+ * in
426
+ * @private
427
+ */
428
+ google.wspl.gears.Database.prototype.handleFailure_ = function(error,
429
+ callbackId, transactionId) {
430
+ var transInfo = this.transactions_[transactionId];
431
+ if (transInfo) {
432
+ transInfo.error = error;
433
+ transInfo.transaction.failure(error, callbackId);
434
+ }
435
+ };
436
+
437
+ /**
438
+ * Handles a COMMIT message from the worker thread.
439
+ *
440
+ * @param {number} id The transaction id.
441
+ * @private
442
+ */
443
+ google.wspl.gears.Database.prototype.handleCommit_ = function(id) {
444
+ var transaction = this.removeTransaction_(id);
445
+ if (transaction) {
446
+ transaction.callback.onSuccess();
447
+ }
448
+
449
+ this.nextTransaction_();
450
+ };
451
+
452
+ /**
453
+ * Handles the completion of a commit from the synchronous database.
454
+ * @private
455
+ */
456
+ google.wspl.gears.Database.prototype.postCommit_ = function() {
457
+ this.handleCommit_(this.currentTransactionId_);
458
+ };
459
+
460
+ /**
461
+ * Handles a ROLLBACK message from the worker thread.
462
+ *
463
+ * @param {number} id The transaction id
464
+ * @private
465
+ */
466
+ google.wspl.gears.Database.prototype.handleRollback_ = function(id) {
467
+ var transaction = this.removeTransaction_(id);
468
+ if (transaction) {
469
+ transaction.callback.onFailure(transaction.error);
470
+ }
471
+
472
+ this.nextTransaction_();
473
+ };
474
+
475
+ /**
476
+ * Handles the completion of a rollback from the synchronous database.
477
+ * @private
478
+ */
479
+ google.wspl.gears.Database.prototype.postRollback_ = function() {
480
+ this.handleRollback_(this.currentTransactionId_);
481
+ };
482
+
483
+ /**
484
+ * Handles a STARTED message from the worker thread.
485
+ *
486
+ * @private
487
+ */
488
+ google.wspl.gears.Database.prototype.handleStarted_ = function() {
489
+ if (!this.workerTimeout_) {
490
+ google.logger('Dbworker started.');
491
+ window.clearTimeout(this.timeoutId_);
492
+ this.timeoutId_ = 0;
493
+ this.doOpen(this.userId_, this.name_);
494
+ }
495
+ };
496
+
497
+ /**
498
+ * Handles a timeout of waiting for a STARTED message from the worker thread.
499
+ *
500
+ * @private
501
+ */
502
+ google.wspl.gears.Database.prototype.handleTimeout_ = function() {
503
+ this.workerTimeout_ = true;
504
+ google.logger('Timed out while waiting for the dbworker to start.');
505
+ };
506
+
507
+ /**
508
+ * Handles a OPEN_SUCCESSFUL message from the worker thread.
509
+ *
510
+ * @private
511
+ */
512
+ google.wspl.gears.Database.prototype.handleOpenSuccessful_ = function() {
513
+ this.workerReady_ = true;
514
+ };
515
+
516
+ /**
517
+ * Handles a OPEN_FAILED message from the worker thread.
518
+ * @param {string} error
519
+ * @private
520
+ */
521
+ google.wspl.gears.Database.prototype.handleOpenFailed_ = function(error) {
522
+ google.logger('Worker failed to open Gears database.');
523
+ };
524
+
525
+ /**
526
+ * Executes the next transaction if there is one queued.
527
+ *
528
+ * @private
529
+ */
530
+ google.wspl.gears.Database.prototype.nextTransaction_ = function() {
531
+ if (this.queuedTransactions_.length && !this.locked_) {
532
+ this.locked_ = true;
533
+
534
+ if (this.workerReady_ && !this.useWorker_) {
535
+ this.useWorker_ = true;
536
+ google.logger('Switching to asynchronous database interface.');
537
+ }
538
+
539
+ var id = this.queuedTransactions_.shift();
540
+ this.currentTransactionId_ = id;
541
+ var transactionData = this.transactions_[id];
542
+
543
+ var db = this;
544
+ function populate() {
545
+ transactionData.populate(transactionData.transaction);
546
+
547
+ // If populate did not execute statements on the database, invoke the
548
+ // success callback and process the next transaction.
549
+ if (!transactionData.transaction.isExecuting()) {
550
+ db.handleCommit_(id);
551
+ }
552
+ };
553
+
554
+ this.setTimeout_(populate, 0);
555
+ }
556
+ };
557
+
558
+ /**
559
+ * Cleans up the transaction and transaction callback for the id specified.
560
+ *
561
+ * @param {number} id The transaction id.
562
+ * @return {google.wspl.Transaction} The transaction and callback in an object.
563
+ * @private
564
+ */
565
+ google.wspl.gears.Database.prototype.removeTransaction_ = function(id) {
566
+ this.locked_ = false;
567
+ var transaction = this.transactions_[id];
568
+ if (transaction) {
569
+ delete this.transactions_[id];
570
+ }
571
+ return transaction;
572
+ };
573
+
574
+ /**
575
+ * Execute a function using window's setTimeout.
576
+ * @param {Function} func The function to execute.
577
+ * @param {number} time The time delay before invocation.
578
+ * @private
579
+ */
580
+ google.wspl.gears.Database.prototype.setTimeout_ = function(func, time) {
581
+ if (this.synchronous_) {
582
+ func();
583
+ } else {
584
+ window.setTimeout(func, time);
585
+ }
586
+ };
587
+
588
+ /**
589
+ * Sends a message to the database worker thread.
590
+ * @param {Object} msg The message object to send.
591
+ * @private
592
+ */
593
+ google.wspl.gears.Database.prototype.sendMessageToWorker_ = function(msg) {
594
+ this.wp_.sendMessage(msg, this.workerId_);
595
+ };