Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / tests.js @ 9ccb70fd

History | View | Annotate | Download (17.2 kB)

1
// Copyright 2011 GRNET S.A. All rights reserved.
2
// 
3
// Redistribution and use in source and binary forms, with or
4
// without modification, are permitted provided that the following
5
// conditions are met:
6
// 
7
//   1. Redistributions of source code must retain the above
8
//      copyright notice, this list of conditions and the following
9
//      disclaimer.
10
// 
11
//   2. Redistributions in binary form must reproduce the above
12
//      copyright notice, this list of conditions and the following
13
//      disclaimer in the documentation and/or other materials
14
//      provided with the distribution.
15
// 
16
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
// POSSIBILITY OF SUCH DAMAGE.
28
// 
29
// The views and conclusions contained in the software and
30
// documentation are those of the authors and should not be
31
// interpreted as representing official policies, either expressed
32
// or implied, of GRNET S.A.
33
// 
34

    
35
$(document).ready(function(){
36

    
37
    // shortcuts
38
    snf = synnefo;
39
    models = snf.models;
40
    util = snf.utils;
41
    views = snf.views;
42
    bb = Backbone;
43
    vms = snf.storage.vms;
44
    nets = snf.storage.networks;
45

    
46
    synnefo.config.api_urls = {
47
        'compute': '/api/v1.1', 
48
        'glance':'/images/v1.1'
49
    };
50

    
51
    module("VM Model")
52

    
53
    test("model change events", function(){
54
        expect(8);
55

    
56
        synnefo.storage.images.add({id:1,metadata:{values:{size:100}}});
57
        var v1 = new models.VM({'imageRef':1});
58
        v1.bind("change", function(){
59
            ok(1, "change event triggered")
60
            equals(v1.get("status"), "BUILD")
61
            equals(v1.get("state"), "BUILD_COPY")
62
        })
63
        v1.set({'status':'BUILD', 'progress':80, 'imageRef': 1});
64
        v1.unbind();
65

    
66
        v1.bind("change", function(){
67
            ok(1, "change event triggered")
68
            equals(v1.get("status"), "BUILD")
69
            equals(v1.get("state"), "DESTROY")
70
        })
71
        v1.set({'state':'DESTROY'});
72
        v1.unbind();
73

    
74
        v1.bind("change", function() {
75
            ok(1, "change event triggered")
76
            equals(v1.get("status"), "BUILD")
77
            equals(v1.get("state"), "BUILD_COPY")
78
        })
79
        v1.set({'status':'BUILD', 'progress':80, 'imageRef': 1});
80
        equals(v1.get("status"), "BUILD")
81
        equals(v1.get("state"), "DESTROY")
82
        v1.unbind();
83
    })
84

    
85
    test("model state transitions", function(){
86
        var vm = models.VM;
87
        
88
        var v1 = new vm();
89
        v1.set({status: 'BUILD_COPY'})
90
        equals(v1.get("state"), 'BUILD_COPY', "State is set");
91
        v1.set({status: 'DESTROY'})
92
        equals(v1.get("state"), 'DESTROY', "From buld to destroy");
93
        v1.set({status: 'BUILD'})
94
        equals(v1.get("state"), 'DESTROY', "Keep destroy state");
95

    
96
        v1 = new vm();
97
        v1.set({status: 'ACTIVE'})
98
        equals(v1.get("state"), 'ACTIVE', "State is set");
99

    
100
        v1.set({status: 'SHUTDOWN'})
101
        equals(v1.get("state"), 'SHUTDOWN', "From active to shutdown (should change)");
102

    
103
        v1.set({status: 'ACTIVE'})
104
        equals(v1.get("state"), 'SHUTDOWN', "From shutdown to active (should not change)");
105
        
106
        v1.set({status: 'STOPPED'})
107
        equals(v1.get("state"), 'STOPPED', "From shutdown to stopped (should change)");
108

    
109
        v1.set({status: 'ACTIVE'})
110
        equals(v1.get("state"), 'ACTIVE', "From stopped to active (should change)");
111
        v1.set({'status': 'STOPPED'})
112
        equals(v1.get('state'), 'STOPPED', "From shutdown to stopped should change");
113

    
114
        v1.set({'status': 'DESTROY'})
115
        equals(v1.get('state'), 'DESTROY', "From stopped to destory should set state to DESTROY");
116
        v1.set({'status': 'ACTIVE'})
117
        equals(v1.get('state'), 'DESTROY', "From destroy to active should keep state to DESTROY");
118
        v1.set({'status': 'REBOOT'})
119
        equals(v1.get('state'), 'DESTROY', "From destroy to active should keep state to DESTROY");
120
        v1.set({'status': 'DELETED'})
121
        equals(v1.get('state'), 'DELETED', "Destroy should be kept until DELETE or ERROR");
122

    
123
        v1 = new vm({status:'BUILD'});
124
        equals(v1.get('state'), 'BUILD', "new vm with build as initial status")
125
        equals(v1.get('status'), 'BUILD', "new vm with build as initial status")
126
        v1.set({status:'ACTIVE'})
127
        equals(v1.get('state'), 'ACTIVE', "active state has been set")
128
        equals(v1.get('status'), 'ACTIVE', "active status has been set")
129
    })
130

    
131

    
132
    test("building states", function(){
133
        synnefo.storage.images.add({id:1,metadata:{values:{size:100}}});
134
        var vm = models.VM;
135
        var v1 = new vm({'status':'BUILD','progress':0, 'imageRef':1});
136
        equals(v1.get('state'), 'BUILD_INIT', "progress 0 sets state to BUILD_INIT");
137
        equals(v1.get('status'), 'BUILD', "progress 0 sets status to BUILD");
138
        equals(v1.get('progress_message'), 'init', "message 'init'");
139
        v1.set({status:'BUILD', progress:50});
140
        equals(v1.get('state'), 'BUILD_COPY', "progress 50 sets state to BUILD_COPY");
141
        equals(v1.get('status'), 'BUILD', "progress 50 sets status to BUILD");
142
        equals(v1.get('progress_message'), '50.00 MB, 100.00 MB, 50', "message: 'final'");
143
        v1.set({status:'BUILD', progress:100});
144
        equals(v1.get('state'), 'BUILD_FINAL', "progress 100 sets state to BUILD_FINAL");
145
        equals(v1.get('status'), 'BUILD', "progress 100 sets status to BUILD");
146
        v1.set({status:'ACTIVE', progress:100});
147
        equals(v1.get('state'), 'ACTIVE', "ACTIVE set transition to ACTIVE");
148
        equals(v1.get('status'), 'ACTIVE', "ACTIVE set transition to ACTIVE");
149
        equals(v1.get('progress_message'), 'final', "message: 'final'");
150
    })
151

    
152
    test("active inactive states", function(){
153
    
154
        var vm = models.VM;
155
        var v1 = new vm();
156
        var v = {}
157
        var active = ['ACTIVE', 'BUILD', 'REBOOT'];
158
        for (v in active) {
159
            v = active[v];
160
            v1.set({status: v})
161
            equals(v1.is_active(), true, v + " status is active")
162
        }
163
        
164
        var v1 = new vm();
165
        var inactive = ['STOPPED', 'ERROR', 'UNKNOWN'];
166
        for (v in inactive) {
167
            v = inactive[v];
168
            v1.set({status: v})
169
            equals(v1.is_active(), false, v1.state() + " status is not active")
170
        }
171
    
172
    })
173

    
174
    test("transition event", function(){
175
        expect(9);
176

    
177
        var vm = new models.VM({status:'BUILD'});
178
        vm.bind("transition", function(data) {
179
            ok(true, "Transition triggered");
180
            equals(data.from, "BUILD")
181
            equals(data.to, "ACTIVE");
182
        })
183
        // trigger 1 time
184
        vm.set({status:'BUILD'});
185
        vm.set({status:'ACTIVE'});
186
        vm.unbind();
187
        
188
        // from build to active
189
        vm = new models.VM({status:'BUILD'});
190
        vm.bind("transition", function(data) {
191
            ok(true, "Transition triggered");
192
            equals(data.from, "BUILD")
193
            equals(data.to, "ACTIVE");
194
        })
195
        // trigger 1 time
196
        vm.set({status:'ACTIVE'});
197
        vm.unbind();
198

    
199
        // from active to shutdown
200
        vm = new models.VM({status:'SHUTDOWN'});
201
        vm.bind("transition", function(data) {
202
            ok(true, "Transition triggered");
203
            equals(data.from, "SHUTDOWN")
204
            equals(data.to, "STOPPED");
205
        })
206
        // trigger 1 time
207
        vm.set({status:'STOPPED'});
208
    })
209
    
210
    module("Collections");
211
        
212
    test("status model remove events", function(){
213
        vms.unbind();
214
        expect(1)
215

    
216
        vms.bind("change", function(){
217
            ok(-1, "change event should not get triggered");
218
        })
219

    
220
        vms.bind("remove", function(){
221
            ok(1, "remove event triggered")
222
        })
223

    
224
        var vm = new models.VM({id:1, status:"ACTIVE", name:"oldname"});
225
        vms.add(vm);
226
        
227
        // NO change/delete just DELETE event triggered
228
        vms.update([{id:1, status:"DELETED", name:"newname"}])
229
    });
230

    
231
    test("collection reset events", function() {
232
        expect(9);
233

    
234
        var testCollection = models.Collection.extend({
235
            url: '/testObject'
236
        });
237
        var collection = new testCollection();
238

    
239
        
240
        // reset on new entry after empty
241
        $.mockjax({
242
            url: '/testObject',
243
            responseTime: 50,
244
            responseText: [
245
                {id:1, attr1: 1, attr2: 2}
246
            ]
247
        }); 
248
        // THIS SHOULD NOT FIRE, since we force update method
249
        collection.bind("reset", function() {
250
            ok(1, "NOT EXPECTED: reset triggered on new entry while collection was empty");
251
        });
252
        collection.bind("add", function() {
253
            ok(1, "1: add triggered on new entry while collection was empty");
254
        });
255
        // THIS SHOULD NOT FIRE, model was added, not changed
256
        collection.bind("change", function() {
257
            ok(1, "NOT EXPECTED: change triggered on new entry while collection was empty");
258
        });
259
        collection.fetch({'async': false});
260
        equals(collection.length, 1, "2: collection contains 1 model");
261
        collection.unbind();
262
        $.mockjaxClear();
263
        
264
        // reset is called on change
265
        $.mockjax({
266
            url: '/testObject',
267
            responseTime: 50,
268
            responseText: [
269
                {id:1, attr1: 4, attr2: 2}
270
            ]
271
        });
272
        collection.bind("reset", function() {
273
            ok(1, "NOT EXPECTED: reset triggered on new entry while collection was empty");
274
        });
275
        collection.bind("add", function() {
276
            ok(1, "NOT EXPECTED: add triggered on new entry while collection was empty");
277
        });
278
        // THIS SHOULD NOT FIRE, model was added, not changed
279
        collection.bind("change", function() {
280
            ok(1, "3: change triggered on new entry while collection was empty");
281
        });
282
        collection.fetch({'async': false, refresh:true});
283
        equals(collection.length, 1, "4 collection contains 1 model");
284
        collection.unbind();
285
        $.mockjaxClear();
286

    
287
        // reset on second entry
288
        $.mockjax({
289
            url: '/testObject',
290
            responseTime: 50,
291
            responseText: [
292
                {id:1, attr1: 4, attr2: 2},
293
                {id:2, attr1: 1, attr2: 2}
294
            ]
295
        });
296
        collection.bind("reset", function() {
297
            ok(1, "NOT EXPECTED: reset triggered when new model arrived");
298
        })
299
        collection.bind("add", function() {
300
            ok(1, "5: add triggered when new model arrived");
301
        })
302
        collection.bind("change", function() {
303
            ok(1, "NOT EXPECTED: change triggered when new model arrived");
304
        }) 
305
        collection.fetch({async:false, refresh:true});
306
        equals(collection.length, 2, "6 new model added");
307
        collection.unbind();
308
        $.mockjaxClear();
309
        
310
        // reset does not remove
311
        $.mockjax({
312
            url: '/testObject',
313
            responseTime: 50,
314
            responseText: [
315
                {id:2, attr1: 1, attr2: 2}
316
            ]
317
        }); 
318
        collection.bind("reset", function() {
319
            ok(1, "NOT EXPECTED: reset triggered when model removed");
320
        })
321
        collection.bind("remove", function() {
322
            ok(1, "7: remove triggered when model removed");
323
        })
324
        collection.bind("change", function() {
325
            ok(1, "NOT EXPECTED: change triggered when model removed");
326
        })
327

    
328
        collection.fetch({async:false, refresh:true});
329
        equals(collection.length, 1, "8 one model removed");
330
        collection.unbind();
331
        $.mockjaxClear();
332

    
333
        // reset is not called on 304
334
        $.mockjax({
335
            url: '/testObject',
336
            responseTime: 50,
337
            status: 304,
338
            responseText: undefined
339
        }); 
340
        // NO event is triggered on 304
341
        collection.bind("reset", function() {
342
            ok(1, "WRONG: reset triggered on 304");
343
        });
344
        collection.bind("remove", function() {
345
            ok(1, "WRONG: remove triggered on 304");
346
        });
347
        collection.bind("change", function() {
348
            ok(1, "WRONG: remove triggered on 304");
349
        });
350
        collection.fetch({async:false, refresh:true});
351
        equals(collection.length, 1, "9 one model removed");
352
        collection.unbind();
353
        $.mockjaxClear();
354
    })
355

    
356

    
357
    module("network vm connections")
358
    test("network vm connections", function() {
359

    
360
        function _net(id, ip) {
361
            return {
362
                id: id,
363
                name: "net " + id,
364
                values:[{version:4, addr: ip}, {version:6, addr:ip}] 
365
            }
366
        }
367
        vms.add({id:1, name:"s1", linked_to_nets:[_net("p", "127")]});
368
        var vm = vms.at(0);
369
        
370
        nets.add({id:"p", nid:"p", name:"n1", linked_to:[1]});
371
        var n = nets.at(0);
372
    })
373

    
374
    module("images/flavors")
375
    test("Test DELETE state image retrieval", function() {
376
        snf.storage.images.reset();
377
        snf.storage.vms.reset();
378

    
379
        var images = snf.storage.images;
380
        var vms = snf.storage.vms;
381

    
382
        var img = images.add({name:"image 1", id:1}).last();
383
        var vm1 = vms.add({imageRef:1, name:"vm1"}).last();
384
        var vm2 = vms.add({imageRef:2, name:"vm2"}).last();
385
            
386
        equals(img, vm1.get_image());
387
        
388
        // reset is not called on 304
389
        $.mockjax({
390
            url: '/api/v1.1/images/2',
391
            responseTime: 50,
392
            status: 200,
393
            responseText: {image:{name:"image 2", id:2}}
394
        }); 
395
        
396
        
397
        equals(images.length, 1, "1 image exists");
398
        vm2.get_image();
399
        equals(images.get(2).get("name"), "image 2", "image data parsed");
400
        equals(images.length, 2);
401
    })
402

    
403
    test("Test DELETE state flavor retrieval", function() {
404
        snf.storage.flavors.reset();
405
        snf.storage.vms.reset();
406

    
407
        var flavors = snf.storage.flavors;
408
        var vms = snf.storage.vms;
409

    
410
        var flv = flavors.add({id:1, cpu:1, disk:1, ram:1024}).last();
411
        var vm1 = vms.add({flavorRef:1, name:"vm1"}).last();
412
        var vm2 = vms.add({flavorRef:2, name:"vm2"}).last();
413
            
414
        equals(flv, vm1.get_flavor());
415
        
416
        // reset is not called on 304
417
        $.mockjax({
418
            url: '/api/v1.1/flavors/2',
419
            responseTime: 50,
420
            status: 200,
421
            responseText: {flavor:{cpu:1, ram:2048, disk:100, id:2}}
422
        }); 
423
        
424
        
425
        equals(flavors.length, 1, "1 flavor exists");
426
        vm2.get_flavor();
427
        equals(flavors.get(2).get("ram"), 2048, "flavor data parsed");
428
        equals(flavors.length, 2);
429
    })
430

    
431
    test("actions list object", function(){
432
        var m = new models.Image();
433
        var l = new models.ParamsList(m, "actions");
434
        var count = 0;
435

    
436
        l.add("destroy");
437
        equals(l.has_action("destroy"), true);
438
        equals(l.contains("destroy"), true);
439

    
440
        l.add("destroy", 1, {});
441
        equals(l.has_action("destroy"), true);
442
        equals(l.contains("destroy", 1, {}), true);
443

    
444
        l.remove("destroy", 1, {});
445
        equals(l.contains("destroy", 1, {}), false);
446

    
447
        m.bind("change:actions", function() { count ++});
448
        l.add("destroy");
449
        
450
        equals(count, 0);
451
        l.add("destroy", 1, {});
452
        equals(count, 1);
453
    });
454

    
455
    module("update handlers")
456
    test("update handlers", function() {
457
        // this test is based on multiple timeouts
458
        // so the results might differ between different browsers
459
        // or browser load
460
        stop();
461

    
462
        var counter = 0;
463
        var cb = function() {
464
            counter++;
465
        }
466
        
467
        var opts = {
468
            callback:cb,
469
            interval: 10,
470
            fast: 5,
471
            increase: 5,
472
            max: 15,
473
            increase_after_calls: 3,
474
            initial_call: false
475
        }
476

    
477
        var h = new snf.api.updateHandler(opts);
478
        h.start();
479

    
480
        var add = $.browser.msie ? 8 : 0;
481

    
482
        window.setTimeout(function(){
483
            h.stop();
484
            start();
485
            // 4 calls, limit reached
486
            equals(counter, 4, "normal calls");
487
            equals(h.interval, opts.max, "limit reached");
488

    
489
            stop();
490
            h.start(false);
491
            h.faster();
492
            window.setTimeout(function(){
493
                // 11 calls, limit reached
494
                start();
495
                equals(counter, 11, "faster calls");
496
                equals(h.interval, opts.max, "limit reached");
497
                h.stop();
498
                stop();
499
                window.setTimeout(function(){
500
                    // no additional calls because we stopped it
501
                    start();
502
                    equals(counter, 11, "no additional calls")
503
                }, 50 + add)
504
            }, 50 + add)
505
        }, 43 + add)
506
    })
507
})