/* * 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.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.HashMap; import org.junit.Before; import org.junit.Test; import com.alibaba.dubbo.common.URL; import com.alibaba.dubbo.remoting.Channel; import com.alibaba.dubbo.remoting.Codec2; import com.alibaba.dubbo.remoting.buffer.ChannelBuffer; import com.alibaba.dubbo.remoting.buffer.ChannelBuffers; import com.alibaba.dubbo.remoting.telnet.codec.TelnetCodec; import junit.framework.Assert; /** * @author chao.liuc * */ public class TelnetCodecTest { protected Codec2 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 ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(request); //decode Object obj = codec.decode(channel, buffer); 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); ChannelBuffer buffer = ChannelBuffers.dynamicBuffer(1024); codec.encode(channel, buffer, request); byte[] data = new byte[buffer.readableBytes()]; buffer.readBytes(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); ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(buf); //decode Object obj = codec.decode(channel, buffer); 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); ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(newbuf); //decode Object obj = codec.decode(channel, buffer); if (isNeedmore){ Assert.assertEquals(Codec2.DecodeResult.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); ChannelBuffer buffer = ChannelBuffers.wrappedBuffer(exitbytes); //decode codec.decode(channel, buffer); 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[]{}, Codec2.DecodeResult.NEED_MORE_INPUT); } @Test public void testDecode_String_NoEnter() throws IOException{ testDecode_assertEquals("aaa", Codec2.DecodeResult.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", Codec2.DecodeResult.NEED_MORE_INPUT); } @Test public void testDecode_Person_ObjectOnly() throws IOException{ testDecode_assertEquals(new Person(), Codec2.DecodeResult.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'}, Codec2.DecodeResult.NEED_MORE_INPUT, new String(new byte[] {32, 8})); //测试中文 byte[] chineseBytes = "中".getBytes(); byte[] request = join(chineseBytes, new byte[]{'\b'}); testDecode_assertEquals(request, Codec2.DecodeResult.NEED_MORE_INPUT, new String(new byte[] {32, 32, 8, 8})); //中文会带来此问题 (-数判断) 忽略此问题,退格键只有在真的telnet程序中才输入有意义. testDecode_assertEquals(new byte[]{'a', 'x', -1, 'x', '\b'}, Codec2.DecodeResult.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, Codec2.DecodeResult.NEED_MORE_INPUT, null); String request1 = "aaa\n"; Object expected1 = "aaa"; //init history testDecode_assertEquals(channel, request1, expected1, null); testDecode_assertEquals(channel, UP, Codec2.DecodeResult.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, Codec2.DecodeResult.NEED_MORE_INPUT, null); String request1 = "aaa\n"; Object expected1 = "aaa"; //init history testDecode_assertEquals(channel, request1, expected1, null); testDecode_assertEquals(channel, UP, Codec2.DecodeResult.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); } }