/* * The MIT License * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.influxdb.client.reactive; import java.time.Instant; import java.util.Arrays; import java.util.concurrent.CountDownLatch; import com.influxdb.annotations.Column; import com.influxdb.annotations.Measurement; import com.influxdb.client.InfluxDBClient; import com.influxdb.client.InfluxDBClientFactory; import com.influxdb.client.WriteOptions; import com.influxdb.client.domain.Authorization; import com.influxdb.client.domain.Bucket; import com.influxdb.client.domain.BucketRetentionRules; import com.influxdb.client.domain.Permission; import com.influxdb.client.domain.PermissionResource; import com.influxdb.client.domain.User; import com.influxdb.client.domain.WritePrecision; import com.influxdb.client.internal.AbstractInfluxDBClient; import com.influxdb.client.write.Point; import com.influxdb.client.write.events.WriteSuccessEvent; import com.influxdb.query.FluxRecord; import io.reactivex.Flowable; import io.reactivex.Maybe; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; import org.reactivestreams.Publisher; /** * @author Jakub Bednar (bednar@github) (22/11/2018 06:59) */ @RunWith(JUnitPlatform.class) class ITWriteQueryReactiveApi extends AbstractITInfluxDBClientTest { private WriteReactiveApi writeClient; private QueryReactiveApi queryClient; private Bucket bucket; private String token; @BeforeEach void setUp() throws Exception { super.setUp(); InfluxDBClient client = InfluxDBClientFactory.create(influxDB_URL, "my-user", "my-password".toCharArray()); BucketRetentionRules bucketRetentionRules = new BucketRetentionRules(); bucketRetentionRules.setEverySeconds(3600); bucket = client.getBucketsApi() .createBucket(generateName("h2o"), bucketRetentionRules, organization); // // Add Permissions to read and write to the Bucket // PermissionResource resource = new PermissionResource(); resource.setOrgID(organization.getId()); resource.setType(PermissionResource.TypeEnum.BUCKETS); resource.setId(bucket.getId()); Permission readBucket = new Permission(); readBucket.setResource(resource); readBucket.setAction(Permission.ActionEnum.READ); Permission writeBucket = new Permission(); writeBucket.setResource(resource); writeBucket.setAction(Permission.ActionEnum.WRITE); User loggedUser = client.getUsersApi().me(); Assertions.assertThat(loggedUser).isNotNull(); Authorization authorization = client.getAuthorizationsApi() .createAuthorization(organization, Arrays.asList(readBucket, writeBucket)); token = authorization.getToken(); client.close(); influxDBClient.close(); influxDBClient = InfluxDBClientReactiveFactory.create(influxDB_URL, token.toCharArray()); queryClient = influxDBClient.getQueryReactiveApi(); } @AfterEach void tearDown() throws Exception { if (writeClient != null) { writeClient.close(); } influxDBClient.close(); } @Test void writeRecord() { String bucketName = bucket.getName(); writeClient = influxDBClient.getWriteReactiveApi(); String lineProtocol = "h2o_feet,location=coyote_creek level\\ water_level=1.0 1"; Maybe<String> record = Maybe.just(lineProtocol); writeClient .listenEvents(WriteSuccessEvent.class) .subscribe(event -> { Assertions.assertThat(event).isNotNull(); Assertions.assertThat(event.getBucket()).isEqualTo(bucket.getName()); Assertions.assertThat(event.getOrganization()).isEqualTo(organization.getId()); Assertions.assertThat(event.getLineProtocol()).isEqualTo(lineProtocol); countDownLatch.countDown(); }); writeClient.writeRecord(bucketName, organization.getId(), WritePrecision.NS, record); waitToCallback(); Assertions.assertThat(countDownLatch.getCount()).isEqualTo(0); Flowable<FluxRecord> result = queryClient.query("from(bucket:\"" + bucketName + "\") |> range(start: 1970-01-01T00:00:00.000000001Z) |> last()", organization.getId()); result.test().assertValueCount(1).assertValue(fluxRecord -> { Assertions.assertThat(fluxRecord.getMeasurement()).isEqualTo("h2o_feet"); Assertions.assertThat(fluxRecord.getValue()).isEqualTo(1.0D); Assertions.assertThat(fluxRecord.getField()).isEqualTo("level water_level"); Assertions.assertThat(fluxRecord.getTime()).isEqualTo(Instant.ofEpochSecond(0, 1)); return true; }); } @Test void writeRecordEmpty() { writeClient = influxDBClient.getWriteReactiveApi(); writeClient.writeRecord(bucket.getName(), organization.getId(), WritePrecision.S, Maybe.empty()); } @Test void writeRecords() { writeClient = influxDBClient.getWriteReactiveApi(WriteOptions.builder().batchSize(1).build()); countDownLatch = new CountDownLatch(2); Publisher<String> records = Flowable.just( "h2o_feet,location=coyote_creek level\\ water_level=1.0 1", "h2o_feet,location=coyote_creek level\\ water_level=2.0 2"); writeClient .listenEvents(WriteSuccessEvent.class) .subscribe(event -> countDownLatch.countDown()); writeClient.writeRecords(bucket.getName(), organization.getId(), WritePrecision.S, records); waitToCallback(); Flowable<FluxRecord> results = queryClient.query("from(bucket:\"" + bucket.getName() + "\") |> range(start: 1970-01-01T00:00:00.000000001Z)", organization.getId()); results.test() .assertValueCount(2) .assertValueAt(0, fluxRecord -> { Assertions.assertThat(fluxRecord.getMeasurement()).isEqualTo("h2o_feet"); Assertions.assertThat(fluxRecord.getValue()).isEqualTo(1.0D); Assertions.assertThat(fluxRecord.getField()).isEqualTo("level water_level"); Assertions.assertThat(fluxRecord.getTime()).isEqualTo(Instant.ofEpochSecond(1)); return true; }) .assertValueAt(1, fluxRecord -> { Assertions.assertThat(fluxRecord.getMeasurement()).isEqualTo("h2o_feet"); Assertions.assertThat(fluxRecord.getValue()).isEqualTo(2.0D); Assertions.assertThat(fluxRecord.getField()).isEqualTo("level water_level"); Assertions.assertThat(fluxRecord.getTime()).isEqualTo(Instant.ofEpochSecond(2)); return true; }); } @Test void writePoint() { writeClient = influxDBClient.getWriteReactiveApi(); Instant time = Instant.ofEpochSecond(1000); Point point = Point.measurement("h2o_feet").addTag("location", "south").addField("water_level", 1).time(time, WritePrecision.MS); writeClient .listenEvents(WriteSuccessEvent.class) .subscribe(event -> countDownLatch.countDown()); writeClient.writePoint(bucket.getName(), organization.getId(), Maybe.just(point)); waitToCallback(); Flowable<FluxRecord> result = queryClient.query("from(bucket:\"" + bucket.getName() + "\") |> range(start: 1970-01-01T00:00:00.000000001Z) |> last()", organization.getId()); result.test().assertValueCount(1).assertValue(fluxRecord -> { Assertions.assertThat(fluxRecord.getMeasurement()).isEqualTo("h2o_feet"); Assertions.assertThat(fluxRecord.getValue()).isEqualTo(1L); Assertions.assertThat(fluxRecord.getField()).isEqualTo("water_level"); Assertions.assertThat(fluxRecord.getValueByKey("location")).isEqualTo("south"); Assertions.assertThat(fluxRecord.getTime()).isEqualTo(time); return true; }); } @Test void writePoints() { writeClient = influxDBClient.getWriteReactiveApi(); countDownLatch = new CountDownLatch(2); Instant time = Instant.ofEpochSecond(2000); Point point1 = Point.measurement("h2o_feet").addTag("location", "west").addField("water_level", 1).time(time, WritePrecision.MS); Point point2 = Point.measurement("h2o_feet").addTag("location", "west").addField("water_level", 2).time(time.plusSeconds(10), WritePrecision.S); writeClient .listenEvents(WriteSuccessEvent.class) .subscribe(event -> countDownLatch.countDown()); writeClient.writePoints(bucket.getName(), organization.getId(), (Publisher<Point>) Flowable.just(point1, point2)); waitToCallback(); Flowable<FluxRecord> result = queryClient.query("from(bucket:\"" + bucket.getName() + "\") |> range(start: 1970-01-01T00:00:00.000000001Z)", organization.getId()); result .test() .assertValueCount(2); } @Test void writeMeasurement() { H2O measurement = new H2O(); measurement.location = "coyote_creek"; measurement.level = 2.927; measurement.time = Instant.ofEpochSecond(10); writeClient = influxDBClient.getWriteReactiveApi(); writeClient .listenEvents(WriteSuccessEvent.class) .subscribe(event -> countDownLatch.countDown()); writeClient.writeMeasurement(bucket.getName(), organization.getId(), WritePrecision.NS, Maybe.just(measurement)); waitToCallback(); Flowable<H2O> measurements = queryClient.query("from(bucket:\"" + bucket.getName() + "\") |> range(start: 1970-01-01T00:00:00.000000001Z) |> last() |> rename(columns:{_value: \"water_level\"})", organization.getId(), H2O.class); measurements.test().assertValueCount(1).assertValueAt(0, h2O -> { Assertions.assertThat(h2O.location).isEqualTo("coyote_creek"); Assertions.assertThat(h2O.description).isNull(); Assertions.assertThat(h2O.level).isEqualTo(2.927); Assertions.assertThat(h2O.time).isEqualTo(measurement.time); return true; }); } @Test void writeMeasurements() { Instant time = Instant.ofEpochSecond(50); H2O measurement1 = new H2O(); measurement1.location = "coyote_creek"; measurement1.level = 2.927; measurement1.time = time; H2O measurement2 = new H2O(); measurement2.location = "bohemia"; measurement2.level = 3.927; measurement2.time = time.plusSeconds(1); writeClient = influxDBClient.getWriteReactiveApi(); writeClient .listenEvents(WriteSuccessEvent.class) .subscribe(event -> countDownLatch.countDown()); writeClient.writeMeasurements(bucket.getName(), organization.getId(), WritePrecision.NS, (Publisher<H2O>) Flowable.just(measurement1, measurement2)); waitToCallback(); Flowable<H2O> measurements = queryClient.query("from(bucket:\"" + bucket.getName() + "\") |> range(start: 1970-01-01T00:00:00.000000001Z) |> sort(desc: false, columns:[\"_time\"]) |>rename(columns:{_value: \"water_level\"})", organization.getId(), H2O.class); measurements .test() .assertValueCount(2) .assertValueAt(1, h2O -> { Assertions.assertThat(h2O.location).isEqualTo("coyote_creek"); Assertions.assertThat(h2O.description).isNull(); Assertions.assertThat(h2O.level).isEqualTo(2.927); Assertions.assertThat(h2O.time).isEqualTo(measurement1.time); return true; }) .assertValueAt(0, h2O -> { Assertions.assertThat(h2O.location).isEqualTo("bohemia"); Assertions.assertThat(h2O.description).isNull(); Assertions.assertThat(h2O.level).isEqualTo(3.927); Assertions.assertThat(h2O.time).isEqualTo(measurement2.time); return true; }); } @Test void queryRaw() { writeClient = influxDBClient.getWriteReactiveApi(); writeClient .listenEvents(WriteSuccessEvent.class) .subscribe(event -> countDownLatch.countDown()); writeClient.writeRecord(bucket.getName(), organization.getId(), WritePrecision.NS, Maybe.just("h2o_feet,location=coyote_creek level\\ water_level=1.0 1")); waitToCallback(); Flowable<String> result = queryClient.queryRaw("from(bucket:\"" + bucket.getName() + "\") |> range(start: 1970-01-01T00:00:00.000000001Z) |> last()", organization.getId()); result.test() .assertValueCount(6) .assertValueAt(0, "#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string") .assertValueAt(1, "#group,false,false,true,true,false,false,true,true,true") .assertValueAt(2, "#default,_result,,,,,,,,") .assertValueAt(3, ",result,table,_start,_stop,_time,_value,_field,_measurement,location") .assertValueAt(4, value -> { Assertions.assertThat(value).endsWith("1970-01-01T00:00:00.000000001Z,1,level water_level,h2o_feet,coyote_creek"); return true; }) .assertValueAt(5, ""); } @Test void queryRawDialect() { writeClient = influxDBClient.getWriteReactiveApi(); writeClient .listenEvents(WriteSuccessEvent.class) .subscribe(event -> countDownLatch.countDown()); writeClient.writeRecord(bucket.getName(), organization.getId(), WritePrecision.NS, Maybe.just("h2o_feet,location=coyote_creek level\\ water_level=1.0 1")); waitToCallback(); Flowable<String> result = queryClient.queryRaw("from(bucket:\"" + bucket.getName() + "\") |> range(start: 1970-01-01T00:00:00.000000001Z) |> last()", null, organization.getId()); result.test() .assertValueCount(3) .assertValueAt(0, ",result,table,_start,_stop,_time,_value,_field,_measurement,location") .assertValueAt(1, value -> { Assertions.assertThat(value).endsWith("1970-01-01T00:00:00.000000001Z,1,level water_level,h2o_feet,coyote_creek"); return true; }) .assertValueAt(2, ""); } @Test public void defaultOrgBucket() { InfluxDBClientReactive client = InfluxDBClientReactiveFactory.create(influxDB_URL, token.toCharArray(), organization.getId(), bucket.getName()); WriteReactiveApi writeApi = client.getWriteReactiveApi(); writeApi.writeRecord(WritePrecision.NS, Maybe.just("h2o,location=north water_level=60.0 1")); writeApi.close(); QueryReactiveApi queryApi = client.getQueryReactiveApi(); String query = "from(bucket:\"" + bucket.getName() + "\") |> range(start: 1970-01-01T00:00:00.000000001Z) |> last()"; // String { Flowable<FluxRecord> result = queryApi.query(query); result.test().assertValueCount(1).assertValue(fluxRecord -> { Assertions.assertThat(fluxRecord.getValue()).isEqualTo(60.0); return true; }); } // Publisher { Flowable<FluxRecord> result = queryApi.query(Flowable.just(query)); result.test().assertValueCount(1).assertValue(fluxRecord -> { Assertions.assertThat(fluxRecord.getValue()).isEqualTo(60.0); return true; }); } // Measurement { Flowable<H2O> result = queryApi.query(query, H2O.class); result.test().assertValueCount(1); } // Raw { Flowable<String> result = queryApi.queryRaw(query); result.test().assertValueCount(6); result = queryApi.queryRaw(Flowable.just(query)); result.test().assertValueCount(6); result = queryApi.queryRaw(query, AbstractInfluxDBClient.DEFAULT_DIALECT); result.test().assertValueCount(6); result = queryApi.queryRaw(Flowable.just(query), AbstractInfluxDBClient.DEFAULT_DIALECT); result.test().assertValueCount(6); } client.close(); } @Measurement(name = "h2o") public static class H2O { @Column(name = "location", tag = true) String location; @Column(name = "water_level") Double level; @Column(name = "level description") String description; @Column(name = "time", timestamp = true) Instant time; } }