Automated tests for Spring Boot WebSocket server

20 05 2017

Developing WebSocket server for your Spring Boot app is fairly simple and well described and documented. However when it comes to making sure that it ‘actually works’ is done manually in most cases.

Below I will show how I do the automated integration tests for Websocket server using Spring’s StompClient. I assume that you are familiar with the idea of WebSockets in Spring. If not, here is a very good article: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html

Source Code

Code of this tutorial is for you to see here: https://github.com/yacekmm/looksok/tree/WebSocketDemo/Spring/WebSocket

System under test: configuration

The demo will be presented on the simpliest WS configuration which consists of one entry point endpoint (`/ws`) and in-memory message broker (under `/queue`):

@Configuration
@EnableWebSocketMessageBroker
public class WsConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) { 
        registry.addEndpoint("/ws");
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/queue");
    }
}

The idea behind the integration test

In the test I’m going to:
– use SpringRunner to start up the whole application with the full context
– Autowire Component that in production will be responsible for sending messages to WebSocket clients
– Build and configure Spring’s StompClient and connect a StompSession to my WebSocket server
send a message over WebSocket and verify if my test client received it

Starting the application for tests

With SpringRunner.class used within jUnit test I start the app context and autowire the WSProxy component (the one that sends messages to WS clients):

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT)
public class WsConfigIntegrationTest {

    @Value("${local.server.port}")
    private int port;
    @Autowired
    private WsProxy wsProxy;

WsProxy in this demo is a simple component sending message with a SimpMessagingTemplate:

@Component
public class WsProxy {

    private SimpMessagingTemplate messagingTemplate;

    @Autowired
    public WsProxy(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    public void sendMessage(@RequestParam String clientId,
                            @RequestParam String payload){
        messagingTemplate.convertAndSend("/queue/" + clientId, payload);
    }
}

In this configuration, the url of WS endpoint is:

String wsUrl = "ws://127.0.0.1:" + port + "/ws";

Configuring StompClient and connecting StompSession

Using the StompClient with a minimum configuration:

WebSocketStompClient stompClient = new WebSocketStompClient(new StandardWebSocketClient());
stompClient.setMessageConverter(new StringMessageConverter());

I create StompSession to my WS url:

StompSession stompSession = stompClient.connect(wsUrl, new MyStompSessionHandler()).get();

The connect() method returns a future, but here, in tests, I wait synchronously until this session is ready by calling get() on it to get the session instantly.

Oh, and don’t worry about the MyStompSessionHandler – in this configuration it does nothing, except debug logging on the ‘Connect to WS’ event (just overrides the StompSessionHandlerAdapter)

Now it’s time to subscribe the /queue/my-id Channel within the session:

stompSession.subscribe(
    "/queue/my-id", 
    new MyStompFrameHandler((payload) -> resultKeeper.complete(payload.toString())));

The MyStompFrameHandler class is responsible for handling the incoming message in within the session and completing the CompletableFuture promise that it received as an argument. CompletableFuture is a helper variable needed to test asynchronous code:

CompletableFuture<String> resultKeeper = new CompletableFuture<>();

And the handler uses it as follows:

public class MyStompFrameHandler implements StompFrameHandler {

    private final Consumer<String> frameHandler;

    public MyStompFrameHandler(Consumer<String> frameHandler) {
        this.frameHandler = frameHandler;
    }

    ...

    @Override
    public void handleFrame(StompHeaders headers, Object payload) {
        log.info("received message: {} with headers: {}", payload, headers);
        frameHandler.accept(payload.toString());
    }
}

Sending the message

Message is sent by a WsProxy with SimpMessagingTemplate:

@Component
public class WsProxy {

    private SimpMessagingTemplate messagingTemplate;

