1 // This file is part of OpenTSDB.
2 // Copyright (C) 2010-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.meta;
14 
15 import static org.junit.Assert.assertEquals;
16 import static org.junit.Assert.assertNotNull;
17 import static org.junit.Assert.assertNull;
18 import static org.junit.Assert.assertTrue;
19 
20 import java.util.List;
21 import java.util.Map;
22 
23 import net.opentsdb.core.BaseTsdbTest;
24 import net.opentsdb.core.Const;
25 import net.opentsdb.core.RowKey;
26 import net.opentsdb.core.TSDB;
27 import net.opentsdb.storage.MockBase;
28 import net.opentsdb.utils.JSON;
29 
30 import org.hbase.async.Bytes;
31 import org.hbase.async.Scanner;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
34 import org.powermock.api.mockito.PowerMockito;
35 import org.powermock.core.classloader.annotations.PowerMockIgnore;
36 import org.powermock.core.classloader.annotations.PrepareForTest;
37 import org.powermock.modules.junit4.PowerMockRunner;
38 
39 import com.google.common.collect.Maps;
40 
41 @PowerMockIgnore({"javax.management.*", "javax.xml.*",
42   "ch.qos.*", "org.slf4j.*",
43   "com.sum.*", "org.xml.*"})
44 @RunWith(PowerMockRunner.class)
45 @PrepareForTest({ Annotation.class, Const.class, Scanner.class })
46 public final class TestAnnotation extends BaseTsdbTest {
47   private Annotation note = new Annotation();
48   private final static String TSUID = "000001000001000001";
49   private byte[] global_row_key;
50   private byte[] tsuid_row_key;
51   // 1425715200 - Sat Mar 7 00:00:00 PST 2015
52   private byte[] global_row_key_2015_midnight;
53 
54   @Test
constructor()55   public void constructor() {
56     assertNotNull(new Annotation());
57   }
58 
59   @Test
serialize()60   public void serialize() throws Exception {
61     assertNotNull(JSON.serializeToString(note));
62   }
63 
64   @Test
deserialize()65   public void deserialize() throws Exception {
66     String json = "{\"tsuid\":\"ABCD\",\"description\":\"Description\"," +
67     "\"notes\":\"Notes\",\"custom\":null,\"endTime\":1328140801,\"startTime" +
68     "\":1328140800}";
69     Annotation note = JSON.parseToObject(json, Annotation.class);
70     assertNotNull(note);
71     assertEquals(note.getTSUID(), "ABCD");
72   }
73 
74   @Test
getAnnotation()75   public void getAnnotation() throws Exception {
76     setupStorage(false);
77 
78     note = Annotation.getAnnotation(tsdb, TSUID, 1388450562L)
79       .joinUninterruptibly();
80     assertNotNull(note);
81     assertEquals(TSUID, note.getTSUID());
82     assertEquals("Hello!", note.getDescription());
83     assertEquals(1388450562L, note.getStartTime());
84   }
85 
86   @Test
getAnnotationSalted()87   public void getAnnotationSalted() throws Exception {
88     setupStorage(true);
89     note = Annotation.getAnnotation(tsdb, TSUID, 1388450562L)
90       .joinUninterruptibly();
91     assertNotNull(note);
92     assertEquals(TSUID, note.getTSUID());
93     assertEquals("Hello!", note.getDescription());
94     assertEquals(1388450562L, note.getStartTime());
95   }
96 
97   @Test
getAnnotationNormalizeMs()98   public void getAnnotationNormalizeMs() throws Exception {
99     setupStorage(false);
100     note = Annotation.getAnnotation(tsdb, TSUID, 1388450562000L)
101       .joinUninterruptibly();
102     assertNotNull(note);
103     assertEquals(TSUID, note.getTSUID());
104     assertEquals("Hello!", note.getDescription());
105     assertEquals(1388450562L, note.getStartTime());
106   }
107 
108   @Test
getAnnotationGlobal()109   public void getAnnotationGlobal() throws Exception {
110     setupStorage(false);
111     note = Annotation.getAnnotation(tsdb, 1328140800000L)
112       .joinUninterruptibly();
113     assertNotNull(note);
114     assertEquals("", note.getTSUID());
115     assertEquals("Description", note.getDescription());
116     assertEquals(1328140800L, note.getStartTime());
117   }
118 
119   @Test
getAnnotationGlobalSalted()120   public void getAnnotationGlobalSalted() throws Exception {
121     setupStorage(true);
122     note = Annotation.getAnnotation(tsdb, 1328140800000L)
123       .joinUninterruptibly();
124     assertNotNull(note);
125     assertEquals("", note.getTSUID());
126     assertEquals("Description", note.getDescription());
127     assertEquals(1328140800L, note.getStartTime());
128   }
129 
130   @Test
getAnnotationNotFound()131   public void getAnnotationNotFound() throws Exception {
132     setupStorage(false);
133     note = Annotation.getAnnotation(tsdb, TSUID, 1388450564L)
134       .joinUninterruptibly();
135     assertNull(note);
136   }
137 
138   @Test
getAnnotationGlobalNotFound()139   public void getAnnotationGlobalNotFound() throws Exception {
140     setupStorage(false);
141     note = Annotation.getAnnotation(tsdb, 1388450563L)
142       .joinUninterruptibly();
143     assertNull(note);
144   }
145 
146   @Test (expected = IllegalArgumentException.class)
getAnnotationNoStartTime()147   public void getAnnotationNoStartTime() throws Exception {
148     Annotation.getAnnotation(tsdb, TSUID, 0L)
149       .joinUninterruptibly();
150   }
151 
152   @Test
getGlobalAnnotations()153   public void getGlobalAnnotations() throws Exception {
154     setupStorage(false);
155     List<Annotation> notes = Annotation.getGlobalAnnotations(tsdb, 1328140000,
156         1328141000).joinUninterruptibly();
157     assertNotNull(notes);
158     assertEquals(2, notes.size());
159     Annotation note0 = notes.get(0);
160     Annotation note1 = notes.get(1);
161     assertEquals("Description", note0.getDescription());
162     assertEquals("Global 2", note1.getDescription());
163   }
164 
165   @Test
getGlobalAnnotationsSalted()166   public void getGlobalAnnotationsSalted() throws Exception {
167     setupStorage(true);
168     List<Annotation> notes = Annotation.getGlobalAnnotations(tsdb, 1328140000,
169         1328141000).joinUninterruptibly();
170     assertNotNull(notes);
171     assertEquals(2, notes.size());
172     Annotation note0 = notes.get(0);
173     Annotation note1 = notes.get(1);
174     assertEquals("Description", note0.getDescription());
175     assertEquals("Global 2", note1.getDescription());
176   }
177 
178   @Test
getGlobalAnnotationOutsideCurrentHour()179   public void getGlobalAnnotationOutsideCurrentHour() throws Exception {
180     setupStorage(false);
181     // 1425716000 - Sat Mar  7 00:13:20 PST 2015
182     storage.addColumn(global_row_key_2015_midnight,
183         new byte[] { 1, 3, (byte) 0x20 },
184         ("{\"startTime\":1425716000,\"endTime\":1425716001,\"description\":" +
185             "\"Global 3\",\"notes\":\"Issue #457\"}").getBytes(MockBase.ASCII()));
186 
187     int right_now = 1425717000;  // Sat Mar  7 00:30:00 PST 2015
188     int fourty_minutes_ago = 1425714600; // Fri Mar  6 23:50:00 PST 2015
189 
190     List<Annotation> recentGlobalAnnotation = Annotation.getGlobalAnnotations(
191         tsdb, fourty_minutes_ago, right_now).joinUninterruptibly();
192     assertNotNull(recentGlobalAnnotation);
193     assertEquals(1, recentGlobalAnnotation.size());
194     Annotation note0 = recentGlobalAnnotation.get(0);
195     assertEquals("Global 3", note0.getDescription());
196     assertEquals("Issue #457", note0.getNotes());
197   }
198 
199   @Test
getGlobalAnnotationOutsideCurrentHourSalt()200   public void getGlobalAnnotationOutsideCurrentHourSalt() throws Exception {
201     setupStorage(true);
202     // 1425716000 - Sat Mar  7 00:13:20 PST 2015
203     storage.addColumn(global_row_key_2015_midnight,
204         new byte[] { 1, 3, (byte) 0x20 },
205         ("{\"startTime\":1425716000,\"endTime\":1425716001,\"description\":" +
206             "\"Global 3\",\"notes\":\"Issue #457\"}").getBytes(MockBase.ASCII()));
207 
208     int right_now = 1425717000;  // Sat Mar  7 00:30:00 PST 2015
209     int fourty_minutes_ago = 1425714600; // Fri Mar  6 23:50:00 PST 2015
210 
211     List<Annotation> recentGlobalAnnotation = Annotation.getGlobalAnnotations(
212         tsdb, fourty_minutes_ago, right_now).joinUninterruptibly();
213     assertNotNull(recentGlobalAnnotation);
214     assertEquals(1, recentGlobalAnnotation.size());
215     Annotation note0 = recentGlobalAnnotation.get(0);
216     assertEquals("Global 3", note0.getDescription());
217     assertEquals("Issue #457", note0.getNotes());
218   }
219 
220   @Test
getGlobalAnnotationsEmpty()221   public void getGlobalAnnotationsEmpty() throws Exception {
222     setupStorage(false);
223     List<Annotation> notes = Annotation.getGlobalAnnotations(tsdb, 1328150000,
224         1328160000).joinUninterruptibly();
225     assertNotNull(notes);
226     assertEquals(0, notes.size());
227   }
228 
229   @Test (expected = IllegalArgumentException.class)
getGlobalAnnotationsZeroEndtime()230   public void getGlobalAnnotationsZeroEndtime() throws Exception {
231     Annotation.getGlobalAnnotations(tsdb, 0, 0).joinUninterruptibly();
232   }
233 
234   @Test (expected = IllegalArgumentException.class)
getGlobalAnnotationsEndLessThanStart()235   public void getGlobalAnnotationsEndLessThanStart() throws Exception {
236     Annotation.getGlobalAnnotations(tsdb, 1328150000, 1328140000).joinUninterruptibly();
237   }
238 
239   @Test
syncToStorage()240   public void syncToStorage() throws Exception {
241     setupStorage(false);
242     note.setTSUID(TSUID);
243     note.setStartTime(1388450562L);
244     note.setDescription("Synced!");
245     note.syncToStorage(tsdb, false).joinUninterruptibly();
246     final byte[] col = storage.getColumn(tsuid_row_key,
247         new byte[] { 1, 0x0A, 0x02 });
248     note = JSON.parseToObject(col, Annotation.class);
249     assertEquals(TSUID, note.getTSUID());
250     assertEquals("Synced!", note.getDescription());
251     assertEquals("My Notes", note.getNotes());
252   }
253 
254   @Test
syncToStorageSalted()255   public void syncToStorageSalted() throws Exception {
256     setupStorage(true);
257     note.setTSUID(TSUID);
258     note.setStartTime(1388450562L);
259     note.setDescription("Synced!");
260     note.syncToStorage(tsdb, false).joinUninterruptibly();
261     final byte[] col = storage.getColumn(tsuid_row_key,
262         new byte[] { 1, 0x0A, 0x02 });
263     note = JSON.parseToObject(col, Annotation.class);
264     assertEquals(TSUID, note.getTSUID());
265     assertEquals("Synced!", note.getDescription());
266     assertEquals("My Notes", note.getNotes());
267   }
268 
269   @Test
syncToStorageMilliseconds()270   public void syncToStorageMilliseconds() throws Exception {
271     setupStorage(false);
272     note.setTSUID(TSUID);
273     note.setStartTime(1388450562500L);
274     note.setDescription("Synced!");
275     note.syncToStorage(tsdb, false).joinUninterruptibly();
276     final byte[] col = storage.getColumn(tsuid_row_key,
277         new byte[] { 1, 0x00, 0x27, 0x19, (byte) 0xC4 });
278     note = JSON.parseToObject(col, Annotation.class);
279     assertEquals(TSUID, note.getTSUID());
280     assertEquals("Synced!", note.getDescription());
281     assertEquals("", note.getNotes());
282     assertEquals(1388450562500L, note.getStartTime());
283   }
284 
285   @Test
syncToStorageGlobal()286   public void syncToStorageGlobal() throws Exception {
287     setupStorage(false);
288     note.setStartTime(1328140800L);
289     note.setDescription("Synced!");
290     note.syncToStorage(tsdb, false).joinUninterruptibly();
291     final byte[] col = storage.getColumn(global_row_key,
292         new byte[] { 1, 0, 0 });
293     note = JSON.parseToObject(col, Annotation.class);
294     assertEquals("", note.getTSUID());
295     assertEquals("Synced!", note.getDescription());
296     assertEquals("Notes", note.getNotes());
297   }
298 
299   @Test
syncToStorageGlobalSalted()300   public void syncToStorageGlobalSalted() throws Exception {
301     setupStorage(true);
302     note.setStartTime(1328140800L);
303     note.setDescription("Synced!");
304     note.syncToStorage(tsdb, false).joinUninterruptibly();
305     final byte[] col = storage.getColumn(global_row_key,
306         new byte[] { 1, 0, 0 });
307     note = JSON.parseToObject(col, Annotation.class);
308     assertEquals("", note.getTSUID());
309     assertEquals("Synced!", note.getDescription());
310     assertEquals("Notes", note.getNotes());
311   }
312 
313   @Test
syncToStorageGlobalMilliseconds()314   public void syncToStorageGlobalMilliseconds() throws Exception {
315     setupStorage(false);
316     note.setStartTime(1328140800500L);
317     note.setDescription("Synced!");
318     note.syncToStorage(tsdb, false).joinUninterruptibly();
319     final byte[] col = storage.getColumn(global_row_key,
320         new byte[] { 1, 0, 0, 1, (byte) 0xF4 });
321     note = JSON.parseToObject(col, Annotation.class);
322     assertEquals("", note.getTSUID());
323     assertEquals("Synced!", note.getDescription());
324     assertEquals("", note.getNotes());
325   }
326 
327   @Test (expected = IllegalArgumentException.class)
syncToStorageMissingStart()328   public void syncToStorageMissingStart() throws Exception {
329     note.setTSUID(TSUID);
330     note.setDescription("Synced!");
331     note.syncToStorage(tsdb, false).joinUninterruptibly();
332   }
333 
334   @Test (expected = IllegalStateException.class)
syncToStorageNoChanges()335   public void syncToStorageNoChanges() throws Exception {
336     note.setTSUID(TSUID);
337     note.setStartTime(1388450562L);
338     note.syncToStorage(tsdb, false).joinUninterruptibly();
339   }
340 
341   @Test
getStorageJSONTags()342   public void getStorageJSONTags() throws Exception {
343     Map<String, String> custom = Maps.newHashMap();
344     custom.put("C", "C");
345     custom.put("P", "P");
346     custom.put("E", "E");
347     System.out.println(custom);
348 
349     note.setTSUID(TSUID);
350     note.setStartTime(1388450562L);
351     note.setCustom(custom);
352     final String json = new String(note.getStorageJSON());
353     assertTrue(json.contains("{\"C\":\"C\",\"E\":\"E\",\"P\":\"P\"}"));
354   }
355 
356   @Test
delete()357   public void delete() throws Exception {
358     setupStorage(false);
359     note.setTSUID(TSUID);
360     note.setStartTime(1388450562);
361     note.delete(tsdb).joinUninterruptibly();
362     assertNull(storage.getColumn(tsuid_row_key,
363         new byte[] { 1, 0x0A, 0x02 }));
364     assertNotNull(storage.getColumn(tsuid_row_key,
365         new byte[] { 1, 0x0A, 0x03 }));
366     assertNotNull(storage.getColumn(tsuid_row_key,
367         new byte[] { 0x50, 0x10 }));
368     assertNotNull(storage.getColumn(tsuid_row_key,
369         new byte[] { 0x50, 0x18 }));
370   }
371 
372   @Test
deleteSalted()373   public void deleteSalted() throws Exception {
374     setupStorage(true);
375     note.setTSUID(TSUID);
376     note.setStartTime(1388450562);
377     note.delete(tsdb).joinUninterruptibly();
378     assertNull(storage.getColumn(tsuid_row_key,
379         new byte[] { 1, 0x0A, 0x02 }));
380     assertNotNull(storage.getColumn(tsuid_row_key,
381         new byte[] { 1, 0x0A, 0x03 }));
382     assertNotNull(storage.getColumn(tsuid_row_key,
383         new byte[] { 0x50, 0x10 }));
384     assertNotNull(storage.getColumn(tsuid_row_key,
385         new byte[] { 0x50, 0x18 }));
386   }
387 
388   @Test
deleteNormalizeMs()389   public void deleteNormalizeMs() throws Exception {
390     setupStorage(false);
391     note.setTSUID(TSUID);
392     note.setStartTime(1388450562000L);
393     note.delete(tsdb).joinUninterruptibly();
394     assertNull(storage.getColumn(tsuid_row_key,
395         new byte[] { 1, 0x0A, 0x02 }));
396     assertNotNull(storage.getColumn(tsuid_row_key,
397         new byte[] { 1, 0x0A, 0x03 }));
398     assertNotNull(storage.getColumn(tsuid_row_key,
399         new byte[] { 0x50, 0x10 }));
400     assertNotNull(storage.getColumn(tsuid_row_key,
401         new byte[] { 0x50, 0x18 }));
402   }
403 
404   // this doesn't throw an error or anything, just issues the delete request
405   // and it's ignored.
406   @Test
deleteNotFound()407   public void deleteNotFound() throws Exception {
408     setupStorage(false);
409     note.setTSUID(TSUID);
410     note.setStartTime(1388450561);
411     note.delete(tsdb).joinUninterruptibly();
412     assertNotNull(storage.getColumn(tsuid_row_key,
413         new byte[] { 1, 0x0A, 0x02 }));
414     assertNotNull(storage.getColumn(tsuid_row_key,
415         new byte[] { 1, 0x0A, 0x03 }));
416     assertNotNull(storage.getColumn(tsuid_row_key,
417         new byte[] { 0x50, 0x10 }));
418     assertNotNull(storage.getColumn(tsuid_row_key,
419         new byte[] { 0x50, 0x18 }));
420   }
421 
422   @Test (expected = IllegalArgumentException.class)
deleteMissingStart()423   public void deleteMissingStart() throws Exception {
424     note.setTSUID(TSUID);
425     note.delete(tsdb).joinUninterruptibly();
426   }
427 
428   @Test
deleteGlobal()429   public void deleteGlobal() throws Exception {
430     setupStorage(false);
431     note.setStartTime(1328140800);
432     note.delete(tsdb).joinUninterruptibly();
433     assertNull(storage.getColumn(global_row_key,
434         new byte[] { 1, 0, 0 }));
435     assertNotNull(storage.getColumn(global_row_key,
436         new byte[] { 1, 0, 1 }));
437   }
438 
439   @Test
deleteGlobalSalted()440   public void deleteGlobalSalted() throws Exception {
441     setupStorage(true);
442     note.setStartTime(1328140800);
443     note.delete(tsdb).joinUninterruptibly();
444     assertNull(storage.getColumn(global_row_key,
445         new byte[] { 1, 0, 0 }));
446     assertNotNull(storage.getColumn(global_row_key,
447         new byte[] { 1, 0, 1 }));
448   }
449 
450   @Test
deleteGlobalNotFound()451   public void deleteGlobalNotFound() throws Exception {
452     setupStorage(false);
453     note.setStartTime(1328140803);
454     note.delete(tsdb).joinUninterruptibly();
455     assertNotNull(storage.getColumn(global_row_key,
456         new byte[] { 1, 0, 0 }));
457     assertNotNull(storage.getColumn(global_row_key,
458         new byte[] { 1, 0, 1 }));
459   }
460 
461   @Test
deleteRange()462   public void deleteRange() throws Exception {
463     setupStorage(false);
464     final int count = Annotation.deleteRange(tsdb,
465         new byte[] { 0, 0, 1, 0, 0, 1, 0, 0, 1}, 1388450560000L,
466         1388450562000L).joinUninterruptibly();
467     assertEquals(1, count);
468     assertNull(storage.getColumn(tsuid_row_key,
469         new byte[] { 1, 0x0A, 0x02 }));
470     assertNotNull(storage.getColumn(tsuid_row_key,
471         new byte[] { 1, 0x0A, 0x03 }));
472     assertNotNull(storage.getColumn(tsuid_row_key,
473         new byte[] { 0x50, 0x10 }));
474     assertNotNull(storage.getColumn(tsuid_row_key,
475         new byte[] { 0x50, 0x18 }));
476   }
477 
478   @Test
deleteRangeSalted()479   public void deleteRangeSalted() throws Exception {
480     setupStorage(true);
481     final int count = Annotation.deleteRange(tsdb,
482         new byte[] { 0, 0, 1, 0, 0, 1, 0, 0, 1}, 1388450560000L,
483         1388450562000L).joinUninterruptibly();
484     assertEquals(1, count);
485     assertNull(storage.getColumn(tsuid_row_key,
486         new byte[] { 1, 0x0A, 0x02 }));
487     assertNotNull(storage.getColumn(tsuid_row_key,
488         new byte[] { 1, 0x0A, 0x03 }));
489     assertNotNull(storage.getColumn(tsuid_row_key,
490         new byte[] { 0x50, 0x10 }));
491     assertNotNull(storage.getColumn(tsuid_row_key,
492         new byte[] { 0x50, 0x18 }));
493   }
494 
495   @Test
deleteRangeNone()496   public void deleteRangeNone() throws Exception {
497     setupStorage(false);
498     final int count = Annotation.deleteRange(tsdb,
499         new byte[] { 0, 0, 1, 0, 0, 1, 0, 0, 1}, 1388450560000L,
500         1388450561000L).joinUninterruptibly();
501     assertEquals(0, count);
502     assertNotNull(storage.getColumn(tsuid_row_key,
503         new byte[] { 1, 0x0A, 0x02 }));
504     assertNotNull(storage.getColumn(tsuid_row_key,
505         new byte[] { 1, 0x0A, 0x03 }));
506     assertNotNull(storage.getColumn(tsuid_row_key,
507         new byte[] { 0x50, 0x10 }));
508     assertNotNull(storage.getColumn(tsuid_row_key,
509         new byte[] { 0x50, 0x18 }));
510   }
511 
512   @Test
deleteRangeNoneSalted()513   public void deleteRangeNoneSalted() throws Exception {
514     setupStorage(true);
515     final int count = Annotation.deleteRange(tsdb,
516         new byte[] { 0, 0, 1, 0, 0, 1, 0, 0, 1}, 1388450560000L,
517         1388450561000L).joinUninterruptibly();
518     assertEquals(0, count);
519     assertNotNull(storage.getColumn(tsuid_row_key,
520         new byte[] { 1, 0x0A, 0x02 }));
521     assertNotNull(storage.getColumn(tsuid_row_key,
522         new byte[] { 1, 0x0A, 0x03 }));
523     assertNotNull(storage.getColumn(tsuid_row_key,
524         new byte[] { 0x50, 0x10 }));
525     assertNotNull(storage.getColumn(tsuid_row_key,
526         new byte[] { 0x50, 0x18 }));
527   }
528 
529   @Test
deleteRangeMultiple()530   public void deleteRangeMultiple() throws Exception {
531     setupStorage(false);
532     final int count = Annotation.deleteRange(tsdb,
533         new byte[] { 0, 0, 1, 0, 0, 1, 0, 0, 1}, 1388450560000L,
534         1388450568000L).joinUninterruptibly();
535     assertEquals(2, count);
536     assertNull(storage.getColumn(tsuid_row_key,
537         new byte[] { 1, 0x0A, 0x02 }));
538     assertNull(storage.getColumn(tsuid_row_key,
539         new byte[] { 1, 0x0A, 0x03 }));
540     assertNotNull(storage.getColumn(tsuid_row_key,
541         new byte[] { 0x50, 0x10 }));
542     assertNotNull(storage.getColumn(tsuid_row_key,
543         new byte[] { 0x50, 0x18 }));
544   }
545 
546   @Test
deleteRangeMultipleSalted()547   public void deleteRangeMultipleSalted() throws Exception {
548     setupStorage(true);
549     final int count = Annotation.deleteRange(tsdb,
550         new byte[] { 0, 0, 1, 0, 0, 1, 0, 0, 1}, 1388450560000L,
551         1388450568000L).joinUninterruptibly();
552     assertEquals(2, count);
553     assertNull(storage.getColumn(tsuid_row_key,
554         new byte[] { 1, 0x0A, 0x02 }));
555     assertNull(storage.getColumn(tsuid_row_key,
556         new byte[] { 1, 0x0A, 0x03 }));
557     assertNotNull(storage.getColumn(tsuid_row_key,
558         new byte[] { 0x50, 0x10 }));
559     assertNotNull(storage.getColumn(tsuid_row_key,
560         new byte[] { 0x50, 0x18 }));
561   }
562 
563   @Test
deleteRangeGlobal()564   public void deleteRangeGlobal() throws Exception {
565     setupStorage(false);
566     final int count = Annotation.deleteRange(tsdb, null, 1328140799000L,
567         1328140800000L).joinUninterruptibly();
568     assertEquals(1, count);
569     assertNull(storage.getColumn(global_row_key,
570         new byte[] { 1, 0, 0 }));
571     assertNotNull(storage.getColumn(global_row_key,
572         new byte[] { 1, 0, 1 }));
573   }
574 
575   @Test
deleteRangeGlobalSalted()576   public void deleteRangeGlobalSalted() throws Exception {
577     setupStorage(true);
578     final int count = Annotation.deleteRange(tsdb, null, 1328140799000L,
579         1328140800000L).joinUninterruptibly();
580     assertEquals(1, count);
581     assertNull(storage.getColumn(global_row_key,
582         new byte[] { 1, 0, 0 }));
583     assertNotNull(storage.getColumn(global_row_key,
584         new byte[] { 1, 0, 1 }));
585   }
586 
587   @Test
deleteRangeGlobalNone()588   public void deleteRangeGlobalNone() throws Exception {
589     setupStorage(false);
590     final int count = Annotation.deleteRange(tsdb, null, 1328140798000L,
591         1328140799000L).joinUninterruptibly();
592     assertEquals(0, count);
593     assertNotNull(storage.getColumn(global_row_key,
594         new byte[] { 1, 0, 0 }));
595     assertNotNull(storage.getColumn(global_row_key,
596         new byte[] { 1, 0, 1 }));
597   }
598 
599   @Test
deleteRangeGlobalMultiple()600   public void deleteRangeGlobalMultiple() throws Exception {
601     setupStorage(false);
602     final int count = Annotation.deleteRange(tsdb, null, 1328140799000L,
603         1328140900000L).joinUninterruptibly();
604     assertEquals(2, count);
605     assertNull(storage.getColumn(global_row_key,
606         new byte[] { 1, 0, 0 }));
607     assertNull(storage.getColumn(global_row_key,
608         new byte[] { 1, 0, 1 }));
609   }
610 
611   @Test
deleteRangeGlobalMultipleSalted()612   public void deleteRangeGlobalMultipleSalted() throws Exception {
613     setupStorage(true);
614     final int count = Annotation.deleteRange(tsdb, null, 1328140799000L,
615         1328140900000L).joinUninterruptibly();
616     assertEquals(2, count);
617     assertNull(storage.getColumn(global_row_key,
618         new byte[] { 1, 0, 0 }));
619     assertNull(storage.getColumn(global_row_key,
620         new byte[] { 1, 0, 1 }));
621   }
622 
623   @Test (expected = IllegalArgumentException.class)
deleteRangeEmptyEnd()624   public void deleteRangeEmptyEnd() throws Exception {
625     Annotation.deleteRange(tsdb, null, 1328140799000L, 0).joinUninterruptibly();
626   }
627 
628   @Test (expected = IllegalArgumentException.class)
deleteRangeEndLessThanStart()629   public void deleteRangeEndLessThanStart() throws Exception {
630     Annotation.deleteRange(tsdb, null, 1328140799000L, 1328140798000L)
631       .joinUninterruptibly();
632   }
633 
634   /**
635    * Sets up storage with or without salting and writes a few bits of data
636    * @param salted Whether or not to use salting
637    */
setupStorage(final boolean salted)638   private void setupStorage(final boolean salted) {
639     if (salted) {
640       PowerMockito.mockStatic(Const.class);
641       PowerMockito.when(Const.SALT_WIDTH()).thenReturn(1);
642       PowerMockito.when(Const.SALT_BUCKETS()).thenReturn(2);
643     }
644 
645     global_row_key = new byte[Const.SALT_WIDTH() + TSDB.metrics_width() +
646                               Const.TIMESTAMP_BYTES];
647     System.arraycopy(Bytes.fromInt(1328140800), 0, global_row_key,
648         Const.SALT_WIDTH() + TSDB.metrics_width(), Const.TIMESTAMP_BYTES);
649 
650     global_row_key_2015_midnight =
651         new byte[Const.SALT_WIDTH() + TSDB.metrics_width() +
652                  Const.TIMESTAMP_BYTES];
653     System.arraycopy(Bytes.fromInt(1425715200), 0, global_row_key_2015_midnight,
654         Const.SALT_WIDTH() + TSDB.metrics_width(), Const.TIMESTAMP_BYTES);
655 
656     tsuid_row_key = getRowKeyTemplate();
657     System.arraycopy(Bytes.fromInt(1388448000), 0, tsuid_row_key,
658         Const.SALT_WIDTH() + TSDB.metrics_width(), Const.TIMESTAMP_BYTES);
659     RowKey.prefixKeyWithSalt(tsuid_row_key);
660 
661     storage = new MockBase(tsdb, client, true, true, true, true);
662 
663     // add a global
664     storage.addColumn(global_row_key,
665         new byte[] { 1, 0, 0 },
666         ("{\"startTime\":1328140800,\"endTime\":1328140801,\"description\":" +
667             "\"Description\",\"notes\":\"Notes\",\"custom\":{\"owner\":" +
668             "\"ops\"}}").getBytes(MockBase.ASCII()));
669 
670     storage.addColumn(global_row_key,
671         new byte[] { 1, 0, 1 },
672         ("{\"startTime\":1328140801,\"endTime\":1328140803,\"description\":" +
673             "\"Global 2\",\"notes\":\"Nothing\"}").getBytes(MockBase.ASCII()));
674 
675     // add a local
676     storage.addColumn(tsuid_row_key,
677         new byte[] { 1, 0x0A, 0x02 },
678         ("{\"tsuid\":\"000001000001000001\",\"startTime\":1388450562," +
679             "\"endTime\":1419984000,\"description\":\"Hello!\",\"notes\":" +
680             "\"My Notes\",\"custom\":{\"owner\":\"ops\"}}")
681             .getBytes(MockBase.ASCII()));
682 
683     storage.addColumn(tsuid_row_key,
684         new byte[] { 1, 0x0A, 0x03 },
685         ("{\"tsuid\":\"000001000001000001\",\"startTime\":1388450563," +
686             "\"endTime\":1419984000,\"description\":\"Note2\",\"notes\":" +
687             "\"Nothing\"}")
688             .getBytes(MockBase.ASCII()));
689 
690     // add some data points too
691     storage.addColumn(tsuid_row_key,
692         new byte[] { 0x50, 0x10 }, new byte[] { 1 });
693 
694     storage.addColumn(tsuid_row_key,
695         new byte[] { 0x50, 0x18 }, new byte[] { 2 });
696   }
697 }
698