blob: 1f87b4beb563104396aacf33ac678a9864f45fd9 [file] [log] [blame]
/*
* Copyright 1999-2011 Alibaba Group.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.dubbo.remoting.codec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.common.io.UnsafeByteArrayInputStream;
import com.alibaba.dubbo.common.io.UnsafeByteArrayOutputStream;
import com.alibaba.dubbo.remoting.Channel;
import com.alibaba.dubbo.remoting.Codec;
import com.alibaba.dubbo.remoting.telnet.codec.TelnetCodec;
/**
* @author chao.liuc
*
*/
public class TelnetCodecTest {
protected Codec codec ;
byte[] UP = new byte[] {27, 91, 65};
byte[] DOWN = new byte[] {27, 91, 66};
/**
* @throws java.lang.Exception
*/
@Before
public void setUp() throws Exception {
codec = new TelnetCodec();
}
protected AbstractMockChannel getServerSideChannel(URL url){
url = url.addParameter(AbstractMockChannel.LOCAL_ADDRESS, url.getAddress())
.addParameter(AbstractMockChannel.REMOTE_ADDRESS, "127.0.0.1:12345");
AbstractMockChannel channel = new AbstractMockChannel(url);
return channel;
}
protected AbstractMockChannel getCliendSideChannel(URL url){
url = url.addParameter(AbstractMockChannel.LOCAL_ADDRESS, "127.0.0.1:12345")
.addParameter(AbstractMockChannel.REMOTE_ADDRESS, url.getAddress());
AbstractMockChannel channel = new AbstractMockChannel(url);
return channel;
}
protected byte[] join(byte[] in1, byte[] in2){
byte[] ret = new byte[in1.length + in2.length];
System.arraycopy(in1, 0, ret, 0, in1.length);
System.arraycopy(in2, 0, ret, in1.length, in2.length);
return ret;
}
protected byte[] objectToByte(Object obj){
byte[] bytes;
if (obj instanceof String){
bytes = ((String)obj).getBytes();
} else if (obj instanceof byte[]){
bytes = (byte[]) obj;
} else {
try {
//object to bytearray
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(obj);
bytes = bo.toByteArray();
bo.close();
oo.close();
}
catch(Exception e){
throw new RuntimeException(e);
}
}
return(bytes);
}
protected Object byteToObject(byte[] objBytes) throws Exception {
if (objBytes == null || objBytes.length == 0) {
return null;
}
ByteArrayInputStream bi = new ByteArrayInputStream(objBytes);
ObjectInputStream oi = new ObjectInputStream(bi);
return oi.readObject();
}
//======================================================
public static class Person implements Serializable{
private static final long serialVersionUID = 3362088148941547337L;
public String name ;
public String sex ;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((sex == null) ? 0 : sex.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (sex == null) {
if (other.sex != null)
return false;
} else if (!sex.equals(other.sex))
return false;
return true;
}
}
protected void testDecode_assertEquals(byte[] request,Object ret) throws IOException{
testDecode_assertEquals(request, ret, true);
}
protected void testDecode_assertEquals(byte[] request,Object ret, boolean isServerside) throws IOException{
//init channel
Channel channel = isServerside? getServerSideChannel(url) : getCliendSideChannel(url);
//init request string
InputStream input = new UnsafeByteArrayInputStream(request);
//decode
Object obj = codec.decode(channel, input);
Assert.assertEquals(ret, obj);
}
protected void testEecode_assertEquals(Object request,byte[] ret, boolean isServerside) throws IOException{
//init channel
Channel channel = isServerside? getServerSideChannel(url) : getCliendSideChannel(url);
UnsafeByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(1024);
codec.encode(channel, bos, request);
bos.flush();
bos.close();
InputStream is = new ByteArrayInputStream(bos.toByteArray());
byte[] data = new byte[is.available()];
is.read(data);
Assert.assertEquals(ret.length, data.length);
for(int i=0;i<ret.length;i++){
if (ret[i] != data[i]){
Assert.fail();
}
}
}
protected void testDecode_assertEquals(Object request,Object ret) throws IOException{
testDecode_assertEquals(request, ret, null);
}
private void testDecode_assertEquals(Object request,Object ret, Object channelReceive) throws IOException{
testDecode_assertEquals(null, request, ret, channelReceive);
}
private void testDecode_assertEquals(AbstractMockChannel channel, Object request,Object expectret, Object channelReceive) throws IOException{
//init channel
if (channel == null){
channel = getServerSideChannel(url);
}
byte[] buf = objectToByte(request);
InputStream input = new UnsafeByteArrayInputStream(buf);
//decode
Object obj = codec.decode(channel, input);
Assert.assertEquals(expectret, obj);
Assert.assertEquals(channelReceive, channel.getReceivedMessage());
}
private void testDecode_PersonWithEnterByte(byte[] enterbytes ,boolean isNeedmore) throws IOException{
//init channel
Channel channel = getServerSideChannel(url);
//init request string
Person request = new Person();
byte[] newbuf = join(objectToByte(request),enterbytes);
InputStream input = new UnsafeByteArrayInputStream(newbuf);
//decode
Object obj = codec.decode(channel, input);
if (isNeedmore){
Assert.assertEquals(Codec.NEED_MORE_INPUT , obj);
}else {
Assert.assertTrue("return must string ", obj instanceof String);
}
}
private void testDecode_WithExitByte(byte[] exitbytes ,boolean isChannelClose) throws IOException{
//init channel
Channel channel = getServerSideChannel(url);
InputStream input = new UnsafeByteArrayInputStream(exitbytes);
//decode
codec.decode(channel, input);
Assert.assertEquals(isChannelClose, channel.isClosed());
}
//======================================================
URL url = URL.valueOf("dubbo://10.20.30.40:20880");
@Test
public void testDecode_String_ClientSide() throws IOException{
testDecode_assertEquals("aaa".getBytes(), "aaa",false);
}
@Test
public void testDecode_BlankMessage() throws IOException{
testDecode_assertEquals(new byte[]{}, Codec.NEED_MORE_INPUT);
}
@Test
public void testDecode_String_NoEnter() throws IOException{
testDecode_assertEquals("aaa", Codec.NEED_MORE_INPUT);
}
@Test
public void testDecode_String_WithEnter() throws IOException{
testDecode_assertEquals("aaa\n", "aaa");
}
@Test
public void testDecode_String_MiddleWithEnter() throws IOException{
testDecode_assertEquals("aaa\r\naaa", Codec.NEED_MORE_INPUT);
}
@Test
public void testDecode_Person_ObjectOnly() throws IOException{
testDecode_assertEquals(new Person(), Codec.NEED_MORE_INPUT);
}
@Test
public void testDecode_Person_WithEnter() throws IOException{
testDecode_PersonWithEnterByte(new byte[] { '\r', '\n' } , false);//windows end
testDecode_PersonWithEnterByte(new byte[] { '\n', '\r' } , true);
testDecode_PersonWithEnterByte(new byte[] { '\n' } , false); //linux end
testDecode_PersonWithEnterByte(new byte[] { '\r' } , true);
testDecode_PersonWithEnterByte(new byte[] { '\r', 100 } , true);
}
@Test
public void testDecode_WithExitByte() throws IOException{
HashMap<byte[] , Boolean> exitbytes = new HashMap<byte[] , Boolean>();
exitbytes.put( new byte[] { 3 }, true ); /* Windows Ctrl+C */
exitbytes.put( new byte[] { 1, 3 }, false ); //must equal the bytes
exitbytes.put( new byte[] { -1, -12, -1, -3, 6 }, true ); /* Linux Ctrl+C */
exitbytes.put( new byte[] {1, -1, -12, -1, -3, 6 }, false ); //must equal the bytes
exitbytes.put( new byte[] { -1, -19, -1, -3, 6 }, true ); /* Linux Pause */
for (byte[] exit : exitbytes.keySet()){
testDecode_WithExitByte(exit ,exitbytes.get(exit));
}
}
@Test
public void testDecode_Backspace() throws IOException{
//32 8 先加空格在补退格.
testDecode_assertEquals(new byte[]{'\b'}, Codec.NEED_MORE_INPUT, new String(new byte[] {32, 8}));
//测试中文
byte[] chineseBytes = "中".getBytes();
byte[] request = join(chineseBytes, new byte[]{'\b'});
testDecode_assertEquals(request, Codec.NEED_MORE_INPUT, new String(new byte[] {32, 32, 8, 8}));
//中文会带来此问题 (-数判断) 忽略此问题,退格键只有在真的telnet程序中才输入有意义.
testDecode_assertEquals(new byte[]{'a', 'x', -1, 'x', '\b'}, Codec.NEED_MORE_INPUT, new String(new byte[] {32, 32, 8, 8}));
}
@Test(expected = IOException.class)
public void testDecode_Backspace_WithError() throws IOException{
url = url.addParameter(AbstractMockChannel.ERROR_WHEN_SEND, Boolean.TRUE.toString());
testDecode_Backspace();
url = url.removeParameter(AbstractMockChannel.ERROR_WHEN_SEND);
}
@Test()
public void testDecode_History_UP() throws IOException{
//init channel
AbstractMockChannel channel = getServerSideChannel(url);
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, null);
String request1 = "aaa\n";
Object expected1 = "aaa";
//init history
testDecode_assertEquals(channel, request1, expected1, null);
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1);
}
@Test(expected = IOException.class)
public void testDecode_UPorDOWN_WithError() throws IOException{
url = url.addParameter(AbstractMockChannel.ERROR_WHEN_SEND, Boolean.TRUE.toString());
//init channel
AbstractMockChannel channel = getServerSideChannel(url);
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, null);
String request1 = "aaa\n";
Object expected1 = "aaa";
//init history
testDecode_assertEquals(channel, request1, expected1, null);
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1);
url = url.removeParameter(AbstractMockChannel.ERROR_WHEN_SEND);
}
/*@Test()
public void testDecode_History_UP_DOWN_MULTI() throws IOException{
AbstractMockChannel channel = getServerSideChannel(url);
String request1 = "aaa\n";
Object expected1 = request1.replace("\n", "");
//init history
testDecode_assertEquals(channel, request1, expected1, null);
String request2 = "bbb\n";
Object expected2 = request2.replace("\n", "");
//init history
testDecode_assertEquals(channel, request2, expected2, null);
String request3 = "ccc\n";
Object expected3= request3.replace("\n", "");
//init history
testDecode_assertEquals(channel, request3, expected3, null);
byte[] UP = new byte[] {27, 91, 65};
byte[] DOWN = new byte[] {27, 91, 66};
//history[aaa,bbb,ccc]
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected3);
testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3);
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected2);
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1);
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1);
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected1);
testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected2);
testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3);
testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3);
testDecode_assertEquals(channel, DOWN, Codec.NEED_MORE_INPUT, expected3);
testDecode_assertEquals(channel, UP, Codec.NEED_MORE_INPUT, expected2);
}*/
//=============================================================================================================================
@Test
public void testEncode_String_ClientSide() throws IOException{
testEecode_assertEquals("aaa", "aaa\r\n".getBytes(), false);
}
}