(no commit message)
[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         assertEquals(env1.getInteger(), app.getInteger());
467         assertFalse(env2.getString().equals(app.getString()));
468         assertFalse(env2.getInteger().equals(app.getInteger()));
469     }
470     
471     public void testRestrictionWithFromAndToInterfaceName() {
472         Environment env1 = new Environment("env1");
473         Environment env2 = new Environment("env2");
474         Application app = new Application("app");
475         Container container = new Container("top").addComponent(env1)
476                 .addComponent(env2).addComponent(app);
477         container.connectRequiredProvided("app", app.getRequiredInterfaces().get(0).getName(), 
478                         "env1", env1.getProvidedInterfaces().get(0).getName());
479         container.connectRequiredProvided("app", app.getRequiredInterfaces().get(1).getName(), 
480                         "env2", env2.getProvidedInterfaces().get(1).getName());
481         container.start();
482         assertEquals(env1.getString(), app.getString());
483         assertEquals(env2.getInteger(), app.getInteger());
484         assertFalse(env2.getString().equals(app.getString()));
485         assertFalse(env1.getInteger().equals(app.getInteger()));
486     }
487     
488     public void testRestrictionWrongComponentNames() {
489         Environment env1 = new Environment("env1");
490         Environment env2 = new Environment("env2");
491         Application app = new Application("app");
492         final Container container = new Container("top").addComponent(env1)
493                 .addComponent(env2).addComponent(app);
494         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
495                 @Override
496                 public void run() throws Exception {
497                         container.connectRequiredProvided("app2", null, "env1", null);
498                 }
499         }, SystemAssemblyException.class); 
500         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
501                 @Override
502                 public void run() throws Exception {
503                         container.connectRequiredProvided("app", null, "env3", null);
504                 }
505         }, SystemAssemblyException.class); 
506     }
507     
508     public void testRestrictionWrongInterfaceNames() {
509         final Environment env1 = new Environment("env1");
510         Environment env2 = new Environment("env2");
511         final Application app = new Application("app");
512         final Container container = new Container("top").addComponent(env1)
513                 .addComponent(env2).addComponent(app);
514         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
515                 @Override
516                 public void run() throws Exception {
517                         container.connectRequiredProvided("app", 
518                                         app.getRequiredInterfaces().get(0).getName() + "xxx", "env1", null);
519                 }
520         }, SystemAssemblyException.class); 
521         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
522                 @Override
523                 public void run() throws Exception {
524                         container.connectRequiredProvided("app", null, "env1", 
525                                         env1.getProvidedInterfaces().get(0).getName() + "yyy");
526                 }
527         }, SystemAssemblyException.class); 
528     }
529
530
531     public void testProvidedInDifferentScopes() {
532         // Scoping problem occurred. Externally and internally provided
533         // components clashed
534         // because unique id generation in the scope was wrong.
535
536         StringComponent str = new StringComponent("string");
537         Application app = new Application("app");
538         Container container = new Container("top").addComponent(str)
539                 .addComponent(app);
540         container.addRequiredInterface(new DefaultRequiredInterface("integer",
541                 Integer.class));
542
543         ProvidedInterface provided = new DefaultProvidedInterface("hallo",
544                 Integer.class);
545         container.getRequiredInterfaces().get(0).setProvider(provided);
546
547         Scope external = new DefaultScope(new ProvidedInterface[0]);
548         external.publishInterface(provided, 100);
549         Scope scope = container.start(external);
550     }
551
552     public void testProvidedInterfaces() {
553         Environment env = new Environment(_tracker);
554         Container envcontainer = new Container("0").addComponent(env)
555                 .addProvidedInterface(
556                         new DefaultProvidedInterface("string", String.class))
557                 .addProvidedInterface(
558                         new DefaultProvidedInterface("integer", Integer.class));
559         Scope scope = envcontainer.start();
560
561         AssertionUtils.assertEquals(new String[] { "start.environment" },
562                 _tracker.getEvents(Thread.currentThread()).toArray(
563                         new String[0]));
564
565         envcontainer.stop(scope);
566     }
567
568     public void testCoupleTwoContainers() {
569         Environment env = new Environment(_tracker);
570         Container envcontainer = new Container("0").addComponent(env)
571                 .addProvidedInterface(
572                         new DefaultProvidedInterface("string", String.class))
573                 .addProvidedInterface(
574                         new DefaultProvidedInterface("integer", Integer.class));
575
576         Application app = new Application(_tracker);
577         Container appcontainer = new Container("1").addComponent(app)
578                 .addRequiredInterface(
579                         new DefaultRequiredInterface("string", String.class))
580                 .addRequiredInterface(
581                         new DefaultRequiredInterface("integer", Integer.class));
582
583         Container top = new Container("top");
584         top.addComponent(envcontainer).addComponent(appcontainer);
585
586         top.start();
587         AssertionUtils.assertEquals(new String[] { "start.environment",
588                 "start.application" }, _tracker.getEvents(
589                 Thread.currentThread()).toArray(new String[0]));
590
591     }
592
593     public void testNonUniqueRequiredInterface() {
594         final Container container = new Container("top");
595         container.addRequiredInterface(new DefaultRequiredInterface("i",
596                 Integer.class));
597         container.addRequiredInterface(new DefaultRequiredInterface("x",
598                 String.class));
599         container.addRequiredInterface(new DefaultRequiredInterface("y",
600                 String.class));
601
602         Application app = new Application("1");
603         container.addComponent(app);
604
605         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
606             @Override
607             public void run() throws Exception {
608                 container.start();
609             }
610         }, SystemAssemblyException.class);
611
612         container.connectExternalRequired("1", app.getRequiredInterfaces().get(0)
613                 .getName(), "y");
614
615         ProvidedInterface i = new DefaultProvidedInterface("i", Integer.class);
616         ProvidedInterface x = new DefaultProvidedInterface("x", String.class);
617         ProvidedInterface y = new DefaultProvidedInterface("y", String.class);
618
619         Scope externalScope = new DefaultScope(new ProvidedInterface[0]);
620
621         externalScope.publishInterface(i, 100);
622         externalScope.publishInterface(x, "x-value");
623         externalScope.publishInterface(y, "y-value");
624
625         container.getRequiredInterfaces().get(0).setProvider(i);
626         container.getRequiredInterfaces().get(1).setProvider(x);
627         container.getRequiredInterfaces().get(2).setProvider(y);
628
629         Scope runtime = container.start(externalScope);
630
631         assertEquals("y-value", app.getString());
632
633     }
634
635     public void testNonUniqueProvidedInterface() {
636
637         final Container container = new Container("top")
638                 .addProvidedInterface(new DefaultProvidedInterface("external",
639                         String.class));
640         Environment env1 = new Environment("env1");
641         Environment env2 = new Environment("env2");
642
643         container.addComponent(env1);
644         container.addComponent(env2);
645
646         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
647             @Override
648             public void run() throws Exception {
649                 container.start();
650             }
651         }, SystemAssemblyException.class);
652
653         // now choose env2
654
655         container.connectExternalProvided(container.getProvidedInterfaces().get(0)
656                 .getName(), env2.getName(), env2.getProvidedInterfaces().get(0)
657                 .getName());
658
659         Scope scope = container.start();
660
661         // check the value of the provided interface of the container
662
663         String value = scope.getInterfaceImplementation(container
664                 .getProvidedInterfaces().get(0), String.class);
665         assertNotNull(value);
666         assertEquals(value, env2.getString());
667         assertFalse(value.equals(env1.getString()));
668     }
669 }