UIImpersonator.addChild() doesn't dispatch the right events - apache-flex

I am running FlexUnit tests through Ant. The test test1 fails with the message "Timeout Occurred before expected event" but test2 passes. The only difference between the two tests is that one uses UIImpersonator.addChild() whereas the other uses FlexGlobals.topLevelApplication.addElement().
test1 fails even if I listen for "addedToStage" event. Listening for "added" event, however, makes test1 pass.
[Test(async, ui, description="Fails")]
public function test1():void
{
var c:UIComponent = new UIComponent;
Async.proceedOnEvent(this, c, FlexEvent.CREATION_COMPLETE);
UIImpersonator.addChild(c);
}
[Test(async, ui, description="Passes")]
public function test2():void
{
var c:UIComponent = new UIComponent;
Async.proceedOnEvent(this, c, FlexEvent.CREATION_COMPLETE);
FlexGlobals.topLevelApplication.addElement(c);
}

when adding a child, it will not initiate the flex component lifecycle, because displayobject is flash core element, not flex.

assuming Flex4/spark. addChild adds a MovieClip, not a Flex UIElement, it doesn't even know FlexEvent type as it is a flash.core object. It will only throw addedToStage or added events (Event.added), but in unit test, it is not added to stage, because UIImpersonator is not part of the stage

I ran into this same issue today using the new Apache FlexUnit 4.2.0 release.
When trying to run the sampleCIProject included in the binary distribution, none of the tests that used Async would succeed. The exception was exactly as described above.
After looking at the source code for a while, I noticed that the core FlexUnit libraries have two flavours: flexunit-4.2.0-20140410-as3_4.12.0.swc and flexunit-4.2.0-20140410-flex_4.12.0.swc.
The first of these is intended for pure AS3 projects, while the latter is intended for projects that use Flex. The sampleCIProject included both of these libraries in the library path, and I'm assuming that it was using the UIImpersonator class from the pure AS3 library rather than the Flex-supporting one. I removed flexunit-4.2.0-20140410-as3_4.12.0.swc from the project, and lo and behold, the Async tests started working again.
Probably a bit late for you, but I hope this helps someone else.

Related

How can I reuse containers during integration tests with quarkus?

I currently have a few integration tests that are running fine, however I'm using the annotation #QuarkusTestResource to launch containers via testcontainers before quarkus is launched and I adapt my properties to the random test container port by overriding the start method of my container class extending QuarkusTestResourceLifecycleManager.
To optimize a little bit I'd like for example to reuse my container that launches kafka since it takes 6-8 seconds to start it and reuse it for several of my integration tests. I've not been able to do so. Since Quarkus manages the lifecycle every times it stops, between every test class, it also stops every container. I tried mixing singleton containers from testcontainers with the Quarkus test resources but it doesn't work. Here's a snippet of the start of one of my integration test class :
#QuarkusTest
#Tag(INTEGRATION_TEST)
#QuarkusTestResource(value = KafkaNode.class, restrictToAnnotatedClass = true, parallel = true)
class MyIntegrationTest { ... }
And my KafkaNode class :
public class KafkaNode implements QuarkusTestResourceLifecycleManager {
static KafkaContainer kafka = new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka:6.2.1"))
.withNetworkAliases("kafkaNode")
.withNetwork(CommonNetwork.getInstance());
#Override
public Map<String, String> start() {
kafka.start();
return Collections.singletonMap("myapp.kafka.servers",
kafka.getBootstrapServers());
}
#Override
public void stop() {
kafka.close();
}
}
I'm open to ideas to reuse of even rework my tests so that I can reuse containers in another way.
You can use the experimental reusable mode for your container via .withReuse(true).
Please note that in order for this to work you need to:
set the testcontainers.reuse.enable=true property in the ~/.testcontainers.properties file
NOT call .close() (which programmatically stops the container in any way)
Once you've setup everything accordingly your container should
not be stopped/garbage collected at the end of the test run anymore
be picked up again at the next test run - avoiding a new container start
Please note that all runtime modifications (configuration, data, topics etc.) will still be there at the next test run. You need to take suitable measures to avoid non-deterministic tests - like using different / random topic names for each test run.
Also note that you'll need to manually stop/delete the container when you're done with it. Testcontainers will not remove the container for you anymore.
You can also read this article that describes how to do it from spring for inspiration: Reuse Containers With Testcontainers for Fast Integration Test
When using multiple QuarkusTestProfile's, the test context will be reseted completely, so that even static variables are not preserved.
I have not yet found a way to use e.g. a single database across all QuarkusTest's in one test when using different QuarkusTestProfiles.
Even if it seems that the container exists across test run boundaries, I can't reference it in later test runs to determine the mapped port, etc.

