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