Now basing the implementation on a component graph.
[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         container.start();
402         assertSame(env.getProvidedInterfaces()[0], container
403                 .getRequiredInterfaces()[0].getProvider());
404         assertSame(env.getProvidedInterfaces()[1], container
405                 .getRequiredInterfaces()[1].getProvider());
406         assertSame(env.getProvidedInterfaces()[0], application
407                 .getRequiredInterfaces()[0].getProvider());
408         assertSame(env.getProvidedInterfaces()[1], application
409                 .getRequiredInterfaces()[1].getProvider());
410     }
411
412     public void testSealed() {
413         final Container container = new Container("xx");
414         assertFalse(container.isSealed());
415         container.start();
416         assertTrue(container.isSealed());
417
418         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
419             @Override
420             public void run() throws Exception {
421                 container.addComponent(new Application());
422             }
423         }, SystemAssemblyException.class);
424
425         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
426             @Override
427             public void run() throws Exception {
428                 container.addRestriction(new InterfaceRestriction() {
429                     @Override
430                     public boolean isViolated(Component aClient,
431                             RequiredInterface aRequired, Component aServer,
432                             ProvidedInterface aProvided) {
433                         return false;
434                     }
435                 });
436             }
437         }, SystemAssemblyException.class);
438         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
439             @Override
440             public void run() throws Exception {
441                 container.addProvidedInterface(new DefaultProvidedInterface(
442                         "xx", String.class));
443             }
444         }, SystemAssemblyException.class);
445
446         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
447             @Override
448             public void run() throws Exception {
449                 container.addRequiredInterface(new DefaultRequiredInterface(
450                         "xx", String.class));
451             }
452         }, SystemAssemblyException.class);
453     }
454
455     public void testRestriction() {
456         Environment env1 = new Environment("env1");
457         Environment env2 = new Environment("env2");
458         Application app = new Application("app");
459         Container container = new Container("top").addComponent(env1)
460                 .addComponent(env2).addComponent(app);
461         container.addRestriction(new DefaultInterfaceRestriction("app", null,
462                 "env1", null));
463         container.start();
464         assertEquals(env1.getString(), app.getString());
465         assertFalse(env2.getString().equals(app.getString()));
466     }
467
468     public void testProvidedInDifferentScopes() {
469         // Scoping problem occurred. Externally and internally provided
470         // components clashed
471         // because unique id generation in the scope was wrong.
472
473         StringComponent str = new StringComponent("string");
474         Application app = new Application("app");
475         Container container = new Container("top").addComponent(str)
476                 .addComponent(app);
477         container.addRequiredInterface(new DefaultRequiredInterface("integer",
478                 Integer.class));
479
480         ProvidedInterface provided = new DefaultProvidedInterface("hallo",
481                 Integer.class);
482         container.getRequiredInterfaces()[0].setProvider(provided);
483
484         Scope external = new DefaultScope(new ProvidedInterface[0]);
485         external.publishInterface(provided, 100);
486         Scope scope = container.start(external);
487     }
488
489     public void testProvidedInterfaces() {
490         Environment env = new Environment(_tracker);
491         Container envcontainer = new Container("0").addComponent(env)
492                 .addProvidedInterface(
493                         new DefaultProvidedInterface("string", String.class))
494                 .addProvidedInterface(
495                         new DefaultProvidedInterface("integer", Integer.class));
496         Scope scope = envcontainer.start();
497
498         AssertionUtils.assertEquals(new String[] { "start.environment" },
499                 _tracker.getEvents(Thread.currentThread()).toArray(
500                         new String[0]));
501
502         envcontainer.stop(scope);
503     }
504
505     public void testCoupleTwoContainers() {
506         Environment env = new Environment(_tracker);
507         Container envcontainer = new Container("0").addComponent(env)
508                 .addProvidedInterface(
509                         new DefaultProvidedInterface("string", String.class))
510                 .addProvidedInterface(
511                         new DefaultProvidedInterface("integer", Integer.class));
512
513         Application app = new Application(_tracker);
514         Container appcontainer = new Container("1").addComponent(app)
515                 .addRequiredInterface(
516                         new DefaultRequiredInterface("string", String.class))
517                 .addRequiredInterface(
518                         new DefaultRequiredInterface("integer", Integer.class));
519
520         Container top = new Container("top");
521         top.addComponent(envcontainer).addComponent(appcontainer);
522
523         top.start();
524         AssertionUtils.assertEquals(new String[] { "start.environment", "start.application" },
525                 _tracker.getEvents(Thread.currentThread()).toArray(
526                         new String[0]));
527
528     }
529 }