1 // This file is part of OpenTSDB.
2 // Copyright (C) 2011-2012  The OpenTSDB Authors.
3 //
4 // This program is free software: you can redistribute it and/or modify it
5 // under the terms of the GNU Lesser General Public License as published by
6 // the Free Software Foundation, either version 2.1 of the License, or (at your
7 // option) any later version.  This program is distributed in the hope that it
8 // will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
9 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
10 // General Public License for more details.  You should have received a copy
11 // of the GNU Lesser General Public License along with this program.  If not,
12 // see <http://www.gnu.org/licenses/>.
13 package net.opentsdb.tsd;
14 
15 import static org.mockito.Matchers.any;
16 import static org.mockito.Mockito.when;
17 import static org.powermock.api.mockito.PowerMockito.mock;
18 
19 import java.net.SocketAddress;
20 import java.nio.charset.Charset;
21 import java.util.HashMap;
22 
23 import net.opentsdb.core.TSDB;
24 import net.opentsdb.utils.Config;
25 
26 import org.jboss.netty.buffer.ChannelBuffer;
27 import org.jboss.netty.buffer.ChannelBuffers;
28 import org.jboss.netty.channel.Channel;
29 import org.jboss.netty.channel.ChannelFuture;
30 import org.jboss.netty.channel.DefaultChannelFuture;
31 import org.jboss.netty.channel.DefaultChannelPipeline;
32 import org.jboss.netty.handler.codec.http.DefaultHttpRequest;
33 import org.jboss.netty.handler.codec.http.HttpMethod;
34 import org.jboss.netty.handler.codec.http.HttpRequest;
35 import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
36 import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
37 import org.jboss.netty.handler.codec.http.HttpVersion;
38 import org.junit.Ignore;
39 import org.powermock.reflect.Whitebox;
40 
41 /**
42  * Helper class that provides mockups for testing any OpenTSDB processes that
43  * deal with Netty.
44  */
45 @Ignore
46 public final class NettyMocks {
47 
48   /**
49    * Sets up a TSDB object for HTTP RPC tests that has a Config object
50    * @return A TSDB mock
51    */
getMockedHTTPTSDB()52   public static TSDB getMockedHTTPTSDB() {
53     final TSDB tsdb = mock(TSDB.class);
54     final Config config = mock(Config.class);
55     HashMap<String, String> properties = new HashMap<String, String>();
56     properties.put("tsd.http.show_stack_trace", "true");
57     Whitebox.setInternalState(config, "properties", properties);
58     when(tsdb.getConfig()).thenReturn(config);
59     return tsdb;
60   }
61 
62   /**
63    * Returns a mocked Channel object that simply sets the name to
64    * [fake channel]
65    * @return A Channel mock
66    */
fakeChannel()67   public static Channel fakeChannel() {
68     final Channel chan = mock(Channel.class);
69     when(chan.toString()).thenReturn("[fake channel]");
70     when(chan.isConnected()).thenReturn(true);
71     when(chan.isWritable()).thenReturn(true);
72 
73     final SocketAddress socket = mock(SocketAddress.class);
74     when(socket.toString()).thenReturn("192.168.1.1:4243");
75     when(chan.getRemoteAddress()).thenReturn(socket);
76     return chan;
77   }
78 
79   /**
80    * Returns an HttpQuery object with the given URI and the following parameters:
81    * Method = GET
82    * Content = null
83    * Content-Type = null
84    * @param tsdb The TSDB to associate with, needs to be mocked with the Config
85    * object set
86    * @param uri A URI to use
87    * @return an HttpQuery object
88    */
getQuery(final TSDB tsdb, final String uri)89   public static HttpQuery getQuery(final TSDB tsdb, final String uri) {
90     final Channel channelMock = NettyMocks.fakeChannel();
91     final HttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
92         HttpMethod.GET, uri);
93     return new HttpQuery(tsdb, req, channelMock);
94   }
95 
96   /**
97    * Returns an HttpQuery object with the given uri, content and type
98    * Method = POST
99    * @param tsdb The TSDB to associate with, needs to be mocked with the Config
100    * object set
101    * @param uri A URI to use
102    * @param content Content to POST (UTF-8 encoding)
103    * @return an HttpQuery object
104    */
postQuery(final TSDB tsdb, final String uri, final String content)105   public static HttpQuery postQuery(final TSDB tsdb, final String uri,
106       final String content) {
107     return postQuery(tsdb, uri, content, "application/json; charset=UTF-8");
108   }
109 
110   /**
111    * Returns an HttpQuery object with the given uri, content and type
112    * Method = POST
113    * @param tsdb The TSDB to associate with, needs to be mocked with the Config
114    * object set
115    * @param uri A URI to use
116    * @param content Content to POST (UTF-8 encoding)
117    * @param type Content-Type value
118    * @return an HttpQuery object
119    */
postQuery(final TSDB tsdb, final String uri, final String content, final String type)120   public static HttpQuery postQuery(final TSDB tsdb, final String uri,
121       final String content, final String type) {
122     return contentQuery(tsdb, uri, content, type, HttpMethod.POST);
123   }
124 
125   /**
126    * Returns an HttpQuery object with the given uri, content and type
127    * Method = PUT
128    * @param tsdb The TSDB to associate with, needs to be mocked with the Config
129    * object set
130    * @param uri A URI to use
131    * @param content Content to POST (UTF-8 encoding)
132    * @return an HttpQuery object
133    */
putQuery(final TSDB tsdb, final String uri, final String content)134   public static HttpQuery putQuery(final TSDB tsdb, final String uri,
135       final String content) {
136     return putQuery(tsdb, uri, content, "application/json; charset=UTF-8");
137   }
138 
139   /**
140    * Returns an HttpQuery object with the given uri, content and type
141    * Method = PUT
142    * @param tsdb The TSDB to associate with, needs to be mocked with the Config
143    * object set
144    * @param uri A URI to use
145    * @param content Content to POST (UTF-8 encoding)
146    * @param type Content-Type value
147    * @return an HttpQuery object
148    */
putQuery(final TSDB tsdb, final String uri, final String content, final String type)149   public static HttpQuery putQuery(final TSDB tsdb, final String uri,
150       final String content, final String type) {
151     return contentQuery(tsdb, uri, content, type, HttpMethod.PUT);
152   }
153 
154   /**
155    * Returns an HttpQuery object with the given uri, content and type
156    * Method = DELETE
157    * @param tsdb The TSDB to associate with, needs to be mocked with the Config
158    * object set
159    * @param uri A URI to use
160    * @param content Content to POST (UTF-8 encoding)
161    * @return an HttpQuery object
162    */
deleteQuery(final TSDB tsdb, final String uri, final String content)163   public static HttpQuery deleteQuery(final TSDB tsdb, final String uri,
164       final String content) {
165     return deleteQuery(tsdb, uri, content, "application/json; charset=UTF-8");
166   }
167 
168   /**
169    * Returns an HttpQuery object with the given uri, content and type
170    * Method = DELETE
171    * @param tsdb The TSDB to associate with, needs to be mocked with the Config
172    * object set
173    * @param uri A URI to use
174    * @param content Content to POST (UTF-8 encoding)
175    * @param type Content-Type value
176    * @return an HttpQuery object
177    */
deleteQuery(final TSDB tsdb, final String uri, final String content, final String type)178   public static HttpQuery deleteQuery(final TSDB tsdb, final String uri,
179       final String content, final String type) {
180     return contentQuery(tsdb, uri, content, type, HttpMethod.DELETE);
181   }
182 
183   /**
184    * Returns an HttpQuery object with the given settings
185    * @param tsdb The TSDB to associate with, needs to be mocked with the Config
186    * object set
187    * @param uri A URI to use
188    * @param content Content to POST (UTF-8 encoding)
189    * @param type Content-Type value
190    * @param method The HTTP method to use, GET, POST, etc.
191    * @return an HttpQuery object
192    */
contentQuery(final TSDB tsdb, final String uri, final String content, final String type, final HttpMethod method)193   public static HttpQuery contentQuery(final TSDB tsdb, final String uri,
194       final String content, final String type, final HttpMethod method) {
195     final Channel channelMock = NettyMocks.fakeChannel();
196     final HttpRequest req = new DefaultHttpRequest(HttpVersion.HTTP_1_1,
197         method, uri);
198     if (content != null) {
199       req.setContent(ChannelBuffers.copiedBuffer(content,
200           Charset.forName("UTF-8")));
201     }
202     req.headers().set("Content-Type", type);
203     return new HttpQuery(tsdb, req, channelMock);
204   }
205 
206   /** @param the query to mock a future callback for */
mockChannelFuture(final HttpQuery query)207   public static void mockChannelFuture(final HttpQuery query) {
208     final ChannelFuture future = new DefaultChannelFuture(query.channel(), false);
209     when(query.channel().write(any(ChannelBuffer.class))).thenReturn(future);
210     future.setSuccess();
211   }
212 
213   /**
214    * Returns a simple pipeline with an HttpRequestDecoder and an
215    * HttpResponseEncoder. No mocking, returns an actual pipeline
216    * @return The pipeline
217    */
createHttpPipeline()218   private DefaultChannelPipeline createHttpPipeline() {
219     DefaultChannelPipeline pipeline = new DefaultChannelPipeline();
220     pipeline.addLast("requestDecoder", new HttpRequestDecoder());
221     pipeline.addLast("responseEncoder", new HttpResponseEncoder());
222     return pipeline;
223   }
224 }
225