2104e3a94e3dbba93db6d6de0c19cfe11983cf75
[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 }, dummy), noRestriction));
88         AssertionUtils.assertEquals(new ProvidedInterface[] { prov1 },
89                 Container.filterProvidedServices(client, req1, 
90                         createProvidedInput(new ProvidedInterface[] { prov1, prov2 }, dummy), noRestriction));
91         AssertionUtils.assertEquals(new ProvidedInterface[] { prov1, prov3 },
92                 Container.filterProvidedServices(client, req1, 
93                         createProvidedInput(new ProvidedInterface[] { prov1, prov3 }, dummy), noRestriction));
94         
95         InterfaceRestriction everything = new InterfaceRestriction() { 
96             @Override
97             public boolean isViolated(Component aClient,
98                     RequiredInterface aRequired, Component aServer,
99                     ProvidedInterface aProvided) {
100                 return true;
101             }
102         };
103         AssertionUtils.assertEquals(new ProvidedInterface[0],
104                 Container.filterProvidedServices(client, req1, 
105                         createProvidedInput(new ProvidedInterface[] { prov1, prov3 }, dummy), everything));
106         
107     }
108
109     public void testEnvironmentApplication() {
110         Environment environment = new Environment(_tracker);
111         Application application = new Application(_tracker);
112         Container container = new Container("root", new Component[] {
113                 environment, application }, new ProvidedInterface[0],
114                 new RequiredInterface[0]);
115         Scope scope = container.start();
116         assertTrue(container.isSealed());
117         AssertionUtils.assertEquals(new String[] { "start.environment",
118                 "start.application" }, _tracker.getEvents(
119                 Thread.currentThread()).toArray(new String[0]));
120         assertEquals(0, scope.getProvidedInterfaces().length);
121
122         assertEquals(environment.getString(), application.getString());
123         assertEquals(environment.getInteger(), application.getInteger());
124
125     }
126
127     public void testEnvironmentApplicationSimpleConstructor() {
128         Environment environment = new Environment(_tracker);
129         Application application = new Application(_tracker);
130         Container container = new Container("root").addComponent(environment)
131                 .addComponent(application);
132
133         Scope scope = container.start();
134         AssertionUtils.assertEquals(new String[] { "start.environment",
135                 "start.application" }, _tracker.getEvents(
136                 Thread.currentThread()).toArray(new String[0]));
137         assertEquals(0, scope.getProvidedInterfaces().length);
138
139         assertEquals(environment.getString(), application.getString());
140         assertEquals(environment.getInteger(), application.getInteger());
141
142     }
143
144     public void testApplicationEnvironment() {
145         try {
146             Component environment = new Environment();
147             Component application = new Application();
148             Container container = new Container("root", new Component[] {
149                     application, environment }, new ProvidedInterface[0],
150                     new RequiredInterface[0]);
151             container.start();
152         } catch (SystemAssemblyException e) {
153             // e.printStackTrace();
154             return;
155         }
156         fail();
157     }
158
159     public void testComposite() {
160         Component environment = new Environment(_tracker);
161         Component application = new Application(_tracker);
162         assertEquals(0, _tracker.getEventCount());
163
164         Container system = new Container("all", new Component[] { environment,
165                 application }, new ProvidedInterface[0],
166                 new RequiredInterface[0]);
167         Scope runtime = system.start();
168         RequiredInterface[] required = system.getRequiredInterfaces();
169         assertEquals(0, required.length);
170         ProvidedInterface[] provided = system.getProvidedInterfaces();
171         assertEquals(0, provided.length);
172
173         AssertionUtils.assertEquals(new String[] { "start.environment",
174                 "start.application" }, _tracker.getEvents(
175                 Thread.currentThread()).toArray(new String[0]));
176         _tracker.clear();
177
178         system.stop(runtime);
179         AssertionUtils.assertEquals(new String[] { "stop.application",
180                 "stop.environment" }, _tracker
181                 .getEvents(Thread.currentThread()).toArray(new String[0]));
182
183     }
184
185     public void testCompositeWithWrongProvidedInfo() {
186         try {
187             Component environment = new Environment();
188             Component application = new Application();
189             Container system = new Container("all", new Component[] {
190                     environment, application },
191                     new ProvidedInterface[] { new DefaultProvidedInterface(
192                             "float", Float.class) },
193                     new DefaultRequiredInterface[0]);
194             system.validate();
195         } catch (SystemAssemblyException e) {
196             return;
197         }
198         fail();
199     }
200
201     public void testCompositeRequiredInterfaceNotProvided() {
202         try {
203             Component environment = new Environment();
204             Component application = new Application();
205             Container system = new Container("all", new Component[] {
206                     environment, application }, new ProvidedInterface[0],
207                     new RequiredInterface[] { new DefaultRequiredInterface(
208                             "string", String.class) });
209             system.start();
210         } catch (SystemAssemblyException e) {
211             return;
212         }
213         fail();
214     }
215
216     public void testCompositeWithSuperfluousRequiredInfo() {
217         Component environment = new Environment();
218         Component application = new Application();
219         Container system = new Container("all", new Component[] { environment,
220                 application }, new ProvidedInterface[0],
221                 new RequiredInterface[] { new DefaultRequiredInterface("float",
222                         Float.class) });
223         system.getRequiredInterfaces()[0]
224                 .setProvider(new DefaultProvidedInterface("hallo", Float.class));
225         system.start();
226         RequiredInterface[] required = system.getRequiredInterfaces();
227         assertEquals(1, required.length);
228         ProvidedInterface[] provided = system.getProvidedInterfaces();
229         assertEquals(0, provided.length);
230     }
231
232     public void testCompositeWithExternalDependencesNotProvided() {
233         try {
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());
239             system.start();
240         } catch (SystemAssemblyException e) {
241             return;
242         }
243         fail();
244
245     }
246
247     public void testDuplicateComponent() {
248         try {
249             Component comp1 = new Application();
250             Component comp2 = new Application();
251             Container system = new Container("top");
252             system.addComponent(comp1).addComponent(comp2);
253         } catch (SystemAssemblyException e) {
254             return;
255         }
256         fail();
257     }
258
259     public void testInconsistentHierarchy() {
260         try {
261             Component comp = new Application();
262             Container system = new Container("top").addComponent(comp);
263             Container system2 = new Container("top2").addComponent(comp);
264         } catch (SystemAssemblyException e) {
265             return;
266         }
267         fail();
268     }
269
270     public void testCompositeWithExternalDependencesProvided() {
271
272         Component environment = new Environment();
273         Component application = new Application();
274         Container system = new Container("all",
275                 new Component[] { application }, new ProvidedInterface[0],
276                 application.getRequiredInterfaces());
277         environment.start(new DefaultScope(new ProvidedInterface[0]));
278         system.getRequiredInterfaces()[0].setProvider(environment
279                 .getProvidedInterfaces()[0]);
280         system.getRequiredInterfaces()[1].setProvider(environment
281                 .getProvidedInterfaces()[1]);
282
283         system.start();
284         RequiredInterface[] required = system.getRequiredInterfaces();
285         assertEquals(2, required.length);
286         ProvidedInterface[] provided = system.getProvidedInterfaces();
287         assertEquals(0, provided.length);
288
289     }
290
291     public void testAmbiguousInterfaces() {
292         try {
293             Component environment1 = new Environment();
294             Component environment2 = new Environment();
295             Component application = new Application();
296             Container container = new Container("root", new Component[] {
297                     environment1, environment2, application },
298                     new ProvidedInterface[0], new RequiredInterface[0]);
299             container.start();
300
301         } catch (SystemAssemblyException e) {
302             return;
303         }
304         fail();
305     }
306
307     public void testIncompleteRequirements() {
308         try {
309             Component application = new Application();
310             Container system = new Container("all",
311                     new Component[] { application }, new ProvidedInterface[0],
312                     new RequiredInterface[0]);
313             system.start();
314         } catch (SystemAssemblyException e) {
315             return;
316         }
317         fail();
318     }
319
320     public void testEnvironmentApplicationRollbackOnException()
321             throws Exception {
322         IMocksControl control = EasyMock.createStrictControl();
323
324         Environment environment = new Environment(_tracker);
325         Application application = control.createMock(Application.class,
326                 new ConstructorArgs(Application.class.getConstructor()),
327                 Application.class.getDeclaredMethod("doStart", Scope.class));
328
329         application.doStart(EasyMockMatchers.anyObject(Scope.class));
330         EasyMock.expectLastCall().andThrow(new RuntimeException());
331         control.replay();
332
333         try {
334             Container container = new Container("root", new Component[] {
335                     environment, application }, new ProvidedInterface[0],
336                     new RequiredInterface[0]);
337
338             container.start();
339         } catch (RuntimeException e) {
340             AssertionUtils.assertEquals(new String[] { "start.environment",
341                     "stop.environment" }, _tracker.getEvents(
342                     Thread.currentThread()).toArray(new String[0]));
343             return;
344         }
345         fail();
346     }
347
348     public void testEnvironmentApplicationRollbackOnExceptionWithExceptionOnStop()
349             throws Exception {
350         IMocksControl control = EasyMock.createControl();
351
352         Environment environment = new Environment(_tracker);
353         // Application 1 will throw an exception while stopping.
354         Application application1 = control.createMock(Application.class,
355                 new ConstructorArgs(Application.class.getConstructor()),
356                 Application.class.getDeclaredMethod("doStop", Object.class));
357
358         application1.doStop(EasyMock.anyObject());
359         EasyMock.expectLastCall().andThrow(new RuntimeException());
360
361         // application 2 will throw an exception while starting
362         Application application2 = control.createMock(Application.class,
363                 new ConstructorArgs(Application.class
364                         .getConstructor(String.class), "application2"),
365                 Application.class.getDeclaredMethod("doStart", Scope.class));
366
367         application2.doStart(EasyMockMatchers.anyObject(Scope.class));
368         EasyMock.expectLastCall().andThrow(new RuntimeException());
369
370         control.replay();
371
372         try {
373             Container container = new Container("root", new Component[] {
374                     environment, application1, application2 },
375                     new ProvidedInterface[0], new RequiredInterface[0]);
376
377             container.start();
378         } catch (RuntimeException e) {
379             AssertionUtils.assertEquals(new String[] { "start.environment",
380                     "stop.environment" }, _tracker.getEvents(
381                     Thread.currentThread()).toArray(new String[0]));
382             return;
383         }
384         fail();
385     }
386
387     public void testOptionalRequiredInterfaceProvidedOptionalInternal() {
388         Application application = new Application(true);
389         Container container = new Container("top",
390                 new Component[] { application }, new ProvidedInterface[0],
391                 Application.required(true));
392         Environment env = new Environment();
393         container.getRequiredInterfaces()[0].setProvider(env
394                 .getProvidedInterfaces()[0]);
395         container.getRequiredInterfaces()[1].setProvider(env
396                 .getProvidedInterfaces()[1]);
397         Scope external = new DefaultScope(env.getProvidedInterfaces());
398         env.start(external);
399
400         container.start(external);
401         assertSame(env.getProvidedInterfaces()[0], container
402                 .getRequiredInterfaces()[0].getProvider());
403         assertSame(env.getProvidedInterfaces()[1], container
404                 .getRequiredInterfaces()[1].getProvider());
405         assertSame(env.getProvidedInterfaces()[0], application
406                 .getRequiredInterfaces()[0].getProvider());
407         assertSame(env.getProvidedInterfaces()[1], application
408                 .getRequiredInterfaces()[1].getProvider());
409     }
410
411     public void testOptionalRequiredInterfaceNotProvidedOptionalInternal() {
412         Application application = new Application(true);
413         Container container = new Container("top",
414                 new Component[] { application }, new ProvidedInterface[0],
415                 Application.required(true));
416         Environment env = new Environment();
417         container.getRequiredInterfaces()[0].setProvider(env
418                 .getProvidedInterfaces()[0]);
419         Scope external = new DefaultScope(new ProvidedInterface[0]);
420         external.publishInterface(env.getProvidedInterfaces()[0], env
421                 .getString());
422         container.start(external);
423         assertSame(env.getProvidedInterfaces()[0], container
424                 .getRequiredInterfaces()[0].getProvider());
425         assertNull(container.getRequiredInterfaces()[1].getProvider());
426         assertSame(env.getProvidedInterfaces()[0], application
427                 .getRequiredInterfaces()[0].getProvider());
428         assertNull(application.getRequiredInterfaces()[1].getProvider());
429     }
430
431     public void testOptionalRequiredInterfaceProvidedMandatoryInternal() {
432         Application application = new Application();
433         Container container = new Container("top",
434                 new Component[] { application }, new ProvidedInterface[0],
435                 Application.required(true));
436         Environment env = new Environment();
437         container.getRequiredInterfaces()[0].setProvider(env
438                 .getProvidedInterfaces()[0]);
439         container.getRequiredInterfaces()[1].setProvider(env
440                 .getProvidedInterfaces()[1]);
441         container.start();
442         assertSame(env.getProvidedInterfaces()[0], container
443                 .getRequiredInterfaces()[0].getProvider());
444         assertSame(env.getProvidedInterfaces()[1], container
445                 .getRequiredInterfaces()[1].getProvider());
446         assertSame(env.getProvidedInterfaces()[0], application
447                 .getRequiredInterfaces()[0].getProvider());
448         assertSame(env.getProvidedInterfaces()[1], application
449                 .getRequiredInterfaces()[1].getProvider());
450     }
451
452     public void testSealed() {
453         final Container container = new Container("xx");
454         assertFalse(container.isSealed());
455         container.start();
456         assertTrue(container.isSealed());
457
458         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
459             @Override
460             public void run() throws Exception {
461                 container.addComponent(new Application());
462             }
463         }, SystemAssemblyException.class);
464
465         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
466             @Override
467             public void run() throws Exception {
468                 container.addRestriction(new InterfaceRestriction() {
469                     @Override
470                     public boolean isViolated(Component aClient,
471                             RequiredInterface aRequired, Component aServer,
472                             ProvidedInterface aProvided) {
473                         return false;
474                     }
475                 });
476             }
477         }, SystemAssemblyException.class);
478         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
479             @Override
480             public void run() throws Exception {
481                 container.addProvidedInterface(new DefaultProvidedInterface(
482                         "xx", String.class));
483             }
484         }, SystemAssemblyException.class);
485
486         AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
487             @Override
488             public void run() throws Exception {
489                 container.addRequiredInterface(new DefaultRequiredInterface(
490                         "xx", String.class));
491             }
492         }, SystemAssemblyException.class);
493     }
494
495     public void testRestriction() {
496         Environment env1 = new Environment("env1");
497         Environment env2 = new Environment("env2");
498         Application app = new Application("app");
499         Container container = new Container("top").addComponent(env1)
500                 .addComponent(env2).addComponent(app);
501         container.addRestriction(new DefaultInterfaceRestriction("app", null,
502                 "env1", null));
503         container.start();
504         assertEquals(env1.getString(), app.getString());
505         assertFalse(env2.getString().equals(app.getString()));
506     }
507     
508     public void testProvidedInDifferentScopes() { 
509         // Scoping problem occurred. Externally and internally provided components clashed
510         // because unique id generation in the scope was wrong. 
511         
512         StringComponent str = new StringComponent("string");
513         Application app = new Application("app");
514         Container container = new Container("top").addComponent(str).addComponent(app);
515         container.addRequiredInterface(new DefaultRequiredInterface("integer", Integer.class));
516         
517         ProvidedInterface provided = new DefaultProvidedInterface("hallo", Integer.class);
518         container.getRequiredInterfaces()[0]
519                                        .setProvider(provided);
520         
521         Scope external = new DefaultScope(new ProvidedInterface[0]);
522         external.publishInterface(provided, 100);
523         Scope scope = container.start(external);
524     }
525 }