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.java 2539 2010-07-02 10:58:13Z alexsnaps $
45   */
46  public class PayloadUtilTest {
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      */
181     private static class PayloadUtilTestCachePeer implements CachePeer {
182 
183         public static final String URL_BASE = "//localhost.localdomain:12000/";
184         private final String cacheName;
185 
186         public PayloadUtilTestCachePeer(String cacheName) {
187             this.cacheName = cacheName;
188         }
189 
190         /***
191          * {@inheritDoc}
192          * 
193          * @see net.sf.ehcache.distribution.CachePeer#getUrl()
194          */
195         public String getUrl() throws RemoteException {
196             return URL_BASE + cacheName;
197         }
198 
199         /***
200          * {@inheritDoc}
201          * 
202          * @see net.sf.ehcache.distribution.CachePeer#getElements(java.util.List)
203          */
204         public List getElements(List keys) throws RemoteException {
205             // no-op
206             return null;
207         }
208 
209         /***
210          * {@inheritDoc}
211          * 
212          * @see net.sf.ehcache.distribution.CachePeer#getGuid()
213          */
214         public String getGuid() throws RemoteException {
215             // no-op
216             return null;
217         }
218 
219         /***
220          * {@inheritDoc}
221          * 
222          * @see net.sf.ehcache.distribution.CachePeer#getKeys()
223          */
224         public List getKeys() throws RemoteException {
225             // no-op
226             return null;
227         }
228 
229         /***
230          * {@inheritDoc}
231          * 
232          * @see net.sf.ehcache.distribution.CachePeer#getName()
233          */
234         public String getName() throws RemoteException {
235             // no-op
236             return null;
237         }
238 
239         /***
240          * {@inheritDoc}
241          * 
242          * @see net.sf.ehcache.distribution.CachePeer#getQuiet(java.io.Serializable)
243          */
244         public Element getQuiet(Serializable key) throws RemoteException {
245             // no-op
246             return null;
247         }
248 
249         /***
250          * {@inheritDoc}
251          * 
252          * @see net.sf.ehcache.distribution.CachePeer#getUrlBase()
253          */
254         public String getUrlBase() throws RemoteException {
255             // no-op
256             return null;
257         }
258 
259         /***
260          * {@inheritDoc}
261          * 
262          * @see net.sf.ehcache.distribution.CachePeer#put(net.sf.ehcache.Element)
263          */
264         public void put(Element element) throws IllegalArgumentException, IllegalStateException, RemoteException {
265             // no-op
266 
267         }
268 
269         /***
270          * {@inheritDoc}
271          * 
272          * @see net.sf.ehcache.distribution.CachePeer#remove(java.io.Serializable)
273          */
274         public boolean remove(Serializable key) throws IllegalStateException, RemoteException {
275             // no-op
276             return false;
277         }
278 
279         /***
280          * {@inheritDoc}
281          * 
282          * @see net.sf.ehcache.distribution.CachePeer#removeAll()
283          */
284         public void removeAll() throws RemoteException, IllegalStateException {
285             // no-op
286         }
287 
288         /***
289          * {@inheritDoc}
290          * 
291          * @see net.sf.ehcache.distribution.CachePeer#send(java.util.List)
292          */
293         public void send(List eventMessages) throws RemoteException {
294             // no-op
295 
296         }
297 
298     }
299 
300 }