Task doesn't run in GUI, but OK in console

I am using a third-party library. That library contains an object with an async method that returns Task<SomeStuff>. I am wrapping that object and others into my own class. My wrapper method is also async and has the same return. Calling the wrapper method works fine in my unit tests and a console app. However, it doesn't work in my WPF GUI app. I have tried different methods for invoking in my GUI but nothing works.
In my unit tests, I invoke with GetAwaiter().GetResult(). However, in my GUI this never returns.
I tried using Start() but that results in an error: "Start may not be called on a promise-style task."
What do I need to do to make this work in my GUI?
// Foo() returns Task<SomeStuff>
// this works fine in unit test as well as console app, but not in GUI (WPF)
SomeStuff stuff = myWrapper.Foo().GetAwaiter().GetResult();
// this results in error: "Start may not be called on a promise-style task."
Task<SomeStuff> myTask = myWrapper.Foo();
myTask.Start();
myTask.Wait();
There is a very good discussion of various approaches to my issue here: [https://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously?rq=1][1]
For the moment I resolved my issue as below. I shall re-read the post from the link and perhaps refine my approach.
Task<SomeStuff> task = Task.Run(() => myWrapper.Foo());
task.Wait();
SomeStuff stuff = task.Result;

Register callback in Autofac and build container again in the callback

I have a dotnet core application.
My Startup.cs registers types/implementations in Autofac.
One of my registrations needs previous access to a service.
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterSettingsReaders(); // this makes available a ISettingsReader<string> that I can use to read my appsettings.json
containerBuilder.RegisterMyInfrastructureService(options =>
{
options.Username = "foo" //this should come from appsettings
});
containerBuilder.Populate(services);
var applicationContainer = containerBuilder.Build();
The dilemma is, by the time I have to .RegisterMyInfrastructureService I need to have available the ISettingsReader<string> that was registered just before (Autofac container hasn't been built yet).
I was reading about registering with callback to execute something after the autofac container has been built. So I could do something like this:
builder.RegisterBuildCallback(c =>
{
var stringReader = c.Resolve<ISettingsReader<string>>();
var usernameValue = stringReader.GetValue("Username");
//now I have my username "foo", but I want to continue registering things! Like the following:
containerBuilder.RegisterMyInfrastructureService(options =>
{
options.Username = usernameValue
});
//now what? again build?
});
but the problem is that after I want to use the service not to do something like starting a service or similar but to continue registering things that required the settings I am now able to provide.
Can I simply call again builder.Build() at the end of my callback so that the container is simply rebuilt without any issue? This seems a bit strange because the builder was already built (that's why the callback was executed).
What's the best way to deal with this dilemma with autofac?
UPDATE 1: I read that things like builder.Update() are now obsolete because containers should be immutable. Which confirms my suspicion that building a container, adding more registrations and building again is not a good practice.
In other words, I can understand that using a register build callback should not be used to register additional things. But then, the question remain: how to deal with these issues?
This discussion issue explains a lot including ways to work around having to update the container. I'll summarize here, but there is a lot of information in that issue that doesn't make sense to try and replicate all over.
Be familiar with all the ways you can register components and pass parameters. Don't forget about things like resolved parameters, modules that can dynamically put parameters in place, and so on.
Lambda registrations solve almost every one of these issues we've seen. If you need to register something that provides configuration and then, later, use that configuration as part of a different registration - lambdas will be huge.
Consider intermediate interfaces like creating an IUsernameProvider that is backed by ISettingsReader<string>. The IUsernameProvider could be the lambda (resolve some settings, read a particular one, etc.) and then the downstream components could take an IUsernameProvider directly.
These sorts of questions are hard to answer because there are a lot of ways to work around having to build/rebuild/re-rebuild the container if you take advantage of things like lambdas and parameters - there's no "best practice" because it always depends on your app and your needs.
Me, personally, I will usually start with the lambda approach.

FlexUnit: Spark component test issue (UIImpersonator)

FlexUnit 4.1
FlashBuilder 4.5.1
BACKGROUND
I'm trying to test a custom Flex 4 skinnable component, using the FlexUnit UIImpersonator class. If I run my tests from a FlashBuilder Spark only project everything works fine. If I try to test from a project with the mx component set on the classpath I get a "getElementIndex not available in non Flex 4 projects" error.
QUESTION
Can I unit test spark components in FlexUnits visual test environment while still having the mx component set on the classpath?
RESEARCH
UIImpersonator delegates it's method calls to a "testEnvironment".
The implementation used for this "testEnvironment" is decided by the VisualTestEnvironmentBuilder class and the FlexEnvironmentBuilder class. If the FlexEnvironmentBuilder class can find the "mx.core.Container" on the classpath it returns a MX environment, else a Spark environment. Only the spark environment has valid implementations for Flex 4 relevant method calls on the UIImpersonator – like the addElement method.
I have the same problem, and didn't found any solution. I suggest to file a bug, but since FlexUnit is in the process of being adopted by Apache Flex, I don't think it would be resolved anytime soon.
As a workaround. Just use UIImpersonator.addChild() and add a reference to mx.core.Container in your TestRunner. This ensures that a MX container is used as testEnvironment and you won't receive a 'getElementIndex...' error.
import mx.core.Container
public function runTests():void {
// reference to mx container
var containerRef:Container = new Container();
// Run your testsuite as usual. eg:
var core:FlexUnitCore = new FlexUnitCore();
core.run(MyTestSuite);
}

Finding Display of an RCP App

I'm writing a testing Framework which is starting a GUI Application. To be able to test this GUI in the case of an SWT application I need to know it's display. In general, this display is loaded by another classloader, therefore I'm using the method findDisplay(Thread t) of the swt Display class by reflection to accomplish this task. My code looks something like this:
Thread[] threads = new Thread[10];
Thread.enumerate(threads);
Object foundObject = null;
for (Thread t : Arrays.asList(threads)){
foundObject = null;
Class<?> clazz = t.getContextClassLoader().loadClass("org.eclipse.swt.widgets.Display");
final Method method = clazz.getMethod("findDisplay", Thread.class);
foundObject = method.invoke(null, new Object[] {t});
if (foundObject != null) {
System.out.println("yeah, found it!");
break;
}
}
In my opinion this should find every Object of type Display in the current thread group. However I don't get any for the texteditor RCP example although the GUI is starting up perfectly.
Any ideas what is going wrong or how I can debug this in a reasonable way?
I figured out what the main problem was: The ContextClassloader had nothing to do with the classloader who actually loaded the classes.
To resolve my problem I took care of having the classloader which loads the swt display class both in the hierarchy of the RCP program and the hierarchy of my framework. This was possible by using the java extension classloader. (I couldn't use the application classloader since my RCP application doesn't work with it as parent, I haven't figured out yet why) It was then just a matter of adding the swt.jar to the java.ext.dirs property.
If you are using Eclipse RCP then maybe you can use:
PlatformUI.getWorkbench().getDisplay()

Resources