added explicit linking of required to externally required interfaces.
[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().length);
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().length);
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         RequiredInterface[] required = system.getRequiredInterfaces();
129         assertEquals(0, required.length);
130         ProvidedInterface[] provided = system.getProvidedInterfaces();
131         assertEquals(0, provided.length);
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()[0]
184                 .setProvider(new DefaultProvidedInterface("hallo", Float.class));
185         system.start();
186         RequiredInterface[] required = system.getRequiredInterfaces();
187         assertEquals(1, required.length);
188         ProvidedInterface[] provided = system.getProvidedInterfaces();
189         assertEquals(0, provided.length);
190     }
191
192     public void testCompositeWithExternalDependencesNotProvided() {
193         try {
194             Component environment = new Environment();
195             Component application = new Application();
196             Container system = new Container("all",
197                     new Component[] { application }, new ProvidedInterface[0],
198                     application.getRequiredInterfaces());
199             system.start();
200         } catch (SystemAssemblyException e) {
201             return;
202         }
203         fail();
204
205     }
206
207     public void testDuplicateComponent() {
208         try {
209             Component comp1 = new Application();
210             Component comp2 = new Application();
211             Container system = new Container("top");
212             system.addComponent(comp1).addComponent(comp2);
213         } catch (SystemAssemblyException e) {
214             return;
215         }
216         fail();
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());
237         environment.start(new DefaultScope(new ProvidedInterface[0]));
238         system.getRequiredInterfaces()[0].setProvider(environment
239                 .getProvidedInterfaces()[0]);
240         system.getRequiredInterfaces()[1].setProvider(environment
241                 .getProvidedInterfaces()[1]);
242
243         system.start();
244         RequiredInterface[] required = system.getRequiredInterfaces();
245         assertEquals(2, required.length);
246         ProvidedInterface[] provided = system.getProvidedInterfaces();
247         assertEquals(0, provided.length);
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()[0].setProvider(env
354                 .getProvidedInterfaces()[0]);
355         container.getRequiredInterfaces()[1].setProvider(env
356                 .getProvidedInterfaces()[1]);
357         Scope external = new DefaultScope(env.getProvidedInterfaces());
358         env.start(external);
359
360         container.start(external);
361         assertSame(env.getProvidedInterfaces()[0], container
362                 .getRequiredInterfaces()[0].getProvider());
363         assertSame(env.getProvidedInterfaces()[1], container
364                 .getRequiredInterfaces()[1].getProvider());
365         assertSame(env.getProvidedInterfaces()[0], application
366                 .getRequiredInterfaces()[0].getProvider());
367         assertSame(env.getProvidedInterfaces()[1], application
368                 .getRequiredInterfaces()[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()[0].setProvider(env
378                 .getProvidedInterfaces()[0]);
379         Scope external = new DefaultScope(new ProvidedInterface[0]);
380         external.publishInterface(env.getProvidedInterfaces()[0], env
381                 .getString());
382         container.start(external);
383         assertSame(env.getProvidedInterfaces()[0], container
384                 .getRequiredInterfaces()[0].getProvider());
385         assertNull(container.getRequiredInterfaces()[1].getProvider());
386         assertSame(env.getProvidedInterfaces()[0], application
387                 .getRequiredInterfaces()[0].getProvider());
388         assertNull(application.getRequiredInterfaces()[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()[0].setProvider(env
398                 .getProvidedInterfaces()[0]);
399         container.getRequiredInterfaces()[1].setProvider(env
400                 .getProvidedInterfaces()[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()[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", Integer.class));
534         container.addRequiredInterface(new DefaultRequiredInterface("x", String.class));
535         container.addRequiredInterface(new DefaultRequiredInterface("y", String.class));
536         
537         Application app = new Application("1");
538         container.addComponent(app);
539
540     
541         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
542             @Override
543             public void run() throws Exception {
544                 container.start();                
545             }
546         }, SystemAssemblyException.class);
547            
548         container.connectExternalRequired("1", app.getRequiredInterfaces()[0].getName(), 
549                 "y");
550         
551         ProvidedInterface i = new DefaultProvidedInterface("i", Integer.class);
552         ProvidedInterface x = new DefaultProvidedInterface("x", String.class);
553         ProvidedInterface y = new DefaultProvidedInterface("y", String.class);
554     
555         Scope externalScope = new DefaultScope(new ProvidedInterface[0]);
556         
557         externalScope.publishInterface(i, 100);
558         externalScope.publishInterface(x, "x-value");
559         externalScope.publishInterface(y, "y-value");
560         
561         container.getRequiredInterfaces()[0].setProvider(i);
562         container.getRequiredInterfaces()[1].setProvider(x);
563         container.getRequiredInterfaces()[2].setProvider(y);
564         
565         Scope runtime = container.start(externalScope);
566         
567         assertEquals("y-value", app.getString());
568         
569     }
570 }