    @Autowired
    public WsProxy(SimpMessagingTemplate messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    public void sendMessage(String clientId, String payload){
        messagingTemplate.convertAndSend("/queue/" + clientId, payload);
    }
}

On some machines it’s also good to wait until the connection is fully established so don’t hesitate to add good old:

Thread.currentThread().sleep(1000);

Testing the result asynchronously

The code in test is async so I pass the Future and wait until it completes with the expected result, or to fail test after timeout on waiting for the response, verifying its body:

assertThat(resultKeeper.get(2, SECONDS)).isEqualTo("test-payload");

That’s it

Now you can run the test, it will start your app, send a message, receive it and verify the contents. Which is everything you need to implement the WebSockets.

Source Code

I’m sure that seeing the source code will make you understand the article better. Grab it from my GitHub: https://github.com/yacekmm/looksok/tree/WebSocketDemo/Spring/WebSocket





Java 8 StringJoiner demo

24 01 2016

Finally Java has convenient and intuitive API for joining strings with delimiters! Since Java 8 there is StringJoiner class. It is an API that you may know from Guava Joiner classes (see my post: https://looksok.wordpress.com/2015/10/17/guava-joiner-join-all-strings-in-an-array-or-map/). Here is a short StringJoiner demo.

Basic String joins

The most basic usage is to create StringJoiner instance with delimiter as a constructor param and add() strings:

StringJoiner joiner = new StringJoiner(",");
joiner.add("apple");
joiner.add("banana");
joiner.add("orange");

System.out.println("Joiner result is: " + joiner.toString());

The result is:

Joiner result is: apple,banana,orange

If you prefer, you can chain add() calls:

StringJoiner joiner = new StringJoiner(",")
    .add("apple")
    .add("banana")
    .add("orange");

Join Collection of Strings

If you have Collection of Strings, the new static String.join() method can join them:

List<String> list = Arrays.asList("apple", "banana", "orange");
String joined = String.join(", ", list);

System.out.println("Join Array result is: " + joined);

With the result of:

Join Array result is: apple, banana, orange

Join inline

You can prepare joined String in one line with String.join() overloaded with varargs, like that:

String.join(", ", "apple", "banana", "orange");

Joining Collector in Stream API

When using streams you have joining Collector at your disposal:

List<String> list = Arrays.asList("apple", "banana", "orange");
String joined = list.stream()
        .collect(Collectors.joining(", "));

System.out.println("Joined with collector: " + joined);

This will result with:

Joined with collector: apple, banana, orange

Source Code

As always, I share with you the source code for this demo on my github: https://github.com/yacekmm/looksok/tree/StringJoinerDemo/Java/JavaDemo





ViewPager with detailed fragment lifecycle (onResumeFragment) [including source code]

2 11 2013

When using ViewPager introduced in this ViewPager tutorial you may encounter some issue connected with fragment and ViewPager lifecycle. The fragment’s lifecycle is connected with activity lifecycle. Some methods like onAttach() are added, but the general rule is the same.

ViewPager manages its fragments in a bit different way. Fragment’s onResume() is not called when fragment is actually resumed and showed to the user on screen. So in standard ViewPager it is impossible to update fragment when it is displayed, since there is no lifecycle method that is called when fragment is displayed.

ViewPager actually loads three fragments at once, calling their onResume(). It loads the visible fragment ant both of its neighbours (the one on the left and one on the right. It is needed for fluent sliding between fragments. It is painful when the content on the first fragment depends, and should be updated when fragment is resumed.

You can easily see how onResume() and onPause() are called in fact just by logging these method calls in Logcat. And how to have true fragment’s lifecycle I will show in this tutorial.

Note: Whole tutorial is based on the ViewPagerTutorial from this post.

Download source code!

You are welcome to download and use the source code from this tutorial as You need. Here it is!

1. Create LifecycleManager Interface
The interface will have two methods and each ViewPager’s Fragment will implement it. These methods Are as follows:

public interface FragmentLifecycle {

	public void onPauseFragment();
	public void onResumeFragment();

}

2. Let each Fragment implement the interface
Add iplements statement for each class declaration:

public class FragmentBlue extends Fragment implements FragmentLifecycle 
public class FragmentGreen extends Fragment implements FragmentLifecycle 
public class FragmentPink extends Fragment implements FragmentLifecycle

3. Implement interface methods in each fragment
In order to check that it really works as expected, I will just log the method call and show Toast:

@Override
public void onPauseFragment() {
	Log.i(TAG, "onPauseFragment()");
	Toast.makeText(getActivity(), "onPauseFragment():" + TAG, Toast.LENGTH_SHORT).show(); 
}

@Override
public void onResumeFragment() {
	Log.i(TAG, "onResumeFragment()");
	Toast.makeText(getActivity(), "onResumeFragment():" + TAG, Toast.LENGTH_SHORT).show(); 
}

4. Call interface methods on ViewPager page change
You can set OnPageChangeListener on ViewPager and get callback each time when ViewPager shows another page:

pager.setOnPageChangeListener(pageChangeListener);

5. Implement OnPageChangeListener to call your custom Lifecycle methods

Listener knows the new position and can call the interface method on new Fragment with the help of PagerAdapter. I can here call onResumeFragment() for new fragment and onPauseFragment() on the current one.

I need to store also the current fragment’s position (initially the current position is equal to 0), since I don’t know whether the user scrolled from left to right or from right to left. See what I mean in code:

private OnPageChangeListener pageChangeListener = new OnPageChangeListener() {

	int currentPosition = 0;

	@Override
	public void onPageSelected(int newPosition) {

		FragmentLifecycle fragmentToShow = (FragmentLifecycle)pageAdapter.getItem(newPosition);
		fragmentToShow.onResumeFragment();

		FragmentLifecycle fragmentToHide = (FragmentLifecycle)pageAdapter.getItem(currentPosition);
		fragmentToHide.onPauseFragment();

		currentPosition = newPosition;
	}

	@Override
	public void onPageScrolled(int arg0, float arg1, int arg2) { }

	public void onPageScrollStateChanged(int arg0) { }
};

6. That’s all – download source code!

You are welcome to download and use the source code from this tutorial as You need. Here it is!

Did I help you?

I manage this blog and share my knowledge for free sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality Donate Button with Credit Cards Thank You!





Source code: Android custom ListView

27 04 2013

Since many of you have asked for a source code of this tutorial:

Android custom ListView tutorial

I decided to write it and share. The tutorial was witten based on a bigger project, so I could not share it. This is why I have written custom ListView source code example from scratch based on the article mentioned above. Here it is:

Source Code: Android custom ListView zip and on GitHub

Did I help you?
I manage this blog and share my knowledge for free sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!





Android: complete widget tutorial (including source code)

15 12 2012

Tutorial will show how to build android widget with one button and image. Button press will change the image displayed. The result will look as follows

What is going to be built

What is going to be built

Source code

Hereby I share my widget tutorial source code zip or github. Feel free to download.

1. Create widget layout

layout is defined as any other layout in Android app. My layout consists of just one button and one imageView (/res/layout/widget_demo.xml).

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:layout_margin="5sp"
    android:background="@android:drawable/alert_dark_frame" >

    <ImageView
        android:id="@+id/widget_image"
        android:layout_width="110sp"
        android:layout_height="110sp"
        android:layout_gravity="center"
        android:src="@drawable/wordpress_icon" />

    <Button
        android:id="@+id/widget_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:text="Change it!" />

</LinearLayout>

Please remember that views that can be used in widget layout are limited. It depends on android version you are developing for. Find out more here. Make sure that view that you are using is supported by target android SDK version.

2. Create App Widget Provider declaration

This is another xml file that tells android OS that this application has a widget (display your widget in OS widget list). Create it with wizard:

File → New → Android → Android XML File
Widget Provider creation wizard

Widget Provider creation wizard

Widget size should be defined in dp. Usually widget size is related to one icon size on desktop (74 x 74 dp). Size should be mutiplication of such blocks. It may be calculated using formula:

((Number of columns or rows)* 74)

Please remember however to leave some space for margins. My widget has width and height equal to two icon blocks (146 dp x 146 dp):

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 
    android:initialLayout="@layout/widget_demo" 
    android:minHeight="146dp" 
    android:minWidth="146dp"
    android:updatePeriodMillis="1000000" 
    >
</appwidget-provider>

3. Create AppWidgetProvider onUpdate implementation

Create class extending AppWidgetProvider. It will be responsible for updating your widget while Android OS requests it (e.g. widget is shown to user).

Here you have to set button listener (as a PendingIntent, because RemoteViews supports only that way of communication)

public class MyWidgetProvider extends AppWidgetProvider {

	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {

		RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_demo);
		remoteViews.setOnClickPendingIntent(R.id.widget_button, buildButtonPendingIntent(context));

		pushWidgetUpdate(context, remoteViews);
	}

	public static PendingIntent buildButtonPendingIntent(Context context) {
		Intent intent = new Intent();
	    intent.setAction("pl.looksok.intent.action.CHANGE_PICTURE");
	    return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
	}

	public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
		ComponentName myWidget = new ComponentName(context, MyWidgetProvider.class);
	    AppWidgetManager manager = AppWidgetManager.getInstance(context);
	    manager.updateAppWidget(myWidget, remoteViews);		
	}
}

In buildButtonPendingIntent I set that after widget button press the intent will be sent. So now… it is time to catch that intent in Broadcast Receiver and handle widget update

4. Register MyWidgetProvider in AndroidManifest.xml

Add these lines in <application/> tag:

