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