now allowing components and interfaces to be added after construction.
[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.Arrays;
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.test.AssertionUtils;
28 import org.wamblee.test.EasyMockMatchers;
29 import org.wamblee.test.EventTracker;
30
31 public class ContainerTest extends TestCase {
32
33         private EventTracker<String> _tracker;
34
35         @Override
36         protected void setUp() throws Exception {
37                 super.setUp();
38                 _tracker = new EventTracker<String>();
39         }
40
41         private static class MyMultiple implements Serializable, Runnable {
42                 @Override
43                 public void run() {
44                         // Empty
45                 }
46         }
47
48         public void testFilterProvided() {
49                 RequiredInterface req1 = new DefaultRequiredInterface("name",
50                                 Runnable.class);
51                 RequiredInterface req2 = new DefaultRequiredInterface("name",
52                                 Serializable.class);
53                 ProvidedInterface prov1 = new DefaultProvidedInterface("name",
54                                 Runnable.class);
55                 ProvidedInterface prov2 = new DefaultProvidedInterface("name",
56                                 Serializable.class);
57                 ProvidedInterface prov3 = new DefaultProvidedInterface("name",
58                                 MyMultiple.class);
59
60                 AssertionUtils.assertEquals(new RequiredInterface[] { req1 }, Container
61                                 .filterRequiredServices(prov1, Arrays
62                                                 .asList(new RequiredInterface[] { req1 })));
63                 AssertionUtils.assertEquals(new RequiredInterface[] { req1 }, Container
64                                 .filterRequiredServices(prov1, Arrays
65                                                 .asList(new RequiredInterface[] { req1, req2 })));
66                 AssertionUtils.assertEquals(new RequiredInterface[] { req1, req2 },
67                                 Container.filterRequiredServices(prov3, Arrays
68                                                 .asList(new RequiredInterface[] { req1, req2 })));
69
70                 AssertionUtils.assertEquals(new ProvidedInterface[] { prov1 },
71                                 Container.filterProvidedServices(req1, Arrays
72                                                 .asList(new ProvidedInterface[] { prov1 })));
73                 AssertionUtils.assertEquals(new ProvidedInterface[] { prov1 },
74                                 Container.filterProvidedServices(req1, Arrays
75                                                 .asList(new ProvidedInterface[] { prov1, prov2 })));
76                 AssertionUtils.assertEquals(new ProvidedInterface[] { prov1, prov3 },
77                                 Container.filterProvidedServices(req1, Arrays
78                                                 .asList(new ProvidedInterface[] { prov1, prov3 })));
79         }
80
81         public void testEnvironmentApplication() {
82                 Environment environment = new Environment(_tracker);
83                 Application application = new Application(_tracker);
84                 Container container = new Container("root", new Component[] {
85                                 environment, application }, new ProvidedInterface[0],
86                                 new RequiredInterface[0]);
87
88                 Scope scope = container.start();
89                 assertTrue(container.isSealed());
90                 AssertionUtils.assertEquals(new String[] { "start.environment",
91                                 "start.application" }, _tracker.getEvents(
92                                 Thread.currentThread()).toArray(new String[0]));
93                 assertEquals(0, scope.getProvidedInterfaces().length);
94                 
95                 assertEquals(environment.getString(), application.getString());
96                 assertEquals(environment.getInteger(), application.getInteger());
97
98         }
99         
100         public void testEnvironmentApplicationSimpleConstructor() {
101                 Environment environment = new Environment(_tracker);
102                 Application application = new Application(_tracker);
103                 Container container = new Container("root").
104                   addComponent(environment).addComponent(application);
105                 
106                 Scope scope = container.start();
107                 AssertionUtils.assertEquals(new String[] { "start.environment",
108                                 "start.application" }, _tracker.getEvents(
109                                 Thread.currentThread()).toArray(new String[0]));
110                 assertEquals(0, scope.getProvidedInterfaces().length);
111                 
112                 assertEquals(environment.getString(), application.getString());
113                 assertEquals(environment.getInteger(), application.getInteger());
114
115         }
116
117         public void testApplicationEnvironment() {
118                 try {
119                         Component environment = new Environment();
120                         Component application = new Application();
121                         Container container = new Container("root", new Component[] {
122                                         application, environment }, new ProvidedInterface[0],
123                                         new RequiredInterface[0]);
124                         container.start();
125                 } catch (SystemAssemblyException e) {
126                         // e.printStackTrace();
127                         return;
128                 }
129                 fail();
130         }
131
132         public void testComposite() {
133                 Component environment = new Environment(_tracker);
134                 Component application = new Application(_tracker);
135                 assertEquals(0, _tracker.getEventCount());
136
137                 Container system = new Container("all", new Component[] { environment,
138                                 application }, new ProvidedInterface[0],
139                                 new RequiredInterface[0]);
140                 Scope runtime = system.start();
141                 RequiredInterface[] required = system.getRequiredInterfaces();
142                 assertEquals(0, required.length);
143                 ProvidedInterface[] provided = system.getProvidedInterfaces();
144                 assertEquals(0, provided.length);
145
146                 AssertionUtils.assertEquals(new String[] { "start.environment",
147                                 "start.application" }, _tracker.getEvents(
148                                 Thread.currentThread()).toArray(new String[0]));
149                 _tracker.clear();
150
151                 system.stop(runtime);
152                 AssertionUtils.assertEquals(new String[] { "stop.application",
153                                 "stop.environment" }, _tracker
154                                 .getEvents(Thread.currentThread()).toArray(new String[0]));
155
156         }
157
158         public void testCompositeWithWrongProvidedInfo() {
159                 try {
160                         Component environment = new Environment();
161                         Component application = new Application();
162                         Container system = new Container("all", new Component[] {
163                                         environment, application },
164                                         new ProvidedInterface[] { new DefaultProvidedInterface(
165                                                         "float", Float.class) },
166                                         new DefaultRequiredInterface[0]);
167                 } catch (SystemAssemblyException e) {
168                         return;
169                 }
170                 fail();
171         }
172
173         public void testCompositeRequiredInterfaceNotProvided() {
174                 try {
175                         Component environment = new Environment();
176                         Component application = new Application();
177                         Container system = new Container("all", new Component[] {
178                                         environment, application }, new ProvidedInterface[0],
179                                         new RequiredInterface[] { new DefaultRequiredInterface(
180                                                         "string", String.class) });
181                         system.start();
182                 } catch (SystemAssemblyException e) {
183                         return;
184                 }
185                 fail();
186         }
187
188         public void testCompositeWithSuperfluousRequiredInfo() {
189                 Component environment = new Environment();
190                 Component application = new Application();
191                 Container system = new Container("all", new Component[] { environment,
192                                 application }, new ProvidedInterface[0],
193                                 new RequiredInterface[] { new DefaultRequiredInterface(
194                                                 "float", Float.class) });
195                 system.getRequiredInterfaces()[0]
196                                 .setProvider(new DefaultProvidedInterface("hallo", Float.class));
197                 system.start();
198                 RequiredInterface[] required = system.getRequiredInterfaces();
199                 assertEquals(1, required.length);
200                 ProvidedInterface[] provided = system.getProvidedInterfaces();
201                 assertEquals(0, provided.length);
202         }
203
204         public void testCompositeWithExternalDependencesNotProvided() {
205                 try {
206                         Component environment = new Environment();
207                         Component application = new Application();
208                         Container system = new Container("all",
209                                         new Component[] { application }, new ProvidedInterface[0],
210                                         application.getRequiredInterfaces());
211                         system.start();
212                 } catch (SystemAssemblyException e) {
213                         return;
214                 }
215                 fail();
216
217         }
218
219         public void testCompositeWithExternalDependencesProvided() {
220
221                 Component environment = new Environment();
222                 Component application = new Application();
223                 Container system = new Container("all",
224                                 new Component[] { application }, new ProvidedInterface[0],
225                                 application.getRequiredInterfaces());
226                 environment.start(new DefaultScope(new ProvidedInterface[0]));
227                 system.getRequiredInterfaces()[0].setProvider(environment
228                                 .getProvidedInterfaces()[0]);
229                 system.getRequiredInterfaces()[1].setProvider(environment
230                                 .getProvidedInterfaces()[1]);
231
232                 system.start();
233                 RequiredInterface[] required = system.getRequiredInterfaces();
234                 assertEquals(2, required.length);
235                 ProvidedInterface[] provided = system.getProvidedInterfaces();
236                 assertEquals(0, provided.length);
237
238         }
239
240         public void testAmbiguousInterfaces() {
241                 try {
242                         Component environment1 = new Environment();
243                         Component environment2 = new Environment();
244                         Component application = new Application();
245                         Container container = new Container("root", new Component[] {
246                                         environment1, environment2, application },
247                                         new ProvidedInterface[0], new RequiredInterface[0]);
248                         container.start();
249
250                 } catch (SystemAssemblyException e) {
251                         return;
252                 }
253                 fail();
254         }
255
256         public void testIncompleteRequirements() {
257                 try {
258                         Component application = new Application();
259                         Container system = new Container("all",
260                                         new Component[] { application }, new ProvidedInterface[0],
261                                         new RequiredInterface[0]);
262                         system.start();
263                 } catch (SystemAssemblyException e) {
264                         return;
265                 }
266                 fail();
267         }
268
269         public void testEnvironmentApplicationRollbackOnException()
270                         throws Exception {
271                 IMocksControl control = EasyMock.createStrictControl();
272
273                 Environment environment = new Environment(_tracker);
274                 Application application = control.createMock(Application.class,
275                                 new ConstructorArgs(Application.class.getConstructor()),
276                                 Application.class.getDeclaredMethod("doStart", Scope.class));
277
278                 application.doStart(EasyMockMatchers.anyObject(Scope.class));
279                 EasyMock.expectLastCall().andThrow(new RuntimeException());
280                 control.replay();
281
282                 try {
283                         Container container = new Container("root", new Component[] {
284                                         environment, application }, new ProvidedInterface[0],
285                                         new RequiredInterface[0]);
286
287                         container.start();
288                 } catch (RuntimeException e) {
289                         AssertionUtils.assertEquals(new String[] { "start.environment",
290                                         "stop.environment" }, _tracker.getEvents(
291                                         Thread.currentThread()).toArray(new String[0]));
292                         return;
293                 }
294                 fail();
295         }
296
297         public void testEnvironmentApplicationRollbackOnExceptionWithExceptionOnStop()
298                         throws Exception {
299                 IMocksControl control = EasyMock.createControl();
300
301                 Environment environment = new Environment(_tracker);
302                 // Application 1 will throw an exception while stopping.
303                 Application application1 = control.createMock(Application.class,
304                                 new ConstructorArgs(Application.class.getConstructor()),
305                                 Application.class.getDeclaredMethod("doStop", Object.class));
306
307                 application1.doStop(EasyMock.anyObject());
308                 EasyMock.expectLastCall().andThrow(new RuntimeException());
309                 
310                 // application 2 will throw an exception while starting
311                 Application application2 = control.createMock(Application.class,
312                                 new ConstructorArgs(Application.class.getConstructor()),
313                                 Application.class.getDeclaredMethod("doStart", Scope.class));
314
315                 application2.doStart(EasyMockMatchers.anyObject(Scope.class));
316                 EasyMock.expectLastCall().andThrow(new RuntimeException());
317                 
318                 control.replay();
319
320                 try {
321                         Container container = new Container("root", new Component[] {
322                                         environment, application1, application2 }, new ProvidedInterface[0],
323                                         new RequiredInterface[0]);
324
325                         container.start();
326                 } catch (RuntimeException e) {
327                         AssertionUtils.assertEquals(new String[] { "start.environment", 
328                                         "stop.environment" }, _tracker.getEvents(
329                                         Thread.currentThread()).toArray(new String[0]));
330                         return;
331                 }
332                 fail();
333         }
334         
335         public void testOptionalRequiredInterfaceProvidedOptionalInternal() {
336                 Application application = new Application(true);
337                 Container container = new Container("top", new Component[] { application }, 
338                                 new ProvidedInterface[0], Application.required(true));
339                 Environment env = new Environment();
340                 container.getRequiredInterfaces()[0].setProvider(
341                                 env.getProvidedInterfaces()[0]); 
342                 container.getRequiredInterfaces()[1].setProvider(
343                                 env.getProvidedInterfaces()[1]);
344                 Scope external = new DefaultScope(env.getProvidedInterfaces());
345                 env.start(external); 
346                 
347             container.start(external);
348             assertSame(env.getProvidedInterfaces()[0], container.getRequiredInterfaces()[0].getProvider());
349             assertSame(env.getProvidedInterfaces()[1], container.getRequiredInterfaces()[1].getProvider());
350             assertSame(env.getProvidedInterfaces()[0], application.getRequiredInterfaces()[0].getProvider());
351             assertSame(env.getProvidedInterfaces()[1], application.getRequiredInterfaces()[1].getProvider());
352         }
353         
354         public void testOptionalRequiredInterfaceNotProvidedOptionalInternal() {
355                 Application application = new Application(true);
356                 Container container = new Container("top", new Component[] { application }, 
357                                 new ProvidedInterface[0], Application.required(true));
358                 Environment env = new Environment();
359                 container.getRequiredInterfaces()[0].setProvider(
360                                 env.getProvidedInterfaces()[0]);
361                 Scope external = new DefaultScope(new ProvidedInterface[0]); 
362                 external.publishInterface(env.getProvidedInterfaces()[0], env.getString());
363             container.start(external);
364             assertSame(env.getProvidedInterfaces()[0], container.getRequiredInterfaces()[0].getProvider());
365             assertNull(container.getRequiredInterfaces()[1].getProvider());
366             assertSame(env.getProvidedInterfaces()[0], application.getRequiredInterfaces()[0].getProvider());
367             assertNull(application.getRequiredInterfaces()[1].getProvider());
368         }
369         
370         public void testOptionalRequiredInterfaceProvidedMandatoryInternal() { 
371                 Application application = new Application();
372                 Container container = new Container("top", new Component[] { application }, 
373                                 new ProvidedInterface[0], Application.required(true));
374                 Environment env = new Environment();
375                 container.getRequiredInterfaces()[0].setProvider(
376                                 env.getProvidedInterfaces()[0]); 
377                 container.getRequiredInterfaces()[1].setProvider(
378                                 env.getProvidedInterfaces()[1]);
379             container.start();
380             assertSame(env.getProvidedInterfaces()[0], container.getRequiredInterfaces()[0].getProvider());
381             assertSame(env.getProvidedInterfaces()[1], container.getRequiredInterfaces()[1].getProvider());
382             assertSame(env.getProvidedInterfaces()[0], application.getRequiredInterfaces()[0].getProvider());
383             assertSame(env.getProvidedInterfaces()[1], application.getRequiredInterfaces()[1].getProvider());   
384         }
385         
386         public void testSealed() { 
387                 final Container container = new Container("xx"); 
388                 assertFalse(container.isSealed()); 
389                 container.start();
390                 assertTrue(container.isSealed());
391                 
392                 AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
393                         @Override
394                         public void run() throws Exception {
395                                 container.addComponent(new Application());      
396                         }
397                 }, SystemAssemblyException.class); 
398                 
399                 AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
400                         @Override
401                         public void run() throws Exception {
402                                 container.addProvidedInterface(new DefaultProvidedInterface("xx", String.class));       
403                         }
404                 }, SystemAssemblyException.class); 
405                 
406                 AssertionUtils.assertException(new AssertionUtils.ErroneousCode() { 
407                         @Override
408                         public void run() throws Exception {
409                                 container.addRequiredInterface(new DefaultRequiredInterface("xx", String.class));       
410                         }
411                 }, SystemAssemblyException.class); 
412         }
413 }