1 // This file is part of OpenTSDB.
2 // Copyright (C) 2013  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.Matchers.anyLong;
17 import static org.mockito.Matchers.anyString;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.never;
20 import static org.mockito.Mockito.times;
21 import static org.mockito.Mockito.verify;
22 import static org.mockito.Mockito.when;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertNotNull;
26 import static org.junit.Assert.assertNull;
27 import static org.junit.Assert.assertTrue;
28 
29 import java.nio.charset.Charset;
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.concurrent.atomic.AtomicLong;
33 
34 import net.opentsdb.core.BaseTsdbTest.FakeTaskTimer;
35 import net.opentsdb.core.IncomingDataPoint;
36 import net.opentsdb.core.TSDB;
37 import net.opentsdb.uid.NoSuchUniqueName;
38 import net.opentsdb.utils.Config;
39 
40 import org.jboss.netty.channel.Channel;
41 import org.jboss.netty.handler.codec.http.HttpResponseStatus;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.powermock.core.classloader.annotations.PowerMockIgnore;
46 import org.powermock.core.classloader.annotations.PrepareForTest;
47 import org.powermock.modules.junit4.PowerMockRunner;
48 import org.powermock.reflect.Whitebox;
49 
50 import com.stumbleupon.async.Deferred;
51 
52 @RunWith(PowerMockRunner.class)
53 //"Classloader hell"...  It's real.  Tell PowerMock to ignore these classes
54 //because they fiddle with the class loader.  We don't test them anyway.
55 @PowerMockIgnore({"javax.management.*", "javax.xml.*",
56              "ch.qos.*", "org.slf4j.*",
57              "com.sum.*", "org.xml.*"})
58 @PrepareForTest({ TSDB.class, Config.class, HttpQuery.class,
59   StorageExceptionHandler.class })
60 public final class TestPutRpc {
61   private static final Map<String, String> TAGS = new HashMap<String, String>(1);
62   static {
63     TAGS.put("host", "web01");
64   }
65   private TSDB tsdb = null;
66   private AtomicLong requests = new AtomicLong();
67   private AtomicLong hbase_errors = new AtomicLong();
68   private AtomicLong invalid_values = new AtomicLong();
69   private AtomicLong illegal_arguments = new AtomicLong();
70   private AtomicLong unknown_metrics = new AtomicLong();
71   private AtomicLong writes_blocked = new AtomicLong();
72   private StorageExceptionHandler handler;
73   private FakeTaskTimer timer;
74 
75   @Before
before()76   public void before() throws Exception {
77     tsdb = NettyMocks.getMockedHTTPTSDB();
78     when(tsdb.addPoint("sys.cpu.nice", 1365465600, 42, TAGS))
79       .thenReturn(Deferred.fromResult(new Object()));
80     when(tsdb.addPoint("sys.cpu.nice", 1365465600, -42, TAGS))
81       .thenReturn(Deferred.fromResult(new Object()));
82     when(tsdb.addPoint("sys.cpu.nice", 1365465600, 42.2f, TAGS))
83       .thenReturn(Deferred.fromResult(new Object()));
84     when(tsdb.addPoint("sys.cpu.nice", 1365465600, -42.2f, TAGS))
85       .thenReturn(Deferred.fromResult(new Object()));
86     when(tsdb.addPoint("sys.cpu.nice", 1365465600, 4220.0f, TAGS))
87       .thenReturn(Deferred.fromResult(new Object()));
88     when(tsdb.addPoint("sys.cpu.nice", 1365465600, -4220.0f, TAGS))
89       .thenReturn(Deferred.fromResult(new Object()));
90     when(tsdb.addPoint("sys.cpu.nice", 1365465600, .0042f, TAGS))
91       .thenReturn(Deferred.fromResult(new Object()));
92     when(tsdb.addPoint("sys.cpu.nice", 1365465600, -0.0042f, TAGS))
93       .thenReturn(Deferred.fromResult(new Object()));
94     when(tsdb.addPoint("sys.cpu.system", 1365465600, 24, TAGS))
95       .thenReturn(Deferred.fromResult(new Object()));
96     // errors
97     when(tsdb.addPoint("doesnotexist", 1365465600, 42, TAGS))
98       .thenThrow(new NoSuchUniqueName("metric", "doesnotexist"));
99     when(tsdb.addPoint("sys.cpu.system", 1365465600, 1, TAGS))
100       .thenReturn(Deferred.fromError(new RuntimeException("Wotcher!")));
101     when(tsdb.addPoint("sys.cpu.system", 1365465600, 2, TAGS))
102       .thenReturn(new Deferred<Object>());
103 
104     requests = Whitebox.getInternalState(PutDataPointRpc.class, "requests");
105     requests.set(0);
106     hbase_errors = Whitebox.getInternalState(PutDataPointRpc.class, "hbase_errors");
107     hbase_errors.set(0);
108     invalid_values = Whitebox.getInternalState(PutDataPointRpc.class, "invalid_values");
109     invalid_values.set(0);
110     illegal_arguments = Whitebox.getInternalState(PutDataPointRpc.class, "illegal_arguments");
111     illegal_arguments.set(0);
112     unknown_metrics = Whitebox.getInternalState(PutDataPointRpc.class, "unknown_metrics");
113     unknown_metrics.set(0);
114     writes_blocked = Whitebox.getInternalState(PutDataPointRpc.class, "writes_blocked");
115     writes_blocked.set(0);
116 
117     timer = new FakeTaskTimer();
118 
119     handler = mock(StorageExceptionHandler.class);
120     when(tsdb.getStorageExceptionHandler()).thenReturn(handler);
121     when(tsdb.getTimer()).thenReturn(timer);
122   }
123 
124   @Test
constructor()125   public void constructor() {
126     assertNotNull(new PutDataPointRpc());
127   }
128 
129   // Socket RPC Tests ------------------------------------
130 
131   @Test
execute()132   public void execute() throws Exception {
133     final PutDataPointRpc put = new PutDataPointRpc();
134     final Channel chan = NettyMocks.fakeChannel();
135     assertNotNull(put.execute(tsdb, chan, new String[] { "put", "sys.cpu.nice",
136         "1365465600", "42", "host=web01" }).joinUninterruptibly());
137     assertEquals(1, requests.get());
138     assertEquals(0, invalid_values.get());
139     verify(chan, never()).write(any());
140     verify(chan, never()).isConnected();
141     verify(tsdb, never()).getStorageExceptionHandler();
142   }
143 
144   @Test
executeBadValue()145   public void executeBadValue() throws Exception {
146     final PutDataPointRpc put = new PutDataPointRpc();
147     final Channel chan = NettyMocks.fakeChannel();
148     assertNull(put.execute(tsdb, chan, new String[] { "put", "sys.cpu.nice",
149         "1365465600", "notanum", "host=web01" }).joinUninterruptibly());
150     assertEquals(1, requests.get());
151     assertEquals(1, invalid_values.get());
152     verify(chan, times(1)).write(any());
153     verify(chan, times(1)).isConnected();
154     verify(tsdb, never()).getStorageExceptionHandler();
155   }
156 
157   @Test
executeMissingMetric()158   public void executeMissingMetric() throws Exception {
159     final PutDataPointRpc put = new PutDataPointRpc();
160     final Channel chan = NettyMocks.fakeChannel();
161     assertNull(put.execute(tsdb, chan, new String[] { "put", "",
162         "1365465600", "42", "host=web01" }).joinUninterruptibly());
163     assertEquals(1, requests.get());
164     assertEquals(0, invalid_values.get());
165     assertEquals(1, illegal_arguments.get());
166     verify(chan, times(1)).write(any());
167     verify(chan, times(1)).isConnected();
168     verify(tsdb, never()).getStorageExceptionHandler();
169   }
170 
171   @Test
executeMissingMetricNotWriteable()172   public void executeMissingMetricNotWriteable() throws Exception {
173     final PutDataPointRpc put = new PutDataPointRpc();
174     final Channel chan = NettyMocks.fakeChannel();
175     when(chan.isWritable()).thenReturn(false);
176     assertNull(put.execute(tsdb, chan, new String[] { "put", "",
177         "1365465600", "42", "host=web01" }).joinUninterruptibly());
178     assertEquals(1, requests.get());
179     assertEquals(0, invalid_values.get());
180     assertEquals(1, illegal_arguments.get());
181     assertEquals(1, writes_blocked.get());
182     verify(chan, never()).write(any());
183     verify(chan, times(1)).isConnected();
184     verify(tsdb, never()).getStorageExceptionHandler();
185   }
186 
187   @Test
executeUnknownMetric()188   public void executeUnknownMetric() throws Exception {
189     final PutDataPointRpc put = new PutDataPointRpc();
190     final Channel chan = NettyMocks.fakeChannel();
191     assertNull(put.execute(tsdb, chan, new String[] { "put", "doesnotexist",
192         "1365465600", "42", "host=web01" }).joinUninterruptibly());
193     assertEquals(1, requests.get());
194     assertEquals(0, invalid_values.get());
195     assertEquals(1, unknown_metrics.get());
196     verify(chan, times(1)).write(any());
197     verify(chan, times(1)).isConnected();
198     verify(tsdb, never()).getStorageExceptionHandler();
199   }
200 
201   @SuppressWarnings("unchecked")
202   @Test (expected = RuntimeException.class)
executeRuntimeException()203   public void executeRuntimeException() throws Exception {
204     when(tsdb.addPoint(anyString(), anyLong(), anyLong(),
205         (HashMap<String, String>)any()))
206         .thenThrow(new RuntimeException("Fail!"));
207 
208     final PutDataPointRpc put = new PutDataPointRpc();
209     final Channel chan = NettyMocks.fakeChannel();
210     put.execute(tsdb, chan, new String[] { "put", "doesnotexist",
211         "1365465600", "42", "host=web01" });
212   }
213 
214   @SuppressWarnings("unchecked")
215   @Test
executeHBaseError()216   public void executeHBaseError() throws Exception {
217     when(tsdb.addPoint(anyString(), anyLong(), anyLong(),
218         (HashMap<String, String>)any(HashMap.class)))
219         .thenReturn(Deferred.fromError(new RuntimeException("Wotcher!")));
220 
221     final PutDataPointRpc put = new PutDataPointRpc();
222     final Channel chan = NettyMocks.fakeChannel();
223     assertNull(put.execute(tsdb, chan, new String[] { "put", "sys.cpu.nice",
224         "1365465600", "42", "host=web01" }).joinUninterruptibly());
225 
226     assertEquals(1, requests.get());
227     assertEquals(0, invalid_values.get());
228     assertEquals(1, hbase_errors.get());
229     verify(chan, times(1)).write(any());
230     verify(chan, times(1)).isConnected();
231     verify(tsdb, times(1)).getStorageExceptionHandler();
232   }
233 
234   @SuppressWarnings("unchecked")
235   @Test
executeHBaseErrorNotWriteable()236   public void executeHBaseErrorNotWriteable() throws Exception {
237     when(tsdb.addPoint(anyString(), anyLong(), anyLong(),
238         (HashMap<String, String>)any()))
239         .thenReturn(Deferred.fromError(new RuntimeException("Wotcher!")));
240 
241     final PutDataPointRpc put = new PutDataPointRpc();
242     final Channel chan = NettyMocks.fakeChannel();
243     when(chan.isWritable()).thenReturn(false);
244     assertNull(put.execute(tsdb, chan, new String[] { "put", "sys.cpu.nice",
245         "1365465600", "42", "host=web01" }).joinUninterruptibly());
246 
247     assertEquals(1, requests.get());
248     assertEquals(0, invalid_values.get());
249     assertEquals(1, hbase_errors.get());
250     assertEquals(1, writes_blocked.get());
251     verify(chan, never()).write(any());
252     verify(chan, times(1)).isConnected();
253     verify(tsdb, times(1)).getStorageExceptionHandler();
254   }
255 
256   @SuppressWarnings("unchecked")
257   @Test
executeHBaseErrorHandler()258   public void executeHBaseErrorHandler() throws Exception {
259     when(tsdb.addPoint(anyString(), anyLong(), anyLong(),
260         (HashMap<String, String>)any()))
261         .thenReturn(Deferred.fromError(new RuntimeException("Wotcher!")));
262 
263     final PutDataPointRpc put = new PutDataPointRpc();
264     final Channel chan = NettyMocks.fakeChannel();
265     assertNull(put.execute(tsdb, chan, new String[] { "put", "sys.cpu.nice",
266         "1365465600", "42", "host=web01" }).joinUninterruptibly());
267 
268     assertEquals(1, requests.get());
269     assertEquals(0, invalid_values.get());
270     assertEquals(1, hbase_errors.get());
271     verify(chan, times(1)).write(any());
272     verify(chan, times(1)).isConnected();
273     verify(tsdb, times(1)).getStorageExceptionHandler();
274     verify(handler, times(1)).handleError((IncomingDataPoint)any(),
275         (Exception)any());
276   }
277 
278   @Test (expected = NullPointerException.class)
executeNullTSDB()279   public void executeNullTSDB() throws Exception {
280     final PutDataPointRpc put = new PutDataPointRpc();
281     final Channel chan = NettyMocks.fakeChannel();
282     put.execute(null, chan, new String[] { "put", "sys.cpu.nice",
283         "1365465600", "42", "host=web01" });
284   }
285 
286   @Test
executeNullChannelOK()287   public void executeNullChannelOK() throws Exception {
288     // we can pass in a null channel but since we only write when an error occurs
289     // then we won't fail.
290     final PutDataPointRpc put = new PutDataPointRpc();
291     assertNotNull(put.execute(tsdb, null, new String[] { "put", "sys.cpu.nice",
292         "1365465600", "42", "host=web01" }).joinUninterruptibly());
293     assertEquals(1, requests.get());
294     assertEquals(0, invalid_values.get());
295     verify(tsdb, never()).getStorageExceptionHandler();
296   }
297 
298   @Test (expected = NullPointerException.class)
executeNullChannelError()299   public void executeNullChannelError() throws Exception {
300     final PutDataPointRpc put = new PutDataPointRpc();
301     put.execute(tsdb, null, new String[] { "put", "sys.cpu.nice",
302         "1365465600", "notanumber", "host=web01" });
303   }
304 
305   @Test (expected = NullPointerException.class)
executeNullArray()306   public void executeNullArray() throws Exception {
307     final PutDataPointRpc put = new PutDataPointRpc();
308     final Channel chan = NettyMocks.fakeChannel();
309     put.execute(tsdb, chan, null);
310   }
311 
312   @Test (expected = ArrayIndexOutOfBoundsException.class)
executeEmptyArray()313   public void executeEmptyArray() throws Exception {
314     final PutDataPointRpc put = new PutDataPointRpc();
315     final Channel chan = NettyMocks.fakeChannel();
316     put.execute(tsdb, chan, new String[0]);
317   }
318 
319   @Test
executeShortArray()320   public void executeShortArray() throws Exception {
321     final PutDataPointRpc put = new PutDataPointRpc();
322     final Channel chan = NettyMocks.fakeChannel();
323     assertNull(put.execute(tsdb, chan, new String[] { "put", "sys.cpu.nice",
324         "1365465600", "42" }).joinUninterruptibly());
325     assertEquals(1, requests.get());
326     assertEquals(0, invalid_values.get());
327     assertEquals(1, illegal_arguments.get());
328     verify(chan, times(1)).write(any());
329     verify(chan, times(1)).isConnected();
330     verify(tsdb, never()).getStorageExceptionHandler();
331   }
332 
333   // HTTP RPC Tests --------------------------------------
334 
335   @Test
putSingle()336   public void putSingle() throws Exception {
337     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
338         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
339         +":42,\"tags\":{\"host\":\"web01\"}}");
340     PutDataPointRpc put = new PutDataPointRpc();
341     put.execute(tsdb, query);
342     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
343     assertEquals(1, requests.get());
344     assertEquals(0, invalid_values.get());
345     verify(tsdb, never()).getStorageExceptionHandler();
346   }
347 
348   @Test
putDouble()349   public void putDouble() throws Exception {
350     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
351         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
352         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
353         + "\"timestamp\":1365465600,\"value\":24,\"tags\":"
354         + "{\"host\":\"web01\"}}]");
355     PutDataPointRpc put = new PutDataPointRpc();
356     put.execute(tsdb, query);
357     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
358     assertEquals(1, requests.get());
359     assertEquals(0, invalid_values.get());
360     verify(tsdb, never()).getStorageExceptionHandler();
361   }
362 
363   @Test
putSingleSummary()364   public void putSingleSummary() throws Exception {
365     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?summary",
366         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
367         +":42,\"tags\":{\"host\":\"web01\"}}");
368     PutDataPointRpc put = new PutDataPointRpc();
369     put.execute(tsdb, query);
370     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
371     final String response =
372       query.response().getContent().toString(Charset.forName("UTF-8"));
373     assertTrue(response.contains("\"failed\":0"));
374     assertTrue(response.contains("\"success\":1"));
375     assertEquals(1, requests.get());
376     assertEquals(0, invalid_values.get());
377     verify(tsdb, never()).getStorageExceptionHandler();
378   }
379 
380   @Test
putSingleDetails()381   public void putSingleDetails() throws Exception {
382     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
383         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
384         +":42,\"tags\":{\"host\":\"web01\"}}");
385     PutDataPointRpc put = new PutDataPointRpc();
386     put.execute(tsdb, query);
387     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
388     final String response =
389       query.response().getContent().toString(Charset.forName("UTF-8"));
390     assertTrue(response.contains("\"failed\":0"));
391     assertTrue(response.contains("\"success\":1"));
392     assertTrue(response.contains("\"errors\":[]"));
393     assertEquals(1, requests.get());
394     assertEquals(0, invalid_values.get());
395     verify(tsdb, never()).getStorageExceptionHandler();
396   }
397 
398   @Test
putSingleSummaryAndDetails()399   public void putSingleSummaryAndDetails() throws Exception {
400     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?summary&details",
401         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
402         +":42,\"tags\":{\"host\":\"web01\"}}");
403     PutDataPointRpc put = new PutDataPointRpc();
404     put.execute(tsdb, query);
405     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
406     final String response =
407       query.response().getContent().toString(Charset.forName("UTF-8"));
408     assertTrue(response.contains("\"failed\":0"));
409     assertTrue(response.contains("\"success\":1"));
410     assertTrue(response.contains("\"errors\":[]"));
411     assertEquals(1, requests.get());
412     assertEquals(0, invalid_values.get());
413     verify(tsdb, never()).getStorageExceptionHandler();
414   }
415 
416   @Test
putDoubleSummary()417   public void putDoubleSummary() throws Exception {
418     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?summary",
419         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
420         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
421         + "\"timestamp\":1365465600,\"value\":24,\"tags\":"
422         + "{\"host\":\"web01\"}}]");
423     PutDataPointRpc put = new PutDataPointRpc();
424     put.execute(tsdb, query);
425     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
426     final String response =
427       query.response().getContent().toString(Charset.forName("UTF-8"));
428     assertTrue(response.contains("\"failed\":0"));
429     assertTrue(response.contains("\"success\":2"));
430     assertEquals(1, requests.get());
431     assertEquals(0, invalid_values.get());
432     verify(tsdb, never()).getStorageExceptionHandler();
433   }
434 
435   @Test
putNegativeInt()436   public void putNegativeInt() throws Exception {
437     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
438         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
439         +":-42,\"tags\":{\"host\":\"web01\"}}");
440     PutDataPointRpc put = new PutDataPointRpc();
441     put.execute(tsdb, query);
442     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
443     assertEquals(1, requests.get());
444     assertEquals(0, invalid_values.get());
445     verify(tsdb, never()).getStorageExceptionHandler();
446   }
447 
448   @Test
putFloat()449   public void putFloat() throws Exception {
450     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
451         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
452         +":42.2,\"tags\":{\"host\":\"web01\"}}");
453     PutDataPointRpc put = new PutDataPointRpc();
454     put.execute(tsdb, query);
455     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
456     assertEquals(1, requests.get());
457     assertEquals(0, invalid_values.get());
458     verify(tsdb, never()).getStorageExceptionHandler();
459   }
460 
461   @Test
putNegativeFloat()462   public void putNegativeFloat() throws Exception {
463     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
464         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
465         +":-42.2,\"tags\":{\"host\":\"web01\"}}");
466     PutDataPointRpc put = new PutDataPointRpc();
467     put.execute(tsdb, query);
468     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
469     assertEquals(1, requests.get());
470     assertEquals(0, invalid_values.get());
471     verify(tsdb, never()).getStorageExceptionHandler();
472   }
473 
474   @Test
putSEBig()475   public void putSEBig() throws Exception {
476     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
477         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
478         +":4.22e3,\"tags\":{\"host\":\"web01\"}}");
479     PutDataPointRpc put = new PutDataPointRpc();
480     put.execute(tsdb, query);
481     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
482     assertEquals(1, requests.get());
483     assertEquals(0, invalid_values.get());
484     verify(tsdb, never()).getStorageExceptionHandler();
485   }
486 
487   @Test
putSECaseBig()488   public void putSECaseBig() throws Exception {
489     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
490         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
491         +":4.22E3,\"tags\":{\"host\":\"web01\"}}");
492     PutDataPointRpc put = new PutDataPointRpc();
493     put.execute(tsdb, query);
494     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
495     assertEquals(1, requests.get());
496     assertEquals(0, invalid_values.get());
497     verify(tsdb, never()).getStorageExceptionHandler();
498   }
499 
500   @Test
putNegativeSEBig()501   public void putNegativeSEBig() throws Exception {
502     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
503         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
504         +":-4.22e3,\"tags\":{\"host\":\"web01\"}}");
505     PutDataPointRpc put = new PutDataPointRpc();
506     put.execute(tsdb, query);
507     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
508     assertEquals(1, requests.get());
509     assertEquals(0, invalid_values.get());
510     verify(tsdb, never()).getStorageExceptionHandler();
511   }
512 
513   @Test
putNegativeSECaseBig()514   public void putNegativeSECaseBig() throws Exception {
515     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
516         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
517         +":-4.22E3,\"tags\":{\"host\":\"web01\"}}");
518     PutDataPointRpc put = new PutDataPointRpc();
519     put.execute(tsdb, query);
520     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
521     assertEquals(1, requests.get());
522     assertEquals(0, invalid_values.get());
523     verify(tsdb, never()).getStorageExceptionHandler();
524   }
525 
526   @Test
putSETiny()527   public void putSETiny() throws Exception {
528     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
529         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
530         +":4.2e-3,\"tags\":{\"host\":\"web01\"}}");
531     PutDataPointRpc put = new PutDataPointRpc();
532     put.execute(tsdb, query);
533     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
534     assertEquals(1, requests.get());
535     assertEquals(0, invalid_values.get());
536     verify(tsdb, never()).getStorageExceptionHandler();
537   }
538 
539   @Test
putSECaseTiny()540   public void putSECaseTiny() throws Exception {
541     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
542         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
543         +":4.2E-3,\"tags\":{\"host\":\"web01\"}}");
544     PutDataPointRpc put = new PutDataPointRpc();
545     put.execute(tsdb, query);
546     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
547     assertEquals(1, requests.get());
548     assertEquals(0, invalid_values.get());
549     verify(tsdb, never()).getStorageExceptionHandler();
550   }
551 
552   @Test
putNegativeSETiny()553   public void putNegativeSETiny() throws Exception {
554     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
555         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
556         +":-4.2e-3,\"tags\":{\"host\":\"web01\"}}");
557     PutDataPointRpc put = new PutDataPointRpc();
558     put.execute(tsdb, query);
559     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
560     assertEquals(1, requests.get());
561     assertEquals(0, invalid_values.get());
562     verify(tsdb, never()).getStorageExceptionHandler();
563   }
564 
565   @Test
putNegativeSECaseTiny()566   public void putNegativeSECaseTiny() throws Exception {
567     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
568         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
569         +":-4.2E-3,\"tags\":{\"host\":\"web01\"}}");
570     PutDataPointRpc put = new PutDataPointRpc();
571     put.execute(tsdb, query);
572     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
573     assertEquals(1, requests.get());
574     assertEquals(0, invalid_values.get());
575     verify(tsdb, never()).getStorageExceptionHandler();
576   }
577 
578   @Test
badMethod()579   public void badMethod() throws Exception {
580     HttpQuery query = NettyMocks.getQuery(tsdb, "/api/put");
581     PutDataPointRpc put = new PutDataPointRpc();
582     BadRequestException ex = null;
583     try {
584       put.execute(tsdb, query);
585     } catch (BadRequestException e) {
586       ex = e;
587     }
588     assertNotNull(ex);
589     assertEquals(1, requests.get());
590     assertEquals(0, invalid_values.get());
591     verify(tsdb, never()).getStorageExceptionHandler();
592   }
593 
594   @Test
badJSON()595   public void badJSON() throws Exception {
596     // missing a quotation mark
597     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put",
598         "{\"metric\":\"sys.cpu.nice\",\"timestamp:1365465600,\"value\""
599         +":42,\"tags\":{\"host\":\"web01\"}}");
600     PutDataPointRpc put = new PutDataPointRpc();
601     BadRequestException ex = null;
602     try {
603       put.execute(tsdb, query);
604     } catch (BadRequestException e) {
605       ex = e;
606     }
607     assertNotNull(ex);
608     assertEquals(1, requests.get());
609     assertEquals(0, invalid_values.get());
610     assertEquals(0, illegal_arguments.get());
611     verify(tsdb, never()).getStorageExceptionHandler();
612   }
613 
614   @Test
notJSON()615   public void notJSON() throws Exception {
616     // missing a quotation mark
617     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put", "Hello World");
618     PutDataPointRpc put = new PutDataPointRpc();
619     BadRequestException ex = null;
620     try {
621       put.execute(tsdb, query);
622     } catch (BadRequestException e) {
623       ex = e;
624     }
625     assertNotNull(ex);
626     assertEquals(1, requests.get());
627     assertEquals(0, invalid_values.get());
628     assertEquals(0, illegal_arguments.get());
629     verify(tsdb, never()).getStorageExceptionHandler();
630   }
631 
632   @Test
noContent()633   public void noContent() throws Exception {
634     // missing a quotation mark
635     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put", "");
636     PutDataPointRpc put = new PutDataPointRpc();
637     BadRequestException ex = null;
638     try {
639       put.execute(tsdb, query);
640     } catch (BadRequestException e) {
641       ex = e;
642     }
643     assertNotNull(ex);
644     assertEquals(1, requests.get());
645     assertEquals(0, invalid_values.get());
646     assertEquals(0, illegal_arguments.get());
647     verify(tsdb, never()).getStorageExceptionHandler();
648   }
649 
650   @SuppressWarnings("unchecked")
651   @Test
hbaseError()652   public void hbaseError() throws Exception {
653     when(tsdb.addPoint(anyString(), anyLong(), anyLong(),
654         (HashMap<String, String>)any()))
655         .thenReturn(Deferred.fromError(new RuntimeException("Wotcher!")));
656     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
657         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
658         +":42,\"tags\":{\"host\":\"web01\"}}");
659     PutDataPointRpc put = new PutDataPointRpc();
660     BadRequestException ex = null;
661     try {
662       put.execute(tsdb, query);
663     } catch (BadRequestException e) {
664       ex = e;
665     }
666     assertNull(ex);
667     assertEquals(1, requests.get());
668     assertEquals(0, invalid_values.get());
669     assertEquals(1, hbase_errors.get());
670     verify(tsdb, times(1)).getStorageExceptionHandler();
671   }
672 
673   @SuppressWarnings("unchecked")
674   @Test
hbaseErrorHandler()675   public void hbaseErrorHandler() throws Exception {
676     final StorageExceptionHandler handler = mock(StorageExceptionHandler.class);
677     when(tsdb.getStorageExceptionHandler()).thenReturn(handler);
678     when(tsdb.addPoint(anyString(), anyLong(), anyLong(),
679         (HashMap<String, String>)any()))
680         .thenReturn(Deferred.fromError(new RuntimeException("Wotcher!")));
681     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
682         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
683         +":42,\"tags\":{\"host\":\"web01\"}}");
684     PutDataPointRpc put = new PutDataPointRpc();
685     BadRequestException ex = null;
686     try {
687       put.execute(tsdb, query);
688     } catch (BadRequestException e) {
689       ex = e;
690     }
691     assertNull(ex);
692     assertEquals(1, requests.get());
693     assertEquals(0, invalid_values.get());
694     assertEquals(1, hbase_errors.get());
695     verify(tsdb, times(1)).getStorageExceptionHandler();
696     verify(handler, times(1)).handleError((IncomingDataPoint)any(),
697         (Exception)any());
698   }
699 
700   @Test
noSuchUniqueName()701   public void noSuchUniqueName() throws Exception {
702     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
703         "{\"metric\":\"doesnotexist\",\"timestamp\":1365465600,\"value\""
704         +":42,\"tags\":{\"host\":\"web01\"}}");
705     PutDataPointRpc put = new PutDataPointRpc();
706     put.execute(tsdb, query);
707     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
708     final String response =
709       query.response().getContent().toString(Charset.forName("UTF-8"));
710     assertTrue(response.contains("\"error\":\"Unknown metric\""));
711     assertTrue(response.contains("\"failed\":1"));
712     assertTrue(response.contains("\"success\":0"));
713     assertEquals(1, requests.get());
714     assertEquals(0, invalid_values.get());
715     assertEquals(0, illegal_arguments.get());
716     assertEquals(1, unknown_metrics.get());
717     verify(tsdb, never()).getStorageExceptionHandler();
718   }
719 
720   @Test
missingMetric()721   public void missingMetric() throws Exception {
722     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
723         "{\"timestamp\":1365465600,\"value\""
724         +":42,\"tags\":{\"host\":\"web01\"}}");
725     PutDataPointRpc put = new PutDataPointRpc();
726     put.execute(tsdb, query);
727     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
728     final String response =
729       query.response().getContent().toString(Charset.forName("UTF-8"));
730     assertTrue(response.contains("\"error\":\"Metric name was empty\""));
731     assertTrue(response.contains("\"failed\":1"));
732     assertTrue(response.contains("\"success\":0"));
733     assertEquals(1, requests.get());
734     assertEquals(0, invalid_values.get());
735     assertEquals(1, illegal_arguments.get());
736     verify(tsdb, never()).getStorageExceptionHandler();
737   }
738 
739   @Test
nullMetric()740   public void nullMetric() throws Exception {
741     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
742         "{\"metric\":null,\"timestamp\":1365465600,\"value\""
743         +":42,\"tags\":{\"host\":\"web01\"}}");
744     PutDataPointRpc put = new PutDataPointRpc();
745     put.execute(tsdb, query);
746     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
747     final String response =
748       query.response().getContent().toString(Charset.forName("UTF-8"));
749     assertTrue(response.contains("\"error\":\"Metric name was empty\""));
750     assertTrue(response.contains("\"failed\":1"));
751     assertTrue(response.contains("\"success\":0"));
752     assertEquals(1, requests.get());
753     assertEquals(0, invalid_values.get());
754     assertEquals(1, illegal_arguments.get());
755     verify(tsdb, never()).getStorageExceptionHandler();
756   }
757 
758   @Test
missingTimestamp()759   public void missingTimestamp() throws Exception {
760     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
761         "{\"metric\":\"sys.cpu.nice\",\"value\""
762         +":42,\"tags\":{\"host\":\"web01\"}}");
763     PutDataPointRpc put = new PutDataPointRpc();
764     put.execute(tsdb, query);
765     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
766     final String response =
767       query.response().getContent().toString(Charset.forName("UTF-8"));
768     assertTrue(response.contains("\"error\":\"Invalid timestamp\""));
769     assertTrue(response.contains("\"failed\":1"));
770     assertTrue(response.contains("\"success\":0"));
771     assertEquals(1, requests.get());
772     assertEquals(0, invalid_values.get());
773     assertEquals(1, illegal_arguments.get());
774     verify(tsdb, never()).getStorageExceptionHandler();
775   }
776 
777   @Test
nullTimestamp()778   public void nullTimestamp() throws Exception {
779     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
780         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":null,\"value\""
781         +":42,\"tags\":{\"host\":\"web01\"}}");
782     PutDataPointRpc put = new PutDataPointRpc();
783     put.execute(tsdb, query);
784     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
785     final String response =
786       query.response().getContent().toString(Charset.forName("UTF-8"));
787     assertTrue(response.contains("\"error\":\"Invalid timestamp\""));
788     assertTrue(response.contains("\"failed\":1"));
789     assertTrue(response.contains("\"success\":0"));
790     assertEquals(1, requests.get());
791     assertEquals(0, invalid_values.get());
792     assertEquals(1, illegal_arguments.get());
793     verify(tsdb, never()).getStorageExceptionHandler();
794   }
795 
796   @Test
invalidTimestamp()797   public void invalidTimestamp() throws Exception {
798     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
799         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":-1,\"value\""
800         +":42,\"tags\":{\"host\":\"web01\"}}");
801     PutDataPointRpc put = new PutDataPointRpc();
802     put.execute(tsdb, query);
803     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
804     final String response =
805       query.response().getContent().toString(Charset.forName("UTF-8"));
806     assertTrue(response.contains("\"error\":\"Invalid timestamp\""));
807     assertTrue(response.contains("\"failed\":1"));
808     assertTrue(response.contains("\"success\":0"));
809     assertEquals(1, requests.get());
810     assertEquals(0, invalid_values.get());
811     assertEquals(1, illegal_arguments.get());
812     verify(tsdb, never()).getStorageExceptionHandler();
813   }
814 
815   @Test
missingValue()816   public void missingValue() throws Exception {
817     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
818         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"tags\":"
819         + "{\"host\":\"web01\"}}");
820     PutDataPointRpc put = new PutDataPointRpc();
821     put.execute(tsdb, query);
822     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
823     final String response =
824       query.response().getContent().toString(Charset.forName("UTF-8"));
825     assertTrue(response.contains("\"error\":\"Empty value\""));
826     assertTrue(response.contains("\"failed\":1"));
827     assertTrue(response.contains("\"success\":0"));
828     assertEquals(1, requests.get());
829     assertEquals(1, invalid_values.get());
830     assertEquals(0, illegal_arguments.get());
831     verify(tsdb, never()).getStorageExceptionHandler();
832   }
833 
834   @Test
nullValue()835   public void nullValue() throws Exception {
836     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
837         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
838         +":null,\"tags\":{\"host\":\"web01\"}}");
839     PutDataPointRpc put = new PutDataPointRpc();
840     put.execute(tsdb, query);
841     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
842     final String response =
843       query.response().getContent().toString(Charset.forName("UTF-8"));
844     assertTrue(response.contains("\"error\":\"Empty value\""));
845     assertTrue(response.contains("\"failed\":1"));
846     assertTrue(response.contains("\"success\":0"));
847     assertEquals(1, requests.get());
848     assertEquals(1, invalid_values.get());
849     assertEquals(0, illegal_arguments.get());
850     verify(tsdb, never()).getStorageExceptionHandler();
851   }
852 
853   @Test
emptyValue()854   public void emptyValue() throws Exception {
855     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
856         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
857         +":\"\",\"tags\":{\"host\":\"web01\"}}");
858     PutDataPointRpc put = new PutDataPointRpc();
859     put.execute(tsdb, query);
860     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
861     final String response =
862       query.response().getContent().toString(Charset.forName("UTF-8"));
863     assertTrue(response.contains("\"error\":\"Empty value\""));
864     assertTrue(response.contains("\"failed\":1"));
865     assertTrue(response.contains("\"success\":0"));
866     assertEquals(1, requests.get());
867     assertEquals(1, invalid_values.get());
868     assertEquals(0, illegal_arguments.get());
869     verify(tsdb, never()).getStorageExceptionHandler();
870   }
871 
872   @Test
badValue()873   public void badValue() throws Exception {
874     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
875         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
876         +":\"notanumber\",\"tags\":{\"host\":\"web01\"}}");
877     PutDataPointRpc put = new PutDataPointRpc();
878     put.execute(tsdb, query);
879     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
880     final String response =
881       query.response().getContent().toString(Charset.forName("UTF-8"));
882     assertTrue(response.contains("\"error\":\"Unable to parse value to a number\""));
883     assertTrue(response.contains("\"failed\":1"));
884     assertTrue(response.contains("\"success\":0"));
885     assertEquals(1, requests.get());
886     assertEquals(1, invalid_values.get());
887     assertEquals(0, illegal_arguments.get());
888     verify(tsdb, never()).getStorageExceptionHandler();
889   }
890 
891   @Test
ValueNaN()892   public void ValueNaN() throws Exception {
893     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
894         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
895         +":NaN,\"tags\":{\"host\":\"web01\"}}");
896     PutDataPointRpc put = new PutDataPointRpc();
897     put.execute(tsdb, query);
898     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
899     final String response =
900       query.response().getContent().toString(Charset.forName("UTF-8"));
901     assertTrue(response.contains("\"error\":\"Unable to parse value to a number\""));
902     assertTrue(response.contains("\"failed\":1"));
903     assertTrue(response.contains("\"success\":0"));
904     assertEquals(1, requests.get());
905     assertEquals(1, invalid_values.get());
906     assertEquals(0, illegal_arguments.get());
907     verify(tsdb, never()).getStorageExceptionHandler();
908   }
909 
910   @Test
ValueNaNCase()911   public void ValueNaNCase() throws Exception {
912     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
913         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
914         +":Nan,\"tags\":{\"host\":\"web01\"}}");
915     PutDataPointRpc put = new PutDataPointRpc();
916     BadRequestException ex = null;
917     try {
918       put.execute(tsdb, query);
919     } catch (BadRequestException e) {
920       ex = e;
921     }
922     assertNotNull(ex);
923     assertEquals(1, requests.get());
924     assertEquals(0, invalid_values.get());
925     assertEquals(0, illegal_arguments.get());
926     verify(tsdb, never()).getStorageExceptionHandler();
927   }
928 
929   @Test
ValueINF()930   public void ValueINF() throws Exception {
931     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
932         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
933         +":+INF,\"tags\":{\"host\":\"web01\"}}");
934     PutDataPointRpc put = new PutDataPointRpc();
935     put.execute(tsdb, query);
936     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
937     final String response =
938       query.response().getContent().toString(Charset.forName("UTF-8"));
939     assertTrue(response.contains("\"error\":\"Unable to parse value to a number\""));
940     assertTrue(response.contains("\"failed\":1"));
941     assertTrue(response.contains("\"success\":0"));
942     assertEquals(1, requests.get());
943     assertEquals(1, invalid_values.get());
944     assertEquals(0, illegal_arguments.get());
945     verify(tsdb, never()).getStorageExceptionHandler();
946   }
947 
948   @Test
ValueNINF()949   public void ValueNINF() throws Exception {
950     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
951         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
952         +":-INF,\"tags\":{\"host\":\"web01\"}}");
953     PutDataPointRpc put = new PutDataPointRpc();
954     put.execute(tsdb, query);
955     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
956     final String response =
957       query.response().getContent().toString(Charset.forName("UTF-8"));
958     assertTrue(response.contains("\"error\":\"Unable to parse value to a number\""));
959     assertTrue(response.contains("\"failed\":1"));
960     assertTrue(response.contains("\"success\":0"));
961     assertEquals(1, requests.get());
962     assertEquals(1, invalid_values.get());
963     assertEquals(0, illegal_arguments.get());
964     verify(tsdb, never()).getStorageExceptionHandler();
965   }
966 
967   @Test
ValueINFUnsigned()968   public void ValueINFUnsigned() throws Exception {
969     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
970         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
971         +":INF,\"tags\":{\"host\":\"web01\"}}");
972     PutDataPointRpc put = new PutDataPointRpc();
973     BadRequestException ex = null;
974     try {
975       put.execute(tsdb, query);
976     } catch (BadRequestException e) {
977       ex = e;
978     }
979     assertNotNull(ex);
980     assertEquals(1, requests.get());
981     assertEquals(0, invalid_values.get());
982     assertEquals(0, illegal_arguments.get());
983     verify(tsdb, never()).getStorageExceptionHandler();
984   }
985 
986   @Test
ValueINFCase()987   public void ValueINFCase() throws Exception {
988     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
989         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
990         +":+inf,\"tags\":{\"host\":\"web01\"}}");
991     PutDataPointRpc put = new PutDataPointRpc();
992     BadRequestException ex = null;
993     try {
994       put.execute(tsdb, query);
995     } catch (BadRequestException e) {
996       ex = e;
997     }
998     assertNotNull(ex);
999     assertEquals(1, requests.get());
1000     assertEquals(0, invalid_values.get());
1001     assertEquals(0, illegal_arguments.get());
1002     verify(tsdb, never()).getStorageExceptionHandler();
1003   }
1004 
1005   @Test
ValueInfiniy()1006   public void ValueInfiniy() throws Exception {
1007     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
1008         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1009         +":+Infinity,\"tags\":{\"host\":\"web01\"}}");
1010     PutDataPointRpc put = new PutDataPointRpc();
1011     put.execute(tsdb, query);
1012     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1013     final String response =
1014       query.response().getContent().toString(Charset.forName("UTF-8"));
1015     assertTrue(response.contains("\"error\":\"Unable to parse value to a number\""));
1016     assertTrue(response.contains("\"failed\":1"));
1017     assertTrue(response.contains("\"success\":0"));
1018     assertEquals(1, requests.get());
1019     assertEquals(1, invalid_values.get());
1020     assertEquals(0, illegal_arguments.get());
1021     verify(tsdb, never()).getStorageExceptionHandler();
1022   }
1023 
1024   @Test
ValueNInfiniy()1025   public void ValueNInfiniy() throws Exception {
1026     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
1027         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1028         +":-Infinity,\"tags\":{\"host\":\"web01\"}}");
1029     PutDataPointRpc put = new PutDataPointRpc();
1030     put.execute(tsdb, query);
1031     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1032     final String response =
1033       query.response().getContent().toString(Charset.forName("UTF-8"));
1034     assertTrue(response.contains("\"error\":\"Unable to parse value to a number\""));
1035     assertTrue(response.contains("\"failed\":1"));
1036     assertTrue(response.contains("\"success\":0"));
1037     assertEquals(1, requests.get());
1038     assertEquals(1, invalid_values.get());
1039     assertEquals(0, illegal_arguments.get());
1040     verify(tsdb, never()).getStorageExceptionHandler();
1041   }
1042 
1043   @Test
ValueInfinityUnsigned()1044   public void ValueInfinityUnsigned() throws Exception {
1045     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
1046         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1047         +":Infinity,\"tags\":{\"host\":\"web01\"}}");
1048     PutDataPointRpc put = new PutDataPointRpc();
1049     put.execute(tsdb, query);
1050     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1051     final String response =
1052       query.response().getContent().toString(Charset.forName("UTF-8"));
1053     assertTrue(response.contains("\"error\":\"Unable to parse value to a number\""));
1054     assertTrue(response.contains("\"failed\":1"));
1055     assertTrue(response.contains("\"success\":0"));
1056     assertEquals(1, requests.get());
1057     assertEquals(1, invalid_values.get());
1058     assertEquals(0, illegal_arguments.get());
1059     verify(tsdb, never()).getStorageExceptionHandler();
1060   }
1061 
1062   @Test
missingTags()1063   public void missingTags() throws Exception {
1064     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
1065         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\":42"
1066         + "}");
1067     PutDataPointRpc put = new PutDataPointRpc();
1068     put.execute(tsdb, query);
1069     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1070     final String response =
1071       query.response().getContent().toString(Charset.forName("UTF-8"));
1072     assertTrue(response.contains("\"error\":\"Missing tags\""));
1073     assertTrue(response.contains("\"failed\":1"));
1074     assertTrue(response.contains("\"success\":0"));
1075     assertEquals(1, requests.get());
1076     assertEquals(0, invalid_values.get());
1077     assertEquals(1, illegal_arguments.get());
1078     verify(tsdb, never()).getStorageExceptionHandler();
1079   }
1080 
1081   @Test
nullTags()1082   public void nullTags() throws Exception {
1083     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
1084         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1085         +":42,\"tags\":null}");
1086     PutDataPointRpc put = new PutDataPointRpc();
1087     put.execute(tsdb, query);
1088     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1089     final String response =
1090       query.response().getContent().toString(Charset.forName("UTF-8"));
1091     assertTrue(response.contains("\"error\":\"Missing tags\""));
1092     assertTrue(response.contains("\"failed\":1"));
1093     assertTrue(response.contains("\"success\":0"));
1094     assertEquals(1, requests.get());
1095     assertEquals(0, invalid_values.get());
1096     assertEquals(1, illegal_arguments.get());
1097     verify(tsdb, never()).getStorageExceptionHandler();
1098   }
1099 
1100   @Test
emptyTags()1101   public void emptyTags() throws Exception {
1102     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?details",
1103         "{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1104         +":42,\"tags\":{}}");
1105     PutDataPointRpc put = new PutDataPointRpc();
1106     put.execute(tsdb, query);
1107     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1108     final String response =
1109       query.response().getContent().toString(Charset.forName("UTF-8"));
1110     assertTrue(response.contains("\"error\":\"Missing tags\""));
1111     assertTrue(response.contains("\"failed\":1"));
1112     assertTrue(response.contains("\"success\":0"));
1113     assertEquals(1, requests.get());
1114     assertEquals(0, invalid_values.get());
1115     assertEquals(1, illegal_arguments.get());
1116     verify(tsdb, never()).getStorageExceptionHandler();
1117   }
1118 
1119   @Test
syncOKNoDetails()1120   public void syncOKNoDetails() throws Exception {
1121     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync=true",
1122         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1123         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1124         + "\"timestamp\":1365465600,\"value\":24,\"tags\":"
1125         + "{\"host\":\"web01\"}}]");
1126     PutDataPointRpc put = new PutDataPointRpc();
1127     put.execute(tsdb, query);
1128     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
1129     assertEquals(1, requests.get());
1130     assertEquals(0, invalid_values.get());
1131     verify(tsdb, never()).getStorageExceptionHandler();
1132     verify(tsdb, never()).getTimer();
1133   }
1134 
1135   @Test
syncOKSummary()1136   public void syncOKSummary() throws Exception {
1137     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync=true&summary",
1138         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1139         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1140         + "\"timestamp\":1365465600,\"value\":24,\"tags\":"
1141         + "{\"host\":\"web01\"}}]");
1142     PutDataPointRpc put = new PutDataPointRpc();
1143     put.execute(tsdb, query);
1144     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
1145     final String response =
1146       query.response().getContent().toString(Charset.forName("UTF-8"));
1147     assertTrue(response.contains("\"failed\":0"));
1148     assertTrue(response.contains("\"success\":2"));
1149     assertFalse(response.contains("\"errors\":[]"));
1150     assertEquals(1, requests.get());
1151     assertEquals(0, invalid_values.get());
1152     verify(tsdb, never()).getStorageExceptionHandler();
1153     verify(tsdb, never()).getTimer();
1154   }
1155 
1156   @Test
syncOKSummaryDetails()1157   public void syncOKSummaryDetails() throws Exception {
1158     HttpQuery query = NettyMocks.postQuery(tsdb,
1159         "/api/put?sync=true&summary&details",
1160         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1161         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1162         + "\"timestamp\":1365465600,\"value\":24,\"tags\":"
1163         + "{\"host\":\"web01\"}}]");
1164     PutDataPointRpc put = new PutDataPointRpc();
1165     put.execute(tsdb, query);
1166     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
1167     final String response =
1168       query.response().getContent().toString(Charset.forName("UTF-8"));
1169 
1170     assertTrue(response.contains("\"failed\":0"));
1171     assertTrue(response.contains("\"success\":2"));
1172     assertTrue(response.contains("\"errors\":[]"));
1173     assertEquals(1, requests.get());
1174     assertEquals(0, invalid_values.get());
1175     verify(tsdb, never()).getStorageExceptionHandler();
1176     verify(tsdb, never()).getTimer();
1177   }
1178 
1179   @Test
syncOKDetails()1180   public void syncOKDetails() throws Exception {
1181     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync=true&details",
1182         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1183         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1184         + "\"timestamp\":1365465600,\"value\":24,\"tags\":"
1185         + "{\"host\":\"web01\"}}]");
1186     PutDataPointRpc put = new PutDataPointRpc();
1187     put.execute(tsdb, query);
1188     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
1189     final String response =
1190       query.response().getContent().toString(Charset.forName("UTF-8"));
1191     assertTrue(response.contains("\"failed\":0"));
1192     assertTrue(response.contains("\"success\":2"));
1193     assertTrue(response.contains("\"errors\":[]"));
1194     assertEquals(1, requests.get());
1195     assertEquals(0, invalid_values.get());
1196     verify(tsdb, never()).getStorageExceptionHandler();
1197     verify(tsdb, never()).getTimer();
1198   }
1199 
1200   @Test
syncOneFailed()1201   public void syncOneFailed() throws Exception {
1202     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync",
1203         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1204         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1205         + "\"timestamp\":1365465600,\"value\":1,\"tags\":"
1206         + "{\"host\":\"web01\"}}]");
1207     PutDataPointRpc put = new PutDataPointRpc();
1208     put.execute(tsdb, query);
1209     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1210     final String response =
1211         query.response().getContent().toString(Charset.forName("UTF-8"));
1212     assertTrue(response.contains("\"code\":400"));
1213     assertTrue(response.contains("\"message\":"));
1214     assertEquals(1, requests.get());
1215     assertEquals(0, invalid_values.get());
1216     verify(tsdb, times(1)).getStorageExceptionHandler();
1217     verify(tsdb, never()).getTimer();
1218   }
1219 
1220   @Test
syncOneFailedSummary()1221   public void syncOneFailedSummary() throws Exception {
1222     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync&summary",
1223         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1224         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1225         + "\"timestamp\":1365465600,\"value\":1,\"tags\":"
1226         + "{\"host\":\"web01\"}}]");
1227     PutDataPointRpc put = new PutDataPointRpc();
1228     put.execute(tsdb, query);
1229     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
1230     final String response =
1231         query.response().getContent().toString(Charset.forName("UTF-8"));
1232     assertTrue(response.contains("\"failed\":1"));
1233     assertTrue(response.contains("\"success\":1"));
1234     assertFalse(response.contains("\"errors\":[]"));
1235     assertEquals(1, requests.get());
1236     assertEquals(0, invalid_values.get());
1237     verify(tsdb, times(1)).getStorageExceptionHandler();
1238     verify(tsdb, never()).getTimer();
1239   }
1240 
1241   @Test
syncOneFailedDetails()1242   public void syncOneFailedDetails() throws Exception {
1243     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync&details",
1244         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1245         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1246         + "\"timestamp\":1365465600,\"value\":1,\"tags\":"
1247         + "{\"host\":\"web01\"}}]");
1248     PutDataPointRpc put = new PutDataPointRpc();
1249     put.execute(tsdb, query);
1250     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
1251     final String response =
1252         query.response().getContent().toString(Charset.forName("UTF-8"));
1253     assertTrue(response.contains("\"failed\":1"));
1254     assertTrue(response.contains("\"success\":1"));
1255     assertTrue(response.contains("\"errors\":[{"));
1256     assertTrue(response.contains("Wotcher!"));
1257     assertEquals(1, requests.get());
1258     assertEquals(0, invalid_values.get());
1259     verify(tsdb, times(1)).getStorageExceptionHandler();
1260     verify(tsdb, never()).getTimer();
1261   }
1262 
1263   @Test
syncTwoFailedDetails()1264   public void syncTwoFailedDetails() throws Exception {
1265     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync&details",
1266         "[{\"metric\":\"doesnotexist\",\"timestamp\":1365465600,\"value\""
1267         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1268         + "\"timestamp\":1365465600,\"value\":1,\"tags\":"
1269         + "{\"host\":\"web01\"}}]");
1270     PutDataPointRpc put = new PutDataPointRpc();
1271     put.execute(tsdb, query);
1272     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1273     final String response =
1274         query.response().getContent().toString(Charset.forName("UTF-8"));
1275     System.out.println(response);
1276     assertTrue(response.contains("\"success\":0"));
1277     assertTrue(response.contains("\"failed\":2"));
1278     assertTrue(response.contains("\"errors\":[{"));
1279     assertTrue(response.contains("Wotcher!"));
1280     assertTrue(response.contains("Unknown metric"));
1281     assertEquals(1, requests.get());
1282     assertEquals(0, invalid_values.get());
1283     verify(tsdb, times(1)).getStorageExceptionHandler();
1284     verify(tsdb, never()).getTimer();
1285   }
1286 
1287   @Test
syncOKTimeoutNoDetails()1288   public void syncOKTimeoutNoDetails() throws Exception {
1289     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync&sync_timeout=30000",
1290         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1291         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1292         + "\"timestamp\":1365465600,\"value\":24,\"tags\":"
1293         + "{\"host\":\"web01\"}}]");
1294     PutDataPointRpc put = new PutDataPointRpc();
1295     put.execute(tsdb, query);
1296     assertEquals(HttpResponseStatus.NO_CONTENT, query.response().getStatus());
1297     assertEquals(1, requests.get());
1298     assertEquals(0, invalid_values.get());
1299     verify(tsdb, never()).getStorageExceptionHandler();
1300     verify(tsdb, times(1)).getTimer();
1301     verify(timer.timeout, times(1)).cancel();
1302   }
1303 
1304   @Test
syncOKTimeoutSummary()1305   public void syncOKTimeoutSummary() throws Exception {
1306     HttpQuery query = NettyMocks.postQuery(tsdb,
1307         "/api/put?sync&sync_timeout=30000&summary",
1308         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1309         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1310         + "\"timestamp\":1365465600,\"value\":24,\"tags\":"
1311         + "{\"host\":\"web01\"}}]");
1312     PutDataPointRpc put = new PutDataPointRpc();
1313     put.execute(tsdb, query);
1314     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
1315     final String response =
1316       query.response().getContent().toString(Charset.forName("UTF-8"));
1317     assertTrue(response.contains("\"failed\":0"));
1318     assertTrue(response.contains("\"success\":2"));
1319     assertTrue(response.contains("\"timeouts\":0"));
1320     assertFalse(response.contains("\"errors\":[]"));
1321     assertEquals(1, requests.get());
1322     assertEquals(0, invalid_values.get());
1323     verify(tsdb, never()).getStorageExceptionHandler();
1324     verify(tsdb, times(1)).getTimer();
1325     verify(timer.timeout, times(1)).cancel();
1326   }
1327 
1328   @Test
syncTimeoutOneFailed()1329   public void syncTimeoutOneFailed() throws Exception {
1330     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync&sync_timeout=30000",
1331         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1332         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1333         + "\"timestamp\":1365465600,\"value\":1,\"tags\":"
1334         + "{\"host\":\"web01\"}}]");
1335     PutDataPointRpc put = new PutDataPointRpc();
1336     put.execute(tsdb, query);
1337     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1338     final String response =
1339         query.response().getContent().toString(Charset.forName("UTF-8"));
1340     assertTrue(response.contains("\"code\":400"));
1341     assertTrue(response.contains("\"message\":"));
1342     assertEquals(1, requests.get());
1343     assertEquals(0, invalid_values.get());
1344     verify(tsdb, times(1)).getStorageExceptionHandler();
1345     verify(tsdb, times(1)).getTimer();
1346     verify(timer.timeout, times(1)).cancel();
1347   }
1348 
1349   @Test
syncTimeoutOneFailedSummary()1350   public void syncTimeoutOneFailedSummary() throws Exception {
1351     HttpQuery query = NettyMocks.postQuery(tsdb, "/api/put?sync&summary&sync_timeout=30000",
1352         "[{\"metric\":\"sys.cpu.nice\",\"timestamp\":1365465600,\"value\""
1353         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1354         + "\"timestamp\":1365465600,\"value\":1,\"tags\":"
1355         + "{\"host\":\"web01\"}}]");
1356     PutDataPointRpc put = new PutDataPointRpc();
1357     put.execute(tsdb, query);
1358     assertEquals(HttpResponseStatus.OK, query.response().getStatus());
1359     final String response =
1360         query.response().getContent().toString(Charset.forName("UTF-8"));
1361     assertTrue(response.contains("\"failed\":1"));
1362     assertTrue(response.contains("\"success\":1"));
1363     assertTrue(response.contains("\"timeouts\":0"));
1364     assertFalse(response.contains("\"errors\":[]"));
1365     assertEquals(1, requests.get());
1366     assertEquals(0, invalid_values.get());
1367     verify(tsdb, times(1)).getStorageExceptionHandler();
1368     verify(tsdb, times(1)).getTimer();
1369     verify(timer.timeout, times(1)).cancel();
1370   }
1371 
1372   @Test
syncTimeoutTwoFailedDetails()1373   public void syncTimeoutTwoFailedDetails() throws Exception {
1374     HttpQuery query = NettyMocks.postQuery(tsdb,
1375         "/api/put?sync&details&sync_timeout=30000",
1376         "[{\"metric\":\"doesnotexist\",\"timestamp\":1365465600,\"value\""
1377         + ":42,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1378         + "\"timestamp\":1365465600,\"value\":1,\"tags\":"
1379         + "{\"host\":\"web01\"}}]");
1380     PutDataPointRpc put = new PutDataPointRpc();
1381     put.execute(tsdb, query);
1382     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1383     final String response =
1384         query.response().getContent().toString(Charset.forName("UTF-8"));
1385     System.out.println(response);
1386     assertTrue(response.contains("\"success\":0"));
1387     assertTrue(response.contains("\"failed\":2"));
1388     assertTrue(response.contains("\"timeouts\":0"));
1389     assertTrue(response.contains("\"errors\":[{"));
1390     assertTrue(response.contains("Wotcher!"));
1391     assertTrue(response.contains("Unknown metric"));
1392     assertEquals(1, requests.get());
1393     assertEquals(0, invalid_values.get());
1394     verify(tsdb, times(1)).getStorageExceptionHandler();
1395     verify(tsdb, times(1)).getTimer();
1396     verify(timer.timeout, times(1)).cancel();
1397   }
1398 
1399   @Test
syncTimeoutOneFailedTimedoutSummary()1400   public void syncTimeoutOneFailedTimedoutSummary() throws Exception {
1401     HttpQuery query = NettyMocks.postQuery(tsdb,
1402         "/api/put?sync&summary&sync_timeout=30000",
1403         "[{\"metric\":\"sys.cpu.system\",\"timestamp\":1365465600,\"value\""
1404         + ":2,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1405         + "\"timestamp\":1365465600,\"value\":1,\"tags\":"
1406         + "{\"host\":\"web01\"}}]");
1407     PutDataPointRpc put = new PutDataPointRpc();
1408     put.execute(tsdb, query);
1409     verify(tsdb, times(1)).getTimer();
1410     verify(timer.timeout, never()).cancel();
1411 
1412     timer.continuePausedTask();
1413 
1414     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1415     final String response =
1416         query.response().getContent().toString(Charset.forName("UTF-8"));
1417     assertTrue(response.contains("\"failed\":1"));
1418     assertTrue(response.contains("\"success\":0"));
1419     assertTrue(response.contains("\"timeouts\":1"));
1420     assertFalse(response.contains("\"errors\":[]"));
1421     assertEquals(1, requests.get());
1422     assertEquals(0, invalid_values.get());
1423     verify(tsdb, times(1)).getStorageExceptionHandler();
1424     verify(timer.timeout, never()).cancel();
1425   }
1426 
1427   @Test
syncTimeoutOneFailedTimedoutDetails()1428   public void syncTimeoutOneFailedTimedoutDetails() throws Exception {
1429     HttpQuery query = NettyMocks.postQuery(tsdb,
1430         "/api/put?sync&details&sync_timeout=30000",
1431         "[{\"metric\":\"sys.cpu.system\",\"timestamp\":1365465600,\"value\""
1432         + ":2,\"tags\":{\"host\":\"web01\"}},{\"metric\":\"sys.cpu.system\","
1433         + "\"timestamp\":1365465600,\"value\":1,\"tags\":"
1434         + "{\"host\":\"web01\"}}]");
1435     PutDataPointRpc put = new PutDataPointRpc();
1436     put.execute(tsdb, query);
1437     verify(tsdb, times(1)).getTimer();
1438     verify(timer.timeout, never()).cancel();
1439 
1440     timer.continuePausedTask();
1441 
1442     assertEquals(HttpResponseStatus.BAD_REQUEST, query.response().getStatus());
1443     final String response =
1444         query.response().getContent().toString(Charset.forName("UTF-8"));
1445     System.out.println(response);
1446     assertTrue(response.contains("\"failed\":1"));
1447     assertTrue(response.contains("\"success\":0"));
1448     assertTrue(response.contains("\"timeouts\":1"));
1449     assertTrue(response.contains("\"errors\":[{"));
1450     assertTrue(response.contains("Write timedout"));
1451     assertTrue(response.contains("Wotcher!"));
1452     assertEquals(1, requests.get());
1453     assertEquals(0, invalid_values.get());
1454     verify(tsdb, times(1)).getStorageExceptionHandler();
1455     verify(timer.timeout, never()).cancel();
1456   }
1457 }
1458