View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
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  
17  package net.sf.ehcache.distribution;
18  
19  import static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertTrue;
21  
22  import java.io.IOException;
23  import java.io.Serializable;
24  import java.rmi.RemoteException;
25  import java.util.ArrayList;
26  import java.util.List;
27  import java.util.Random;
28  
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  import net.sf.ehcache.AbstractCacheTest;
33  import net.sf.ehcache.CacheManager;
34  import net.sf.ehcache.Element;
35  
36  import org.junit.After;
37  import org.junit.Before;
38  import org.junit.Test;
39  
40  /***
41   * Note these tests need a live network interface running in multicast mode to work
42   *
43   * @author <a href="mailto:gluck@thoughtworks.com">Greg Luck</a>
44   * @version $Id: PayloadUtilTest.html 13146 2011-08-01 17:12:39Z oletizi $
45   */
46  public class PayloadUtilTest extends AbstractRMITest {
47  
48      private static final Logger LOG = LoggerFactory.getLogger(PayloadUtilTest.class.getName());
49      private static final Random RANDOM = new Random(System.currentTimeMillis());
50      private static final String RANDOM_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.";
51      private CacheManager manager;
52  
53      /***
54       * setup test
55       *
56       * @throws Exception
57       */
58      @Before
59      public void setUp() throws Exception {
60          String fileName = AbstractCacheTest.TEST_CONFIG_DIR + "ehcache-big.xml";
61          manager = new CacheManager(fileName);
62      }
63  
64      /***
65       * Shuts down the cachemanager
66       *
67       * @throws Exception
68       */
69      @After
70      public void tearDown() throws Exception {
71          manager.shutdown();
72      }
73  
74      /***
75       * The maximum Ethernet MTU is 1500 bytes.
76       * <p/>
77       * We want to be able to work with 100 caches
78       */
79      @Test
80      public void testMaximumDatagram() throws IOException {
81          String payload = createReferenceString();
82  
83          final byte[] compressed = PayloadUtil.gzip(payload.getBytes());
84  
85          int length = compressed.length;
86          LOG.info("gzipped size: " + length);
87          assertTrue("Heartbeat too big for one Datagram " + length, length <= 1500);
88  
89      }
90  
91      private String createReferenceString() {
92  
93          String[] names = manager.getCacheNames();
94          String urlBase = "//localhost.localdomain:12000/";
95          StringBuilder buffer = new StringBuilder();
96          for (String name : names) {
97              buffer.append(urlBase);
98              buffer.append(name);
99              buffer.append("|");
100         }
101         String payload = buffer.toString();
102         return payload;
103     }
104 
105     @Test
106     public void testBigPayload() throws RemoteException {
107         List<CachePeer> bigPayloadList = new ArrayList<CachePeer>();
108         // create 5000 peers, each peer having cache name between 50 - 500 char length
109         int peers = 5000;
110         int minCacheNameSize = 50;
111         int maxCacheNameSize = 500;
112         for (int i = 0; i < peers; i++) {
113             bigPayloadList.add(new PayloadUtilTestCachePeer(getRandomName(minCacheNameSize, maxCacheNameSize)));
114         }
115 
116         doTestBigPayLoad(bigPayloadList, 5);
117         doTestBigPayLoad(bigPayloadList, 10);
118         doTestBigPayLoad(bigPayloadList, 50);
119         doTestBigPayLoad(bigPayloadList, 100);
120         doTestBigPayLoad(bigPayloadList, 150);
121         doTestBigPayLoad(bigPayloadList, 300);
122         doTestBigPayLoad(bigPayloadList, 500);
123 
124         // do a big test where maximumPeersPerSend is a large value, try to accomodate all peers in one payload
125         // this should result in payload breaking up by MTU size
126         doTestBigPayLoad(bigPayloadList, 1000000);
127 
128         // test heartbeat won't work when single cache has very very long cacheName
129         bigPayloadList.clear();
130         bigPayloadList.add(new PayloadUtilTestCachePeer(getRandomName(3000, 3001)));
131         List<byte[]> compressedList = PayloadUtil.createCompressedPayloadList(bigPayloadList, 150);
132         assertEquals(0, compressedList.size());
133 
134     }
135 
136     private void doTestBigPayLoad(List<CachePeer> bigPayloadList, int maximumPeersPerSend) throws RemoteException {
137         List<byte[]> compressedList = PayloadUtil.createCompressedPayloadList(bigPayloadList, maximumPeersPerSend);
138         // the big list cannot be compressed in 1 entry
139         assertTrue(compressedList.size() > 1);
140         StringBuilder actual = new StringBuilder();
141         for (byte[] bytes : compressedList) {
142             assertTrue("One payload should not be greater than MTU, actual size: " + bytes.length + ", MTU: " + PayloadUtil.MTU,
143                     bytes.length <= PayloadUtil.MTU);
144             String urlList = new String(PayloadUtil.ungzip(bytes));
145             String[] urls = urlList.split(PayloadUtil.URL_DELIMITER_REGEXP);
146             assertTrue("Number of URL's in one payload should not exceed maximumPeersPerSend (=" + maximumPeersPerSend + "), actual: "
147                     + urls.length, urls.length <= maximumPeersPerSend);
148 
149             if (bytes == compressedList.get(compressedList.size() - 1)) {
150                 actual.append(urlList);
151             } else {
152                 actual.append(urlList + PayloadUtil.URL_DELIMITER);
153             }
154         }
155         StringBuilder expected = new StringBuilder();
156         for (CachePeer peer : bigPayloadList) {
157             if (peer != bigPayloadList.get(bigPayloadList.size() - 1)) {
158                 expected.append(peer.getUrl() + PayloadUtil.URL_DELIMITER);
159             } else {
160                 expected.append(peer.getUrl());
161             }
162         }
163         assertEquals(expected.toString(), actual.toString());
164     }
165 
166     private String getRandomName(final int minLength, final int maxLength) {
167         int length = minLength + RANDOM.nextInt(maxLength - minLength);
168         StringBuilder rv = new StringBuilder();
169         for (int i = 0; i < length; i++) {
170             rv.append(RANDOM_CHARS.charAt(RANDOM.nextInt(RANDOM_CHARS.length())));
171         }
172         return rv.toString();
173     }
174 
175     /***
176      * A test class which implements only {@link #getUrl()} to test PayloadUtil.createCompressedPayloadList()
177      *
178      * @author Abhishek Sanoujam
179      */
180     private static class PayloadUtilTestCachePeer implements CachePeer {
181 
182         public static final String URL_BASE = "//localhost.localdomain:12000/";
183         private final String cacheName;
184 
185         public PayloadUtilTestCachePeer(String cacheName) {
186             this.cacheName = cacheName;
187         }
188 
189         /***
190          * {@inheritDoc}
191          *
192          * @see net.sf.ehcache.distribution.CachePeer#getUrl()
193          */
194         public String getUrl() throws RemoteException {
195             return URL_BASE + cacheName;
196         }
197 
198         /***
199          * {@inheritDoc}
200          *
201          * @see net.sf.ehcache.distribution.CachePeer#getElements(java.util.List)
202          */
203         public List getElements(List keys) throws RemoteException {
204             // no-op
205             return null;
206         }
207 
208         /***
209          * {@inheritDoc}
210          *
211          * @see net.sf.ehcache.distribution.CachePeer#getGuid()
212          */
213         public String getGuid() throws RemoteException {
214             // no-op
215             return null;
216         }
217 
218         /***
219          * {@inheritDoc}
220          *
221          * @see net.sf.ehcache.distribution.CachePeer#getKeys()
222          */
223         public List getKeys() throws RemoteException {
224             // no-op
225             return null;
226         }
227 
228         /***
229          * {@inheritDoc}
230          *
231          * @see net.sf.ehcache.distribution.CachePeer#getName()
232          */
233         public String getName() throws RemoteException {
234             // no-op
235             return null;
236         }
237 
238         /***
239          * {@inheritDoc}
240          *
241          * @see net.sf.ehcache.distribution.CachePeer#getQuiet(java.io.Serializable)
242          */
243         public Element getQuiet(Serializable key) throws RemoteException {
244             // no-op
245             return null;
246         }
247 
248         /***
249          * {@inheritDoc}
250          *
251          * @see net.sf.ehcache.distribution.CachePeer#getUrlBase()
252          */
253         public String getUrlBase() throws RemoteException {
254             // no-op
255             return null;
256         }
257 
258         /***
259          * {@inheritDoc}
260          *
261          * @see net.sf.ehcache.distribution.CachePeer#put(net.sf.ehcache.Element)
262          */
263         public void put(Element element) throws IllegalArgumentException, IllegalStateException, RemoteException {
264             // no-op
265 
266         }
267 
268         /***
269          * {@inheritDoc}
270          *
271          * @see net.sf.ehcache.distribution.CachePeer#remove(java.io.Serializable)
272          */
273         public boolean remove(Serializable key) throws IllegalStateException, RemoteException {
274             // no-op
275             return false;
276         }
277 
278         /***
279          * {@inheritDoc}
280          *
281          * @see net.sf.ehcache.distribution.CachePeer#removeAll()
282          */
283         public void removeAll() throws RemoteException, IllegalStateException {
284             // no-op
285         }
286 
287         /***
288          * {@inheritDoc}
289          *
290          * @see net.sf.ehcache.distribution.CachePeer#send(java.util.List)
291          */
292         public void send(List eventMessages) throws RemoteException {
293             // no-op
294 
295         }
296 
297     }
298 
299 }