7aed9f6b98c3469f4e2368fcf9ec132c8750bddd
[utils] / system / general / src / test / java / org / wamblee / system / container / ContainerTest.java
1 /*
2  * Copyright 2007 the original author or authors.
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 package org.wamblee.system.container;
17
18 import java.io.Serializable;
19 import java.util.ArrayList;
20 import java.util.List;
21
22 import junit.framework.TestCase;
23
24 import org.easymock.classextension.ConstructorArgs;
25 import org.easymock.classextension.EasyMock;
26 import org.easymock.classextension.IMocksControl;
27 import org.wamblee.general.Pair;
28 import org.wamblee.system.core.Component;
29 import org.wamblee.system.core.DefaultProvidedInterface;
30 import org.wamblee.system.core.DefaultRequiredInterface;
31 import org.wamblee.system.core.DefaultScope;
32 import org.wamblee.system.core.Environment;
33 import org.wamblee.system.core.ProvidedInterface;
34 import org.wamblee.system.core.RequiredInterface;
35 import org.wamblee.system.core.Scope;
36 import org.wamblee.system.core.StringComponent;
37 import org.wamblee.system.core.SystemAssemblyException;
38 import org.wamblee.test.AssertionUtils;
39 import org.wamblee.test.EasyMockMatchers;
40 import org.wamblee.test.EventTracker;
41
42 public class ContainerTest extends TestCase {
43
44     private EventTracker<String> _tracker;
45
46     @Override
47     protected void setUp() throws Exception {
48         super.setUp();
49         _tracker = new EventTracker<String>();
50     }
51
52     private static class MyMultiple implements Serializable, Runnable {
53         @Override
54         public void run() {
55             // Empty
56         }
57     }
58
59     private List<Pair<ProvidedInterface, Component>> createProvidedInput(
60             ProvidedInterface[] aProvided, Component aProvider) {
61         List<Pair<ProvidedInterface, Component>> result = new ArrayList<Pair<ProvidedInterface, Component>>();
62         for (ProvidedInterface provided : aProvided) {
63             result.add(new Pair<ProvidedInterface, Component>(provided,
64                     aProvider));
65         }
66         return result;
67     }
68
69     public void testEnvironmentApplication() {
70         Environment environment = new Environment(_tracker);
71         Application application = new Application(_tracker);
72         Container container = new Container("root", new Component[] {
73                 environment, application }, new ProvidedInterface[0],
74                 new RequiredInterface[0]);
75         Scope scope = container.start();
76         assertTrue(container.isSealed());
77         AssertionUtils.assertEquals(new String[] { "start.environment",
78                 "start.application" }, _tracker.getEvents(
79                 Thread.currentThread()).toArray(new String[0]));
80         assertEquals(0, scope.getProvidedInterfaces().size());
81
82         assertEquals(environment.getString(), application.getString());
83         assertEquals(environment.getInteger(), application.getInteger());
84
85     }
86
87     public void testEnvironmentApplicationSimpleConstructor() {
88         Environment environment = new Environment(_tracker);
89         Application application = new Application(_tracker);
90         Container container = new Container("root").addComponent(environment)
91                 .addComponent(application);
92
93         Scope scope = container.start();
94         AssertionUtils.assertEquals(new String[] { "start.environment",
95                 "start.application" }, _tracker.getEvents(
96                 Thread.currentThread()).toArray(new String[0]));
97         assertEquals(0, scope.getProvidedInterfaces().size());
98
99         assertEquals(environment.getString(), application.getString());
100         assertEquals(environment.getInteger(), application.getInteger());
101
102     }
103
104     public void testApplicationEnvironment() {
105         try {
106             Component<?> environment = new Environment();
107             Component<?> application = new Application();
108             Container container = new Container("root", new Component[] {
109                     application, environment }, new ProvidedInterface[0],
110                     new RequiredInterface[0]);
111             container.start();
112         } catch (SystemAssemblyException e) {
113             // e.printStackTrace();
114             return;
115         }
116         fail();
117     }
118
119     public void testComposite() {
120         Component<?> environment = new Environment(_tracker);
121         Component<?> application = new Application(_tracker);
122         assertEquals(0, _tracker.getEventCount());
123
124         Container system = new Container("all", new Component[] { environment,
125                 application }, new ProvidedInterface[0],
126                 new RequiredInterface[0]);
127         Scope runtime = system.start();
128         List<RequiredInterface> required = system.getRequiredInterfaces();
129         assertEquals(0, required.size());
130         List<ProvidedInterface> provided = system.getProvidedInterfaces();
131         assertEquals(0, provided.size());
132
133         AssertionUtils.assertEquals(new String[] { "start.environment",
134                 "start.application" }, _tracker.getEvents(
135                 Thread.currentThread()).toArray(new String[0]));
136         _tracker.clear();
137
138         system.stop(runtime);
139         AssertionUtils.assertEquals(new String[] { "stop.application",
140                 "stop.environment" }, _tracker
141                 .getEvents(Thread.currentThread()).toArray(new String[0]));
142
143     }
144
145     public void testCompositeWithWrongProvidedInfo() {
146         try {
147             Component<?> environment = new Environment();
148             Component<?> application = new Application();
149             Container system = new Container("all", new Component[] {
150                     environment, application },
151                     new ProvidedInterface[] { new DefaultProvidedInterface(
152                             "float", Float.class) },
153                     new DefaultRequiredInterface[0]);
154             system.validate();
155         } catch (SystemAssemblyException e) {
156             return;
157         }
158         fail();
159     }
160
161     public void testCompositeRequiredInterfaceNotProvided() {
162         try {
163             Component<?> environment = new Environment();
164             Component<?> application = new Application();
165             Container system = new Container("all", new Component[] {
166                     environment, application }, new ProvidedInterface[0],
167                     new RequiredInterface[] { new DefaultRequiredInterface(
168                             "string", String.class) });
169             system.start();
170         } catch (SystemAssemblyException e) {
171             return;
172         }
173         fail();
174     }
175
176     public void testCompositeWithSuperfluousRequiredInfo() {
177         Component<?> environment = new Environment();
178         Component<?> application = new Application();
179         Container system = new Container("all", new Component[] { environment,
180                 application }, new ProvidedInterface[0],
181                 new RequiredInterface[] { new DefaultRequiredInterface("float",
182                         Float.class) });
183         system.getRequiredInterfaces().get(0)
184                 .setProvider(new DefaultProvidedInterface("hallo", Float.class));
185         system.start();
186         List<RequiredInterface> required = system.getRequiredInterfaces();
187         assertEquals(1, required.size());
188         List<ProvidedInterface> provided = system.getProvidedInterfaces();
189         assertEquals(0, provided.size());
190     }
191
192     public void testCompositeWithExternalDependencesNotProvided() {
193         try {
194             Component<?> application = new Application();
195            
196             Container system = new Container("all",
197                     new Component[] { application }, new ProvidedInterface[0],
198                     application.getRequiredInterfaces().toArray(new RequiredInterface[0]));
199             system.start();
200         } catch (SystemAssemblyException e) {
201             return;
202         }
203         fail();
204     }
205
206     public void testDuplicateComponent() {
207         try {
208             Component<?> comp1 = new Application();
209             Component<?> comp2 = new Application();
210             Container system = new Container("top");
211             system.addComponent(comp1).addComponent(comp2);
212         } catch (SystemAssemblyException e) {
213             return;
214         }
215         fail();
216     }
217
218
219     public void testInconsistentHierarchy() {
220         try {
221             Component<?> comp = new Application();
222             Container system = new Container("top").addComponent(comp);
223             Container system2 = new Container("top2").addComponent(comp);
224         } catch (SystemAssemblyException e) {
225             return;
226         }
227         fail();
228     }
229
230     public void testCompositeWithExternalDependencesProvided() {
231
232         Component<?> environment = new Environment();
233         Component<?> application = new Application();
234         Container system = new Container("all",
235                 new Component[] { application }, new ProvidedInterface[0],
236                 application.getRequiredInterfaces().toArray(new RequiredInterface[0]));
237         environment.start(new DefaultScope(new ProvidedInterface[0]));
238         system.getRequiredInterfaces().get(0).setProvider(environment
239                 .getProvidedInterfaces().get(0));
240         system.getRequiredInterfaces().get(1).setProvider(environment
241                 .getProvidedInterfaces().get(1));
242
243         system.start();
244         List<RequiredInterface> required = system.getRequiredInterfaces();
245         assertEquals(2, required.size());
246         List<ProvidedInterface> provided = system.getProvidedInterfaces();
247         assertEquals(0, provided.size());
248
249     }
250
251     public void testAmbiguousInterfaces() {
252         try {
253             Component<?> environment1 = new Environment();
254             Component<?> environment2 = new Environment();
255             Component<?> application = new Application();
256             Container container = new Container("root", new Component[] {
257                     environment1, environment2, application },
258                     new ProvidedInterface[0], new RequiredInterface[0]);
259             container.start();
260
261         } catch (SystemAssemblyException e) {
262             return;
263         }
264         fail();
265     }
266
267     public void testIncompleteRequirements() {
268         try {
269             Component<?> application = new Application();
270             Container system = new Container("all",
271                     new Component[] { application }, new ProvidedInterface[0],
272                     new RequiredInterface[0]);
273             system.start();
274         } catch (SystemAssemblyException e) {
275             return;
276         }
277         fail();
278     }
279
280     public void testEnvironmentApplicationRollbackOnException()
281             throws Exception {
282         IMocksControl control = EasyMock.createStrictControl();
283
284         Environment environment = new Environment(_tracker);
285         Application application = control.createMock(Application.class,
286                 new ConstructorArgs(Application.class.getConstructor()),
287                 Application.class.getDeclaredMethod("doStart", Scope.class));
288
289         application.doStart(EasyMockMatchers.anyObject(Scope.class));
290         EasyMock.expectLastCall().andThrow(new RuntimeException());
291         control.replay();
292
293         try {
294             Container container = new Container("root", new Component[] {
295                     environment, application }, new ProvidedInterface[0],
296                     new RequiredInterface[0]);
297
298             container.start();
299         } catch (RuntimeException e) {
300             AssertionUtils.assertEquals(new String[] { "start.environment",
301                     "stop.environment" }, _tracker.getEvents(
302                     Thread.currentThread()).toArray(new String[0]));
303             return;
304         }
305         fail();
306     }
307
308     public void testEnvironmentApplicationRollbackOnExceptionWithExceptionOnStop()
309             throws Exception {
310         IMocksControl control = EasyMock.createControl();
311
312         Environment environment = new Environment(_tracker);
313         // Application 1 will throw an exception while stopping.
314         Application application1 = control.createMock(Application.class,
315                 new ConstructorArgs(Application.class.getConstructor()),
316                 Application.class.getDeclaredMethod("doStop", Object.class));
317
318         application1.doStop(EasyMock.anyObject());
319         EasyMock.expectLastCall().andThrow(new RuntimeException());
320
321         // application 2 will throw an exception while starting
322         Application application2 = control.createMock(Application.class,
323                 new ConstructorArgs(Application.class
324                         .getConstructor(String.class), "application2"),
325                 Application.class.getDeclaredMethod("doStart", Scope.class));
326
327         application2.doStart(EasyMockMatchers.anyObject(Scope.class));
328         EasyMock.expectLastCall().andThrow(new RuntimeException());
329
330         control.replay();
331
332         try {
333             Container container = new Container("root", new Component[] {
334                     environment, application1, application2 },
335                     new ProvidedInterface[0], new RequiredInterface[0]);
336
337             container.start();
338         } catch (RuntimeException e) {
339             AssertionUtils.assertEquals(new String[] { "start.environment",
340                     "stop.environment" }, _tracker.getEvents(
341                     Thread.currentThread()).toArray(new String[0]));
342             return;
343         }
344         fail();
345     }
346
347     public void testOptionalRequiredInterfaceProvidedOptionalInternal() {
348         Application application = new Application(true);
349         Container container = new Container("top",
350                 new Component[] { application }, new ProvidedInterface[0],
351                 Application.required(true));
352         Environment env = new Environment();
353         container.getRequiredInterfaces().get(0).setProvider(env
354                 .getProvidedInterfaces().get(0));
355         container.getRequiredInterfaces().get(1).setProvider(env
356                 .getProvidedInterfaces().get(1));
357         Scope external = new DefaultScope(env.getProvidedInterfaces());
358         env.start(external);
359
360         container.start(external);
361         assertSame(env.getProvidedInterfaces().get(0), container
362                 .getRequiredInterfaces().get(0).getProvider());
363         assertSame(env.getProvidedInterfaces().get(1), container
364                 .getRequiredInterfaces().get(1).getProvider());
365         assertSame(env.getProvidedInterfaces().get(0), application
366                 .getRequiredInterfaces().get(0).getProvider());
367         assertSame(env.getProvidedInterfaces().get(1), application
368                 .getRequiredInterfaces().get(1).getProvider());
369     }
370
371     public void testOptionalRequiredInterfaceNotProvidedOptionalInternal() {
372         Application application = new Application(true);
373         Container container = new Container("top",
374                 new Component[] { application }, new ProvidedInterface[0],
375                 Application.required(true));
376         Environment env = new Environment();
377         container.getRequiredInterfaces().get(0).setProvider(env
378                 .getProvidedInterfaces().get(0));
379         Scope external = new DefaultScope(new ProvidedInterface[0]);
380         external.publishInterface(env.getProvidedInterfaces().get(0), env
381                 .getString());
382         container.start(external);
383         assertSame(env.getProvidedInterfaces().get(0), container
384                 .getRequiredInterfaces().get(0).getProvider());
385         assertNull(container.getRequiredInterfaces().get(1).getProvider());
386         assertSame(env.getProvidedInterfaces().get(0), application
387                 .getRequiredInterfaces().get(0).getProvider());
388         assertNull(application.getRequiredInterfaces().get(1).getProvider());
389     }
390
391     public void testOptionalRequiredInterfaceProvidedMandatoryInternal() {
392         Application application = new Application();
393         Container container = new Container("top",
394                 new Component[] { application }, new ProvidedInterface[0],
395                 Application.required(true));
396         Environment env = new Environment();
397         container.getRequiredInterfaces().get(0).setProvider(env
398                 .getProvidedInterfaces().get(0));
399         container.getRequiredInterfaces().get(1).setProvider(env
400                 .getProvidedInterfaces().get(1));
401         try {
402             container.start();
403         } catch (SystemAssemblyException e) {
404             return;
405         }
406         fail();
407     }
408
409     public void testSealed() {
410         final Container container = new Container("xx");
411         assertFalse(container.isSealed());
412         container.start();
413         assertTrue(container.isSealed());
414
415         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
416             @Override
417             public void run() throws Exception {
418                 container.addComponent(new Application());
419             }
420         }, SystemAssemblyException.class);
421
422         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
423             @Override
424             public void run() throws Exception {
425                 container.connectRequiredProvided("x", "y", "a", "b");
426             }
427         }, SystemAssemblyException.class);
428         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
429             @Override
430             public void run() throws Exception {
431                 container.connectExternalRequired("x", "y", "a");
432             }
433         }, SystemAssemblyException.class);
434         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
435             @Override
436             public void run() throws Exception {
437                 container.connectExternalProvided("x", "y", "z");
438             }
439         }, SystemAssemblyException.class);
440         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
441             @Override
442             public void run() throws Exception {
443                 container.addProvidedInterface(new DefaultProvidedInterface(
444                         "xx", String.class));
445             }
446         }, SystemAssemblyException.class);
447
448         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
449             @Override
450             public void run() throws Exception {
451                 container.addRequiredInterface(new DefaultRequiredInterface(
452                         "xx", String.class));
453             }
454         }, SystemAssemblyException.class);
455     }
456
457     public void testRestriction() {
458         Environment env1 = new Environment("env1");
459         Environment env2 = new Environment("env2");
460         Application app = new Application("app");
461         Container container = new Container("top").addComponent(env1)
462                 .addComponent(env2).addComponent(app);
463         container.connectRequiredProvided("app", null, "env1", null);
464         container.start();
465         assertEquals(env1.getString(), app.getString());
466         assertFalse(env2.getString().equals(app.getString()));
467     }
468
469     public void testProvidedInDifferentScopes() {
470         // Scoping problem occurred. Externally and internally provided
471         // components clashed
472         // because unique id generation in the scope was wrong.
473
474         StringComponent str = new StringComponent("string");
475         Application app = new Application("app");
476         Container container = new Container("top").addComponent(str)
477                 .addComponent(app);
478         container.addRequiredInterface(new DefaultRequiredInterface("integer",
479                 Integer.class));
480
481         ProvidedInterface provided = new DefaultProvidedInterface("hallo",
482                 Integer.class);
483         container.getRequiredInterfaces().get(0).setProvider(provided);
484
485         Scope external = new DefaultScope(new ProvidedInterface[0]);
486         external.publishInterface(provided, 100);
487         Scope scope = container.start(external);
488     }
489
490     public void testProvidedInterfaces() {
491         Environment env = new Environment(_tracker);
492         Container envcontainer = new Container("0").addComponent(env)
493                 .addProvidedInterface(
494                         new DefaultProvidedInterface("string", String.class))
495                 .addProvidedInterface(
496                         new DefaultProvidedInterface("integer", Integer.class));
497         Scope scope = envcontainer.start();
498
499         AssertionUtils.assertEquals(new String[] { "start.environment" },
500                 _tracker.getEvents(Thread.currentThread()).toArray(
501                         new String[0]));
502
503         envcontainer.stop(scope);
504     }
505
506     public void testCoupleTwoContainers() {
507         Environment env = new Environment(_tracker);
508         Container envcontainer = new Container("0").addComponent(env)
509                 .addProvidedInterface(
510                         new DefaultProvidedInterface("string", String.class))
511                 .addProvidedInterface(
512                         new DefaultProvidedInterface("integer", Integer.class));
513
514         Application app = new Application(_tracker);
515         Container appcontainer = new Container("1").addComponent(app)
516                 .addRequiredInterface(
517                         new DefaultRequiredInterface("string", String.class))
518                 .addRequiredInterface(
519                         new DefaultRequiredInterface("integer", Integer.class));
520
521         Container top = new Container("top");
522         top.addComponent(envcontainer).addComponent(appcontainer);
523
524         top.start();
525         AssertionUtils.assertEquals(new String[] { "start.environment",
526                 "start.application" }, _tracker.getEvents(
527                 Thread.currentThread()).toArray(new String[0]));
528
529     }
530
531     public void testNonUniqueRequiredInterface() {
532         final Container container = new Container("top");
533         container.addRequiredInterface(new DefaultRequiredInterface("i",
534                 Integer.class));
535         container.addRequiredInterface(new DefaultRequiredInterface("x",
536                 String.class));
537         container.addRequiredInterface(new DefaultRequiredInterface("y",
538                 String.class));
539
540         Application app = new Application("1");
541         container.addComponent(app);
542
543         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
544             @Override
545             public void run() throws Exception {
546                 container.start();
547             }
548         }, SystemAssemblyException.class);
549
550         container.connectExternalRequired("1", app.getRequiredInterfaces().get(0)
551                 .getName(), "y");
552
553         ProvidedInterface i = new DefaultProvidedInterface("i", Integer.class);
554         ProvidedInterface x = new DefaultProvidedInterface("x", String.class);
555         ProvidedInterface y = new DefaultProvidedInterface("y", String.class);
556
557         Scope externalScope = new DefaultScope(new ProvidedInterface[0]);
558
559         externalScope.publishInterface(i, 100);
560         externalScope.publishInterface(x, "x-value");
561         externalScope.publishInterface(y, "y-value");
562
563         container.getRequiredInterfaces().get(0).setProvider(i);
564         container.getRequiredInterfaces().get(1).setProvider(x);
565         container.getRequiredInterfaces().get(2).setProvider(y);
566
567         Scope runtime = container.start(externalScope);
568
569         assertEquals("y-value", app.getString());
570
571     }
572
573     public void testNonUniqueProvidedInterface() {
574
575         final Container container = new Container("top")
576                 .addProvidedInterface(new DefaultProvidedInterface("external",
577                         String.class));
578         Environment env1 = new Environment("env1");
579         Environment env2 = new Environment("env2");
580
581         container.addComponent(env1);
582         container.addComponent(env2);
583
584         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
585             @Override
586             public void run() throws Exception {
587                 container.start();
588             }
589         }, SystemAssemblyException.class);
590
591         // now choose env2
592
593         container.connectExternalProvided(container.getProvidedInterfaces().get(0)
594                 .getName(), env2.getName(), env2.getProvidedInterfaces().get(0)
595                 .getName());
596
597         Scope scope = container.start();
598
599         // check the value of the provided interface of the container
600
601         String value = scope.getInterfaceImplementation(container
602                 .getProvidedInterfaces().get(0), String.class);
603         assertNotNull(value);
604         assertEquals(value, env2.getString());
605         assertFalse(value.equals(env1.getString()));
606     }
607 }