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.core; 14 15 import static org.junit.Assert.assertArrayEquals; 16 import static org.junit.Assert.assertEquals; 17 import static org.junit.Assert.assertNotNull; 18 import static org.junit.Assert.assertNull; 19 import static org.junit.Assert.assertSame; 20 import static org.junit.Assert.assertTrue; 21 import static org.junit.Assert.fail; 22 23 import java.util.ArrayList; 24 import java.util.Collections; 25 import java.util.List; 26 27 import net.opentsdb.core.TsdbQuery.ForTesting; 28 import net.opentsdb.query.filter.TagVFilter; 29 import net.opentsdb.query.filter.TagVWildcardFilter; 30 import net.opentsdb.storage.MockBase; 31 import net.opentsdb.uid.NoSuchUniqueName; 32 import net.opentsdb.utils.DateTime; 33 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 import org.powermock.api.mockito.PowerMockito; 38 import org.powermock.core.classloader.annotations.PrepareForTest; 39 import org.powermock.modules.junit4.PowerMockRunner; 40 41 import com.stumbleupon.async.DeferredGroupException; 42 43 /** 44 * This class is for unit testing the TsdbQuery class. Pretty much making sure 45 * the various ctors and methods function as expected. For actually running the 46 * queries and validating the group by and aggregation logic, see 47 * {@link TestTsdbQueryQueries} 48 */ 49 @RunWith(PowerMockRunner.class) 50 @PrepareForTest({ DateTime.class }) 51 public final class TestTsdbQuery extends BaseTsdbTest { 52 private TsdbQuery query = null; 53 54 @Before beforeLocal()55 public void beforeLocal() throws Exception { 56 query = new TsdbQuery(tsdb); 57 } 58 59 @Test setStartTime()60 public void setStartTime() throws Exception { 61 query.setStartTime(1356998400L); 62 assertEquals(1356998400L, query.getStartTime()); 63 } 64 65 @Test setStartTimeZero()66 public void setStartTimeZero() throws Exception { 67 query.setStartTime(0L); 68 } 69 70 @Test (expected = IllegalArgumentException.class) setStartTimeInvalidNegative()71 public void setStartTimeInvalidNegative() throws Exception { 72 query.setStartTime(-1L); 73 } 74 75 @Test (expected = IllegalArgumentException.class) setStartTimeInvalidTooBig()76 public void setStartTimeInvalidTooBig() throws Exception { 77 query.setStartTime(17592186044416L); 78 } 79 80 @Test (expected = IllegalArgumentException.class) setStartTimeEqualtoEndTime()81 public void setStartTimeEqualtoEndTime() throws Exception { 82 query.setEndTime(1356998400L); 83 query.setStartTime(1356998400L); 84 } 85 86 @Test (expected = IllegalArgumentException.class) setStartTimeGreaterThanEndTime()87 public void setStartTimeGreaterThanEndTime() throws Exception { 88 query.setEndTime(1356998400L); 89 query.setStartTime(1356998460L); 90 } 91 92 @Test setEndTime()93 public void setEndTime() throws Exception { 94 query.setEndTime(1356998400L); 95 assertEquals(1356998400L, query.getEndTime()); 96 } 97 98 @Test (expected = IllegalStateException.class) getStartTimeNotSet()99 public void getStartTimeNotSet() throws Exception { 100 query.getStartTime(); 101 } 102 103 @Test (expected = IllegalArgumentException.class) setEndTimeInvalidNegative()104 public void setEndTimeInvalidNegative() throws Exception { 105 query.setEndTime(-1L); 106 } 107 108 @Test (expected = IllegalArgumentException.class) setEndTimeInvalidTooBig()109 public void setEndTimeInvalidTooBig() throws Exception { 110 query.setEndTime(17592186044416L); 111 } 112 113 @Test (expected = IllegalArgumentException.class) setEndTimeEqualtoEndTime()114 public void setEndTimeEqualtoEndTime() throws Exception { 115 query.setStartTime(1356998400L); 116 query.setEndTime(1356998400L); 117 } 118 119 @Test (expected = IllegalArgumentException.class) setEndTimeGreaterThanEndTime()120 public void setEndTimeGreaterThanEndTime() throws Exception { 121 query.setStartTime(1356998460L); 122 query.setEndTime(1356998400L); 123 } 124 125 @Test getEndTimeNotSet()126 public void getEndTimeNotSet() throws Exception { 127 PowerMockito.mockStatic(DateTime.class); 128 PowerMockito.when(DateTime.currentTimeMillis()).thenReturn(1357300800000L); 129 assertEquals(1357300800000L, query.getEndTime()); 130 } 131 132 @Test setTimeSeries()133 public void setTimeSeries() throws Exception { 134 query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false); 135 assertNotNull(query); 136 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 137 assertEquals(1, ForTesting.getFilters(query).size()); 138 assertEquals(1, ForTesting.getGroupBys(query).size()); 139 assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0)); 140 assertEquals(1, ForTesting.getRowKeyLiterals(query).size()); 141 assertEquals(1, ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES).length); 142 assertArrayEquals(TAGV_BYTES, 143 ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES)[0]); 144 } 145 146 @Test (expected = NullPointerException.class) setTimeSeriesNullTags()147 public void setTimeSeriesNullTags() throws Exception { 148 query.setTimeSeries(METRIC_STRING, null, Aggregators.SUM, false); 149 } 150 151 @Test setTimeSeriesEmptyTags()152 public void setTimeSeriesEmptyTags() throws Exception { 153 tags.clear(); 154 query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false); 155 assertNotNull(query); 156 } 157 158 @Test (expected = NoSuchUniqueName.class) setTimeSeriesNosuchMetric()159 public void setTimeSeriesNosuchMetric() throws Exception { 160 query.setTimeSeries(NSUN_METRIC, tags, Aggregators.SUM, false); 161 } 162 163 @Test (expected = NoSuchUniqueName.class) setTimeSeriesNosuchTagk()164 public void setTimeSeriesNosuchTagk() throws Exception { 165 tags.clear(); 166 tags.put(NSUN_TAGK, TAGV_STRING); 167 query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false); 168 } 169 170 @Test (expected = NoSuchUniqueName.class) setTimeSeriesNosuchTagv()171 public void setTimeSeriesNosuchTagv() throws Exception { 172 tags.put(TAGK_STRING, NSUN_TAGV); 173 query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false); 174 } 175 176 @Test setTimeSeriesTS()177 public void setTimeSeriesTS() throws Exception { 178 final List<String> tsuids = new ArrayList<String>(2); 179 tsuids.add("000001000001000001"); 180 tsuids.add("000001000001000002"); 181 query.setTimeSeries(tsuids, Aggregators.SUM, false); 182 assertNotNull(query); 183 } 184 185 @Test (expected = IllegalArgumentException.class) setTimeSeriesTSNullList()186 public void setTimeSeriesTSNullList() throws Exception { 187 query.setTimeSeries(null, Aggregators.SUM, false); 188 } 189 190 @Test (expected = IllegalArgumentException.class) setTimeSeriesTSEmptyList()191 public void setTimeSeriesTSEmptyList() throws Exception { 192 final List<String> tsuids = new ArrayList<String>(); 193 query.setTimeSeries(tsuids, Aggregators.SUM, false); 194 } 195 196 @Test (expected = IllegalArgumentException.class) setTimeSeriesTSDifferentMetrics()197 public void setTimeSeriesTSDifferentMetrics() throws Exception { 198 final List<String> tsuids = new ArrayList<String>(2); 199 tsuids.add("000001000001000001"); 200 tsuids.add("000002000001000002"); 201 query.setTimeSeries(tsuids, Aggregators.SUM, false); 202 } 203 204 @Test configureFromQuery()205 public void configureFromQuery() throws Exception { 206 setDataPointStorage(); 207 final TSQuery ts_query = getTSQuery(); 208 ts_query.validateAndSetQuery(); 209 query = new TsdbQuery(tsdb); 210 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 211 212 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 213 assertEquals(1, ForTesting.getFilters(query).size()); 214 assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0)); 215 assertEquals(1, ForTesting.getGroupBys(query).size()); 216 assertNotNull(ForTesting.getRateOptions(query)); 217 } 218 219 @Test configureFromQueryWithRate()220 public void configureFromQueryWithRate() throws Exception { 221 setDataPointStorage(); 222 final TSQuery ts_query = getTSQuery(); 223 final RateOptions rate_options = new RateOptions(); 224 rate_options.setResetValue(1024); 225 ts_query.getQueries().get(0).setRateOptions(rate_options); 226 ts_query.validateAndSetQuery(); 227 query = new TsdbQuery(tsdb); 228 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 229 230 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 231 assertEquals(1, ForTesting.getFilters(query).size()); 232 assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0)); 233 assertEquals(1, ForTesting.getGroupBys(query).size()); 234 assertTrue(rate_options == ForTesting.getRateOptions(query)); 235 } 236 237 @Test configureFromQueryNoTags()238 public void configureFromQueryNoTags() throws Exception { 239 setDataPointStorage(); 240 final TSQuery ts_query = getTSQuery(); 241 ts_query.getQueries().get(0).setTags(Collections.EMPTY_MAP); 242 ts_query.validateAndSetQuery(); 243 query = new TsdbQuery(tsdb); 244 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 245 246 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 247 assertEquals(0, ForTesting.getFilters(query).size()); 248 assertNull(ForTesting.getGroupBys(query)); 249 assertNull(ForTesting.getRowKeyLiterals(query)); 250 } 251 252 @Test configureFromQueryGroupByAll()253 public void configureFromQueryGroupByAll() throws Exception { 254 setDataPointStorage(); 255 final TSQuery ts_query = getTSQuery(); 256 tags.clear(); 257 tags.put(TAGK_STRING, "*"); 258 ts_query.getQueries().get(0).setTags(tags); 259 ts_query.validateAndSetQuery(); 260 query = new TsdbQuery(tsdb); 261 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 262 263 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 264 assertEquals(1, ForTesting.getFilters(query).size()); 265 assertEquals(1, ForTesting.getGroupBys(query).size()); 266 assertArrayEquals(TAGK_BYTES, 267 ForTesting.getGroupBys(query).get(0)); 268 assertEquals(1, ForTesting.getRowKeyLiterals(query).size()); 269 assertNull(ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES)); 270 } 271 272 @Test configureFromQueryGroupByPipe()273 public void configureFromQueryGroupByPipe() throws Exception { 274 setDataPointStorage(); 275 final TSQuery ts_query = getTSQuery(); 276 tags.clear(); 277 tags.put(TAGK_STRING, TAGV_STRING + "|" + TAGV_B_STRING); 278 ts_query.getQueries().get(0).setTags(tags); 279 ts_query.validateAndSetQuery(); 280 query = new TsdbQuery(tsdb); 281 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 282 283 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 284 assertEquals(1, ForTesting.getFilters(query).size()); 285 assertEquals(1, ForTesting.getGroupBys(query).size()); 286 assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0)); 287 assertEquals(1, ForTesting.getRowKeyLiterals(query).size()); 288 assertEquals(2, ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES).length); 289 assertArrayEquals(TAGV_BYTES, 290 ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES)[0]); 291 assertArrayEquals(TAGV_B_BYTES, 292 ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES)[1]); 293 } 294 295 @Test configureFromQueryWithGroupByFilter()296 public void configureFromQueryWithGroupByFilter() throws Exception { 297 setDataPointStorage(); 298 final TSQuery ts_query = getTSQuery(); 299 tags.clear(); 300 tags.put("host", TagVWildcardFilter.FILTER_NAME + "(*imes)"); 301 ts_query.getQueries().get(0).setTags(tags); 302 ts_query.validateAndSetQuery(); 303 query = new TsdbQuery(tsdb); 304 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 305 306 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 307 assertEquals(1, ForTesting.getFilters(query).size()); 308 assertEquals(1, ForTesting.getGroupBys(query).size()); 309 assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0)); 310 assertEquals(1, ForTesting.getRowKeyLiterals(query).size()); 311 assertNull(ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES)); 312 assertNotNull(ForTesting.getRateOptions(query)); 313 } 314 315 @Test configureFromQueryWithFilter()316 public void configureFromQueryWithFilter() throws Exception { 317 setDataPointStorage(); 318 final TSQuery ts_query = getTSQuery(); 319 final List<TagVFilter> filters = new ArrayList<TagVFilter>(1); 320 filters.add(new TagVWildcardFilter("host", "*imes")); 321 ts_query.getQueries().get(0).setFilters(filters); 322 ts_query.validateAndSetQuery(); 323 query = new TsdbQuery(tsdb); 324 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 325 326 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 327 assertEquals(1, ForTesting.getFilters(query).size()); 328 assertNull(ForTesting.getGroupBys(query)); 329 assertEquals(1, ForTesting.getRowKeyLiterals(query).size()); 330 assertNull(ForTesting.getRowKeyLiterals(query).get(TAGV_BYTES)); 331 assertNotNull(ForTesting.getRateOptions(query)); 332 } 333 334 @Test configureFromQueryWithGroupByAndRegularFilters()335 public void configureFromQueryWithGroupByAndRegularFilters() throws Exception { 336 setDataPointStorage(); 337 final TSQuery ts_query = getTSQuery(); 338 final List<TagVFilter> filters = new ArrayList<TagVFilter>(1); 339 filters.add(new TagVWildcardFilter("host", "*imes")); 340 filters.add(TagVFilter.Builder().setFilter("*").setTagk("host") 341 .setType("wildcard").setGroupBy(true).build()); 342 ts_query.getQueries().get(0).setFilters(filters); 343 ts_query.validateAndSetQuery(); 344 345 query = new TsdbQuery(tsdb); 346 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 347 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 348 assertEquals(2, ForTesting.getFilters(query).size()); 349 assertEquals(1, ForTesting.getGroupBys(query).size()); 350 assertArrayEquals(TAGK_BYTES, ForTesting.getGroupBys(query).get(0)); 351 assertEquals(1, ForTesting.getRowKeyLiterals(query).size()); 352 assertNull(ForTesting.getRowKeyLiterals(query).get(TAGK_BYTES)); 353 assertNotNull(ForTesting.getRateOptions(query)); 354 } 355 356 @Test (expected = IllegalArgumentException.class) configureFromQueryNullSubs()357 public void configureFromQueryNullSubs() throws Exception { 358 final TSQuery ts_query = new TSQuery(); 359 new TsdbQuery(tsdb).configureFromQuery(ts_query, 0); 360 } 361 362 @Test (expected = IllegalArgumentException.class) configureFromQueryEmptySubs()363 public void configureFromQueryEmptySubs() throws Exception { 364 final TSQuery ts_query = new TSQuery(); 365 ts_query.setQueries(new ArrayList<TSSubQuery>(0)); 366 new TsdbQuery(tsdb).configureFromQuery(ts_query, 0); 367 } 368 369 @Test (expected = IllegalArgumentException.class) configureFromQueryNegativeIndex()370 public void configureFromQueryNegativeIndex() throws Exception { 371 final TSQuery ts_query = getTSQuery(); 372 new TsdbQuery(tsdb).configureFromQuery(ts_query, -1); 373 } 374 375 @Test (expected = IllegalArgumentException.class) configureFromQueryIndexOutOfBounds()376 public void configureFromQueryIndexOutOfBounds() throws Exception { 377 final TSQuery ts_query = getTSQuery(); 378 new TsdbQuery(tsdb).configureFromQuery(ts_query, 2); 379 } 380 381 @Test (expected = NoSuchUniqueName.class) configureFromQueryNSUMetric()382 public void configureFromQueryNSUMetric() throws Exception { 383 setDataPointStorage(); 384 final TSQuery ts_query = getTSQuery(); 385 ts_query.getQueries().get(0).setMetric(NSUN_METRIC); 386 ts_query.validateAndSetQuery(); 387 query = new TsdbQuery(tsdb); 388 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 389 } 390 391 @Test (expected = DeferredGroupException.class) configureFromQueryNSUTagk()392 public void configureFromQueryNSUTagk() throws Exception { 393 setDataPointStorage(); 394 final TSQuery ts_query = getTSQuery(); 395 tags.clear(); 396 tags.put(NSUN_TAGK, TAGV_STRING); 397 ts_query.getQueries().get(0).setTags(tags); 398 ts_query.validateAndSetQuery(); 399 query = new TsdbQuery(tsdb); 400 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 401 } 402 403 @Test (expected = DeferredGroupException.class) configureFromQueryNSUTagv()404 public void configureFromQueryNSUTagv() throws Exception { 405 setDataPointStorage(); 406 final TSQuery ts_query = getTSQuery(); 407 tags.clear(); 408 tags.put(TAGK_STRING, NSUN_TAGV); 409 ts_query.getQueries().get(0).setTags(tags); 410 ts_query.validateAndSetQuery(); 411 query = new TsdbQuery(tsdb); 412 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 413 } 414 415 @Test (expected = DeferredGroupException.class) configureFromQueryGroupByPipeNSUTagk()416 public void configureFromQueryGroupByPipeNSUTagk() throws Exception { 417 setDataPointStorage(); 418 final TSQuery ts_query = getTSQuery(); 419 tags.clear(); 420 tags.put(NSUN_TAGK, TAGV_STRING + "|" + TAGV_B_STRING); 421 ts_query.getQueries().get(0).setTags(tags); 422 ts_query.validateAndSetQuery(); 423 query = new TsdbQuery(tsdb); 424 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 425 } 426 427 @Test (expected = DeferredGroupException.class) configureFromQueryGroupByPipeNSUTagv()428 public void configureFromQueryGroupByPipeNSUTagv() throws Exception { 429 setDataPointStorage(); 430 final TSQuery ts_query = getTSQuery(); 431 tags.clear(); 432 tags.put(TAGK_STRING, TAGV_STRING + "|" + NSUN_TAGV); 433 ts_query.getQueries().get(0).setTags(tags); 434 ts_query.validateAndSetQuery(); 435 query = new TsdbQuery(tsdb); 436 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 437 } 438 439 @Test configureFromQueryGroupByPipeNSUTagvSkipUnresolved()440 public void configureFromQueryGroupByPipeNSUTagvSkipUnresolved() 441 throws Exception { 442 config.overrideConfig("tsd.query.skip_unresolved_tagvs", "true"); 443 setDataPointStorage(); 444 final TSQuery ts_query = getTSQuery(); 445 tags.clear(); 446 tags.put(TAGK_STRING, TAGV_STRING + "|" + NSUN_TAGV); 447 ts_query.getQueries().get(0).setTags(tags); 448 ts_query.validateAndSetQuery(); 449 query = new TsdbQuery(tsdb); 450 query.configureFromQuery(ts_query, 0).joinUninterruptibly(); 451 452 assertArrayEquals(METRIC_BYTES, ForTesting.getMetric(query)); 453 assertEquals(1, ForTesting.getFilters(query).size()); 454 assertEquals(1, ForTesting.getGroupBys(query).size()); 455 assertArrayEquals(TAGK_BYTES, 456 ForTesting.getGroupBys(query).get(0)); 457 } 458 459 @Test deleteDatapoints()460 public void deleteDatapoints() throws Exception { 461 setDataPointStorage(); 462 463 tsdb.addPoint(METRIC_STRING, 1356998400, 42, tags).joinUninterruptibly(); 464 query.setStartTime(1356998400); 465 query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false); 466 467 query.setDelete(true); 468 final DataPoints[] dps1 = query.run(); 469 assertEquals(1, dps1.length); 470 // second run should be empty 471 final DataPoints[] dps2 = query.run(); 472 assertEquals(0, dps2.length); 473 } 474 475 @Test scannerException()476 public void scannerException() throws Exception { 477 storeLongTimeSeriesSeconds(true, false); 478 final RuntimeException ex = new RuntimeException("Boo!"); 479 storage.throwException(MockBase.stringToBytes( 480 "00000150E22700000001000001"), ex, true); 481 482 storage.dumpToSystemOut(); 483 query.setStartTime(1356998400); 484 query.setEndTime(1357041600); 485 query.setTimeSeries(METRIC_STRING, tags, Aggregators.SUM, false); 486 try { 487 query.run(); 488 fail("Expected a RuntimeException"); 489 } catch (RuntimeException e) { 490 assertSame(ex, e); 491 } 492 } 493 494 /** @return a simple TSQuery object for testing */ getTSQuery()495 private TSQuery getTSQuery() { 496 final TSQuery ts_query = new TSQuery(); 497 ts_query.setStart("1356998400"); 498 499 final TSSubQuery sub_query = new TSSubQuery(); 500 sub_query.setMetric(METRIC_STRING); 501 sub_query.setAggregator("sum"); 502 503 sub_query.setTags(tags); 504 505 final ArrayList<TSSubQuery> sub_queries = new ArrayList<TSSubQuery>(1); 506 sub_queries.add(sub_query); 507 508 ts_query.setQueries(sub_queries); 509 return ts_query; 510 } 511 } 512