        <receiver android:name="MyWidgetProvider" >
            <intent-filter >
                <action 
                    android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/demo_widget_provider" />
        </receiver>

5. Create Broadcast Intent receiver

This will be called for pending intents updates. Widgets are built on RemoteViews (views that are managed by another process than your application). This is why they communicate with your app by PendingIntents.

public class MyWidgetIntentReceiver extends BroadcastReceiver {

	private static int clickCount = 0;

	@Override
	public void onReceive(Context context, Intent intent) {
		if(intent.getAction().equals("pl.looksok.intent.action.CHANGE_PICTURE")){
			updateWidgetPictureAndButtonListener(context);
		}
	}

	private void updateWidgetPictureAndButtonListener(Context context) {
		RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_demo);
		remoteViews.setImageViewResource(R.id.widget_image, getImageToSet());

		//REMEMBER TO ALWAYS REFRESH YOUR BUTTON CLICK LISTENERS!!!
		remoteViews.setOnClickPendingIntent(R.id.widget_button, MyWidgetProvider.buildButtonPendingIntent(context));

		MyWidgetProvider.pushWidgetUpdate(context.getApplicationContext(), remoteViews);
	}

	private int getImageToSet() {
		clickCount++;
		return clickCount % 2 == 0 ? R.drawable.me : R.drawable.wordpress_icon;
	}
}

WARNING!!!

Since you are creating RemoteViews from scratch in Broadcast Receiver (using constructor with new keyword), you must refresh widget layout from scratch. Mainly: refresh the button listeners pending intents. This will help you to avoid issues like this and that.

6. Register Broadcast Receiver in AndroidManifest.xml

Add the following lines in <application/> tag:

<receiver
    android:name="MyWidgetIntentReceiver"
    android:label="widgetBroadcastReceiver" >
    <intent-filter>
        <action android:name="pl.looksok.intent.action.CHANGE_PICTURE" />
    </intent-filter>

    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/demo_widget_provider" />
</receiver>

7. That’s all!

Hereby I share my widget tutorial source code zip or github. Feel free to download. Feel free to customize widget according to your needs!

Here you will find some another widget tutorial. Maybe it will also be useful for you.

Did I help you?
I manage this blog and share my knowledge for free sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!








%d bloggers like this: