/** * * Test.cpp: Unit and integration tests for InfluxDB client for Arduino * * MIT License * * Copyright (c) 2020 InfluxData * * 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. */ #include "Test.h" #include "TestSupport.h" #include #include "../src/Version.h" #define INFLUXDB_CLIENT_TESTING_BAD_URL "http://127.0.0.1:999" void Test::run() { failures = 0; Serial.println("Unit & Integration Tests"); // Basic tests testUtils(); testOptions(); testPoint(); testBatch(); testLineProtocol(); testEcaping(); testUrlEncode(); testIsValidID(); testFluxTypes(); testFluxTypesSerialization(); testFluxParserEmpty(); testFluxParserSingleTable(); testFluxParserNilValue(); testFluxParserMultiTables(false); testFluxParserMultiTables(true); testFluxParserErrorDiffentColumnsNum(); testFluxParserFluxError(); testFluxParserInvalidDatatype(); testFluxParserMissingDatatype(); testFluxParserErrorInRow(); testQueryParams(); testBasicFunction(); testFlushing(); testInit(); testRepeatedInit(); testV1(); testUserAgent(); testHTTPReadTimeout(); testDefaultTags(); // Advanced tests testLargeBatch(); testFailedWrites(); testTimestamp(); testTimestampAdjustment(); testRetryOnFailedConnection(); testRetryOnFailedConnectionWithFlush(); testNonRetry(); testBufferOverwriteBatchsize1(); testBufferOverwriteBatchsize5(); testServerTempDownBatchsize5(); testRetriesOnServerOverload(); testRetryInterval(); testBuckets(); testQueryWithParams(); Serial.printf("Tests %s\n", failures ? "FAILED" : "SUCCEEDED"); } void Test::testUtils() { TEST_INIT("testUtils"); int d = getNumLength(12345678901); TEST_ASSERTM(d == 11, String(d)); d = getNumLength(1); TEST_ASSERTM(d == 1, String(d)); d = getNumLength(12); TEST_ASSERTM(d == 2, String(d)); TEST_END(); } void Test::testOptions() { TEST_INIT("testOptions"); WriteOptions defWO; TEST_ASSERT(defWO._writePrecision == WritePrecision::NoTime); TEST_ASSERT(defWO._batchSize == 1); TEST_ASSERT(defWO._bufferSize == 5); TEST_ASSERT(defWO._flushInterval == 60); TEST_ASSERT(defWO._retryInterval == 5); TEST_ASSERT(defWO._maxRetryInterval == 300); TEST_ASSERT(defWO._maxRetryAttempts == 3); TEST_ASSERT(defWO._defaultTags.length() == 0); //Test max batch size // defWO = WriteOptions().batchSize(1<<14); // #if defined(ESP8266) // TEST_ASSERT(defWO._batchSize == 255); // #elif defined(ESP32) // TEST_ASSERT(defWO._batchSize == 2047); // #endif defWO = WriteOptions().writePrecision(WritePrecision::NS).batchSize(32000).bufferSize(20).flushInterval(120).retryInterval(1).maxRetryInterval(20).maxRetryAttempts(5).addDefaultTag("tag1","val1").addDefaultTag("tag2","val2"); TEST_ASSERT(defWO._writePrecision == WritePrecision::NS); TEST_ASSERT(defWO._batchSize == 32000); TEST_ASSERT(defWO._bufferSize == 20); TEST_ASSERT(defWO._flushInterval == 120); TEST_ASSERT(defWO._retryInterval == 1); TEST_ASSERT(defWO._maxRetryInterval == 20); TEST_ASSERT(defWO._maxRetryAttempts == 5); TEST_ASSERT(defWO._defaultTags == "tag1=val1,tag2=val2"); HTTPOptions defHO; TEST_ASSERT(!defHO._connectionReuse); TEST_ASSERT(defHO._httpReadTimeout == 5000); defHO = HTTPOptions().connectionReuse(true).httpReadTimeout(20000); TEST_ASSERT(defHO._connectionReuse); TEST_ASSERT(defHO._httpReadTimeout == 20000); InfluxDBClient c; TEST_ASSERT(c._writeOptions._writePrecision == WritePrecision::NoTime); TEST_ASSERT(c._writeOptions._batchSize == 1); TEST_ASSERT(c._writeOptions._bufferSize == 5); TEST_ASSERT(c._writeOptions._flushInterval == 60); TEST_ASSERT(c._writeOptions._retryInterval == 5); TEST_ASSERT(c._writeOptions._maxRetryAttempts == 3); TEST_ASSERT(c._writeOptions._maxRetryInterval == 300); ConnectionInfo connInfo = { serverUrl: "http://localhost:8086", bucket: "", org: "", authToken: "my-token" }; HTTPService s(&connInfo); TEST_ASSERT(!s._httpOptions._connectionReuse); TEST_ASSERT(s._httpOptions._httpReadTimeout == 5000); // Client has no params TEST_ASSERT(!c.setWriteOptions(defWO)); TEST_ASSERT(c.getLastErrorMessage() == "Invalid parameters"); c.setConnectionParams("http://localhost:8086","my-org","my-bucket", "my-token"); TEST_ASSERT(c.setWriteOptions(defWO)); TEST_ASSERT(c._writeOptions._writePrecision == WritePrecision::NS); TEST_ASSERT(c._writeOptions._batchSize == 32000); TEST_ASSERT(c._writeOptions._bufferSize == 64000); TEST_ASSERT(c._writeOptions._flushInterval == 120); TEST_ASSERT(c._writeOptions._retryInterval == 1); TEST_ASSERT(c._writeOptions._maxRetryAttempts == 5); TEST_ASSERT(c._writeOptions._maxRetryInterval == 20); TEST_ASSERT(c.setHTTPOptions(defHO)); TEST_ASSERT(c._service->_httpOptions._connectionReuse); TEST_ASSERT(c._service->_httpOptions._httpReadTimeout == 20000); c.setWriteOptions(WritePrecision::MS, 15, 14, 70, false); TEST_ASSERT(c._writeOptions._writePrecision == WritePrecision::MS); TEST_ASSERT(c._writeOptions._batchSize == 15); TEST_ASSERTM(c._writeOptions._bufferSize == 30, String(c._writeOptions._bufferSize)); TEST_ASSERT(c._writeOptions._flushInterval == 70); TEST_ASSERT(!c._service->_httpOptions._connectionReuse); TEST_ASSERT(c._service->_httpOptions._httpReadTimeout == 20000); defWO = WriteOptions().batchSize(100).bufferSize(7000); c.setWriteOptions(defWO); TEST_ASSERTM(c._writeBufferSize == 70, String(c._writeBufferSize)); defWO = WriteOptions().batchSize(10).bufferSize(7000); c.setWriteOptions(defWO); TEST_ASSERTM(c._writeBufferSize == 255, String(c._writeBufferSize)); TEST_END(); } void Test::testEcaping() { TEST_INIT("testEcaping"); Point p("t\re=s\nt\t_t e\"s,t"); p.addTag("ta=g","val=ue"); p.addTag("ta\tg","val\tue"); p.addTag("ta\rg","val\rue"); p.addTag("ta\ng","val\nue"); p.addTag("ta g","valu e"); p.addTag("ta,g","valu,e"); p.addTag("tag","value"); p.addTag("ta\"g","val\"ue"); p.addField("fie=ld", "val=ue"); p.addField("fie\tld", "val\tue"); p.addField("fie\rld", "val\rue"); p.addField("fie\nld", "val\nue"); p.addField("fie ld", "val ue"); p.addField("fie,ld", "val,ue"); p.addField("fie\"ld", "val\"ue"); InfluxDBClient client; String line = p.toLineProtocol(); const char *lp = "t\\\re=s\\\nt\\\t_t\\ e\"s\\,t,ta\\=g=val\\=ue,ta\\\tg=val\\\tue,ta\\\rg=val\\\rue,ta\\\ng=val\\\nue,ta\\ g=valu\\ e,ta\\,g=valu\\,e,tag=value,ta\"g=val\"ue fie\\=ld=\"val=ue\",fie\\\tld=\"val\tue\",fie\\\rld=\"val\rue\",fie\\\nld=\"val\nue\",fie\\ ld=\"val ue\",fie\\,ld=\"val,ue\",fie\"ld=\"val\\\"ue\""; TEST_ASSERTM(line == lp, line); line = client.pointToLineProtocol(p); TEST_ASSERTM(line == lp, line); WriteOptions w; w.addDefaultTag("dta=g","dval=ue"); w.addDefaultTag("dtag","dvalue"); const char *lp2 = "t\\\re=s\\\nt\\\t_t\\ e\"s\\,t,dta\\=g=dval\\=ue,dtag=dvalue,ta\\=g=val\\=ue,ta\\\tg=val\\\tue,ta\\\rg=val\\\rue,ta\\\ng=val\\\nue,ta\\ g=valu\\ e,ta\\,g=valu\\,e,tag=value,ta\"g=val\"ue fie\\=ld=\"val=ue\",fie\\\tld=\"val\tue\",fie\\\rld=\"val\rue\",fie\\\nld=\"val\nue\",fie\\ ld=\"val ue\",fie\\,ld=\"val,ue\",fie\"ld=\"val\\\"ue\""; line = p.toLineProtocol(w._defaultTags); TEST_ASSERTM(line == lp2, line); client.setWriteOptions(w); line = client.pointToLineProtocol(p); TEST_ASSERTM(line == lp2, line); TEST_END(); } void Test::testPoint() { TEST_INIT("testPoint"); Point p("test"); TEST_ASSERT(!p.hasTags()); TEST_ASSERT(!p.hasFields()); String name = "tag3"; String value = "tagvalue3"; p.addTag("tag1", "tagvalue"); p.addTag(F("tag2"), F("tagvalue2")); p.addTag(name, value); TEST_ASSERT(p.hasTags()); TEST_ASSERT(!p.hasFields()); p.addField("fieldInt", -23); TEST_ASSERT(p.hasFields()); p.addField("fieldBool", true); p.addField("fieldFloat1", 1.123f); p.addField("fieldFloat2", 1.12345f, 5); p.addField(F("fieldDouble1"), 1.123); name = "fieldDouble2"; p.addField(name, 1.12345, 5); p.addField("fieldChar", 'A'); p.addField("fieldUChar", (unsigned char)1); p.addField("fieldUInt", 23u); p.addField("fieldLong", 123456l); p.addField("fieldULong", 123456ul); p.addField("fieldLongLong", 9123456789l); p.addField("fieldULongLong", 9123456789ul); p.addField("fieldString", "text test"); p.addField(F("fieldString2"), F("text test2")); name = "fieldString3"; value = "text test3"; p.addField(name, value); String line = p.toLineProtocol(); String testLine = "test,tag1=tagvalue,tag2=tagvalue2,tag3=tagvalue3 fieldInt=-23i,fieldBool=true,fieldFloat1=1.12,fieldFloat2=1.12345,fieldDouble1=1.12,fieldDouble2=1.12345,fieldChar=\"A\",fieldUChar=1i,fieldUInt=23i,fieldLong=123456i,fieldULong=123456i,fieldLongLong=9123456789i,fieldULongLong=9123456789i,fieldString=\"text test\",fieldString2=\"text test2\",fieldString3=\"text test3\""; TEST_ASSERTM(line == testLine, line); String defaultTags="dtag=val"; line = p.toLineProtocol(defaultTags); testLine = "test,dtag=val,tag1=tagvalue,tag2=tagvalue2,tag3=tagvalue3 fieldInt=-23i,fieldBool=true,fieldFloat1=1.12,fieldFloat2=1.12345,fieldDouble1=1.12,fieldDouble2=1.12345,fieldChar=\"A\",fieldUChar=1i,fieldUInt=23i,fieldLong=123456i,fieldULong=123456i,fieldLongLong=9123456789i,fieldULongLong=9123456789i,fieldString=\"text test\",fieldString2=\"text test2\",fieldString3=\"text test3\""; TEST_ASSERTM(line == testLine, line); p.clearTags(); line = p.toLineProtocol(defaultTags); testLine = "test,dtag=val fieldInt=-23i,fieldBool=true,fieldFloat1=1.12,fieldFloat2=1.12345,fieldDouble1=1.12,fieldDouble2=1.12345,fieldChar=\"A\",fieldUChar=1i,fieldUInt=23i,fieldLong=123456i,fieldULong=123456i,fieldLongLong=9123456789i,fieldULongLong=9123456789i,fieldString=\"text test\",fieldString2=\"text test2\",fieldString3=\"text test3\""; TEST_ASSERTM(line == testLine, line); p.clearFields(); p.clearTags(); //line protocol without tags p.addField("f", 1); line = p.toLineProtocol(); testLine = "test f=1i"; TEST_ASSERTM(line == testLine, line); TEST_ASSERT(!p.hasTime()); time_t now = time(nullptr); String snow(now); p.setTime(now); String testLineTime = testLine + " " + snow; line = p.toLineProtocol(); TEST_ASSERTM(line == testLineTime, line); unsigned long long ts = now*1000000000LL+123456789; p.setTime(ts); testLineTime = testLine + " " + snow + "123456789"; line = p.toLineProtocol(); TEST_ASSERTM(line == testLineTime, line); now += 10; snow = ""; snow.concat(now); p.setTime(snow); testLineTime = testLine + " " + snow; line = p.toLineProtocol(); TEST_ASSERTM(line == testLineTime, line); p.setTime(WritePrecision::S); line = p.toLineProtocol(); int partsCount; String *parts = getParts(line, ' ', partsCount); TEST_ASSERTM(partsCount == 3, String("3 != ") + partsCount); TEST_ASSERTM(parts[2].length() == snow.length(), parts[2] + "," + snow); delete[] parts; p.setTime(WritePrecision::MS); TEST_ASSERT(p.hasTime()); line = p.toLineProtocol(); parts = getParts(line, ' ', partsCount); TEST_ASSERT(partsCount == 3); TEST_ASSERT(parts[2].length() == snow.length() + 3); delete[] parts; p.setTime(WritePrecision::US); line = p.toLineProtocol(); parts = getParts(line, ' ', partsCount); TEST_ASSERT(partsCount == 3); TEST_ASSERT(parts[2].length() == snow.length() + 6); delete[] parts; p.setTime(WritePrecision::NS); line = p.toLineProtocol(); parts = getParts(line, ' ', partsCount); TEST_ASSERT(partsCount == 3); TEST_ASSERT(parts[2].length() == snow.length() + 9); delete[] parts; p.clearFields(); TEST_ASSERT(!p.hasFields()); p.clearTags(); TEST_ASSERT(!p.hasFields()); p.setTime(""); TEST_ASSERT(!p.hasTime()); p.addField("nan", (float)NAN); TEST_ASSERT(!p.hasFields()); p.addField("nan", (double)NAN); TEST_ASSERT(!p.hasFields()); TEST_END(); } void Test::testBatch() { TEST_INIT("testBatch"); InfluxDBClient::Batch batch(2); TEST_ASSERT(batch._size == 2); TEST_ASSERT(batch.pointer == 0); TEST_ASSERT(!batch.buffer[0]); TEST_ASSERT(batch.isEmpty()); TEST_ASSERT(!batch.isFull()); const char *line = "air,location=Zdiby,sensor=STH31 temp=22.1,hum=44"; TEST_ASSERT(!batch.append(line)); TEST_ASSERT(!batch.isEmpty()); TEST_ASSERT(!batch.isFull()); TEST_ASSERT(batch.append(line)); TEST_ASSERT(!batch.isEmpty()); TEST_ASSERT(batch.isFull()); TEST_ASSERT(batch.pointer == 2); InfluxDBClient::BatchStreamer str(&batch); int len = strlen(line); TEST_ASSERT(str.available() == len*2+2); int size = str.available()+1; char *buff = new char[size]; TEST_ASSERT(str.readBytes(buff, len+1) == len+1); TEST_ASSERT(str.peek() == 'a'); TEST_ASSERT(str.available() == len+1); TEST_ASSERT(str.readBytes(buff+len+1, len) == len); TEST_ASSERT(str.peek() == '\n'); TEST_ASSERT(str.available() == 1); TEST_ASSERT(str.readBytes(buff+2*len+1, 1) == 1); TEST_ASSERT(str.peek() == -1); TEST_ASSERT(str.available() == 0); buff[size-1] = 0; Serial.println(buff); int i; for(i=0;iaddField("index", i); TEST_ASSERT(!client.writePoint(*p)); delete p; } TEST_ASSERT(client.isBufferFull()); TEST_ASSERT(!client.isBufferEmpty()); client.setConnectionParams(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); TEST_ASSERT(client.isBufferFull()); TEST_ASSERT(!client.isBufferEmpty()); client.resetBuffer(); TEST_ASSERT(waitServer(Test::managementUrl, true)); for (int i = 0; i < 5; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERT(client.writePoint(*p)); delete p; } TEST_ASSERT(client.isBufferEmpty()); String query = "select"; FluxQueryResult q = client.query(query); int count = countLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERTM( count == 5, String(count) + " vs 5"); //5 points // test precision for (int i = (int)WritePrecision::NoTime; i <= (int)WritePrecision::NS; i++) { client.setWriteOptions((WritePrecision)i, 1); Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERTM(client.writePoint(*p), String("i=") + i); delete p; } TEST_END(); deleteAll(Test::apiUrl); } void Test::testInit() { TEST_INIT("testInit"); { InfluxDBClient client; TEST_ASSERT(!client.validateConnection()); TEST_ASSERT(client.getLastStatusCode() == 0); TEST_ASSERT(client.getLastErrorMessage() == "Invalid parameters"); } { InfluxDBClient client; String rec = "a,a=1 a=3"; TEST_ASSERT(!client.writeRecord(rec)); TEST_ASSERT(client.getLastStatusCode() == 0); TEST_ASSERT(client.getLastErrorMessage() == "Invalid parameters"); } { InfluxDBClient client; String query = "select"; FluxQueryResult q = client.query(query); TEST_ASSERT(!q.next()); TEST_ASSERT(q.getError() == "Invalid parameters"); TEST_ASSERT(client.getLastStatusCode() == 0); TEST_ASSERT(client.getLastErrorMessage() == "Invalid parameters"); client.setConnectionParams(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); String rec = "a,a=1 a=3"; TEST_ASSERT(client.writeRecord(rec)); q = client.query(query); TEST_ASSERT(countLines(q) == 1); TEST_ASSERTM(q.getError()=="", q.getError()); } TEST_END(); deleteAll(Test::apiUrl); } void Test::testUserAgent() { TEST_INIT("testUserAgent"); InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); waitServer(Test::managementUrl, true); TEST_ASSERT(client.validateConnection()); String url = String(Test::apiUrl) + "/test/user-agent"; WiFiClient wifiClient; HTTPClient http; TEST_ASSERT(http.begin(wifiClient, url)); TEST_ASSERT(http.GET() == 200); String agent = "influxdb-client-arduino/" INFLUXDB_CLIENT_VERSION " (" INFLUXDB_CLIENT_PLATFORM " " INFLUXDB_CLIENT_PLATFORM_VERSION ")"; String data = http.getString(); TEST_ASSERTM(data == agent, data); http.end(); TEST_END(); } void Test::testHTTPReadTimeout() { TEST_INIT("testHTTPReadTimeout"); InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); waitServer(Test::managementUrl, true); TEST_ASSERT(client.validateConnection()); //set server delay on query for 6s (client has default timeout 5s) String rec = "a,direction=timeout,timeout=6 a=1"; TEST_ASSERT(client.writeRecord(rec)); rec = "a,tag=a, a=1i"; TEST_ASSERT(client.writeRecord(rec)); String query = "select"; FluxQueryResult q = client.query(query); // should timeout TEST_ASSERT(!q.next()); TEST_ASSERTM(q.getError() == "read Timeout", q.getError()); q.close(); rec = "a,direction=timeout,timeout=4 a=1"; TEST_ASSERT(client.writeRecord(rec)); q = client.query(query); // should be ok TEST_ASSERTM(q.next(), q.getError()); TEST_ASSERT(!q.next()); TEST_ASSERTM(q.getError() == "", q.getError()); q.close(); TEST_END(); deleteAll(Test::apiUrl); } void Test::testRepeatedInit() { // test for validation repeated re-init and not leaking wificlient TEST_INIT("testRepeatedInit"); waitServer(Test::managementUrl, true); uint32_t startRAM = ESP.getFreeHeap(); do { InfluxDBClient client; for(int i = 0; i<20;i++) { client.setConnectionParams(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); TEST_ASSERTM(client.validateConnection(),client.getLastErrorMessage()); } } while(0); uint32_t endRAM = ESP.getFreeHeap(); long diff = endRAM-startRAM; TEST_ASSERTM(diff>-300,String(diff)); TEST_END(); } void Test::testRetryOnFailedConnection() { TEST_INIT("testRetryOnFailedConnection"); InfluxDBClient clientOk(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); clientOk.setWriteOptions(WriteOptions().batchSize(1).bufferSize(5)); waitServer(Test::managementUrl, true); TEST_ASSERT(clientOk.validateConnection()); Point *p = createPoint("test1"); TEST_ASSERT(clientOk.writePoint(*p)); delete p; p = createPoint("test1"); TEST_ASSERT(clientOk.writePoint(*p)); delete p; TEST_ASSERT(clientOk.isBufferEmpty()); clientOk.setHTTPOptions(HTTPOptions().httpReadTimeout(500)); Serial.println("Stop server!"); waitServer(Test::managementUrl, false); TEST_ASSERT(!clientOk.validateConnection()); TEST_ASSERTM(clientOk._retryTime == 0, String(clientOk._retryTime)); p = createPoint("test1"); TEST_ASSERT(!clientOk.writePoint(*p)); TEST_ASSERTM(clientOk._retryTime == 0, String(clientOk._retryTime)); delete p; p = createPoint("test1"); TEST_ASSERT(!clientOk.writePoint(*p)); TEST_ASSERTM(clientOk._retryTime == 0, String(clientOk._retryTime)); delete p; Serial.println("Start server!"); waitServer(Test::managementUrl, true); clientOk.setHTTPOptions(HTTPOptions().httpReadTimeout(5000)); TEST_ASSERT(clientOk.validateConnection()); p = createPoint("test1"); TEST_ASSERT(clientOk.writePoint(*p)); TEST_ASSERTM(clientOk._retryTime == 0, String(clientOk._retryTime)); delete p; TEST_ASSERT(clientOk.isBufferEmpty()); String query = "select"; FluxQueryResult q = clientOk.query(query); TEST_ASSERT(countLines(q) == 3); TEST_END(); deleteAll(Test::apiUrl); } void Test::testRetryOnFailedConnectionWithFlush() { TEST_INIT("testRetryOnFailedConnectionWithFlush"); InfluxDBClient clientOk(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); clientOk.setWriteOptions(WriteOptions().batchSize(2).bufferSize(2).retryInterval(4)); waitServer(Test::managementUrl, true); TEST_ASSERT(clientOk.validateConnection()); Point *p = createPoint("test1"); TEST_ASSERT(clientOk.writePoint(*p)); delete p; TEST_ASSERT(clientOk.flushBuffer()); TEST_ASSERT(clientOk.isBufferEmpty()); clientOk.setHTTPOptions(HTTPOptions().httpReadTimeout(500)); Serial.println("Stop server!"); waitServer(Test::managementUrl, false); // test dropping batch on max retry count TEST_ASSERT(!clientOk.validateConnection()); p = createPoint("test1"); TEST_ASSERT(clientOk.writePoint(*p)); delete p; Serial.print(millis()/1000.0f,3); Serial.println(" Write 1"); TEST_ASSERT(!clientOk.flushBuffer()); TEST_ASSERT(!clientOk.isBufferEmpty()); Serial.println(clientOk.getLastErrorMessage()); Serial.print(millis()/1000.0f,3); Serial.println(" Write 2"); TEST_ASSERT(!clientOk.flushBuffer()); TEST_ASSERT(!clientOk.isBufferEmpty()); Serial.println(clientOk.getLastErrorMessage()); Serial.print(millis()/1000.0f,3); Serial.println(" Write 3"); TEST_ASSERT(!clientOk.flushBuffer()); TEST_ASSERT(!clientOk.isBufferEmpty()); Serial.println(clientOk.getLastErrorMessage()); Serial.println("Start server!"); waitServer(Test::managementUrl, true); clientOk.setHTTPOptions(HTTPOptions().httpReadTimeout(5000)); TEST_ASSERT(clientOk.validateConnection()); Serial.print(millis()/1000.0f,3); Serial.println(" Write 4"); p = createPoint("test1"); TEST_ASSERT(clientOk.writePoint(*p)); delete p; TEST_ASSERT(clientOk.flushBuffer()); TEST_ASSERT(clientOk.isBufferEmpty()); Serial.print(millis()/1000.0f,3); Serial.println(" Write 5"); p = createPoint("test1"); TEST_ASSERT(clientOk.writePoint(*p)); delete p; TEST_ASSERT(clientOk.flushBuffer()); TEST_ASSERT(clientOk.isBufferEmpty()); String query = "select"; FluxQueryResult q = clientOk.query(query); TEST_ASSERT(countLines(q) == 3); TEST_END(); deleteAll(Test::apiUrl); } void Test::testBufferOverwriteBatchsize1() { TEST_INIT("testBufferOverwriteBatchsize1"); InfluxDBClient client(INFLUXDB_CLIENT_TESTING_BAD_URL, Test::orgName, Test::bucketName, Test::token); client.setWriteOptions(WriteOptions().batchSize(1).bufferSize(5)); client.setHTTPOptions(HTTPOptions().httpReadTimeout(500)); TEST_ASSERT(!client.validateConnection()); for (int i = 0; i < 12; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERT(!client.writePoint(*p)); delete p; } TEST_ASSERT(client.isBufferFull()); TEST_ASSERTM(strstr(client._writeBuffer[0]->buffer[0], "index=10i"), client._writeBuffer[0]->buffer[0]); setServerUrl(client,Test::apiUrl ); waitServer(Test::managementUrl, true); client.setHTTPOptions(HTTPOptions().httpReadTimeout(5000)); Point *p = createPoint("test1"); p->addField("index", 12); TEST_ASSERTM(client.writePoint(*p), client.getLastErrorMessage()); TEST_ASSERT(client.isBufferEmpty()); String query = "select"; FluxQueryResult q = client.query(query); std::vector lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERTM(lines.size() == 5, String("5 != " + lines.size())); //5 points TEST_ASSERTM(lines[0].indexOf(",8") > 0, lines[0]); TEST_ASSERTM(lines[1].indexOf(",9") > 0, lines[1]); TEST_ASSERTM(lines[2].indexOf(",10") > 0, lines[2]); TEST_ASSERTM(lines[3].indexOf(",11") > 0, lines[3]); TEST_ASSERTM(lines[4].indexOf(",12") > 0, lines[4]); TEST_END(); deleteAll(Test::apiUrl); } void Test::testBufferOverwriteBatchsize5() { TEST_INIT("testBufferOverwriteBatchsize5"); InfluxDBClient client(INFLUXDB_CLIENT_TESTING_BAD_URL, Test::orgName, Test::bucketName, Test::token); client.setWriteOptions(WriteOptions().batchSize(5).bufferSize(20)); client.setHTTPOptions(HTTPOptions().httpReadTimeout(500)); TEST_ASSERT(!client.validateConnection()); for (int i = 0; i < 39; i++) { Point *p = createPoint("test1"); p->addField("index", i); //will succeed only first batchsize-1 points TEST_ASSERTM(client.writePoint(*p) == (i < 4), String("i=") + i); delete p; } TEST_ASSERT(client.isBufferFull()); TEST_ASSERTM(strstr(client._writeBuffer[0]->buffer[0], "index=20i"), client._writeBuffer[0]->buffer[0]); setServerUrl(client,Test::apiUrl ); waitServer(Test::managementUrl, true); client.setHTTPOptions(HTTPOptions().httpReadTimeout(5000)); Point *p = createPoint("test1"); p->addField("index", 39); TEST_ASSERTM(client.writePoint(*p), client.getLastErrorMessage()); TEST_ASSERT(client.isBufferEmpty()); //flushing of empty buffer is ok TEST_ASSERT(client.flushBuffer()); String query = "select"; FluxQueryResult q = client.query(query); std::vector lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERTM(lines.size() == 20,String(lines.size())); //20 points (4 batches) TEST_ASSERTM(lines[0].indexOf(",20") > 0,lines[0]); TEST_ASSERTM(lines[1].indexOf(",21") > 0,lines[1]); TEST_ASSERTM(lines[2].indexOf(",22") > 0,lines[2]); TEST_ASSERTM(lines[3].indexOf(",23") > 0,lines[3]); TEST_ASSERTM(lines[4].indexOf(",24") > 0,lines[4]); TEST_ASSERTM(lines[19].indexOf(",39") > 0,lines[9]); deleteAll(Test::apiUrl); // buffer has been emptied, now writes should go according batch size for (int i = 0; i < 4; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERT(client.writePoint(*p)); delete p; } TEST_ASSERT(!client.isBufferEmpty()); q = client.query(query); TEST_ASSERT(countLines(q) == 0); TEST_ASSERTM(q.getError()=="", q.getError()); p = createPoint("test1"); p->addField("index", 4); TEST_ASSERT(client.writePoint(*p)); TEST_ASSERT(client.isBufferEmpty()); q = client.query(query); lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(lines.size() == 5); TEST_ASSERT(lines[0].indexOf(",0") > 0); TEST_ASSERT(lines[1].indexOf(",1") > 0); TEST_ASSERT(lines[2].indexOf(",2") > 0); TEST_ASSERT(lines[3].indexOf(",3") > 0); TEST_ASSERT(lines[4].indexOf(",4") > 0); TEST_END(); deleteAll(Test::apiUrl); } void Test::testServerTempDownBatchsize5() { TEST_INIT("testServerTempDownBatchsize5"); InfluxDBClient client; client.setConnectionParams(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); client.setWriteOptions(WriteOptions().batchSize(5).bufferSize(20).flushInterval(60)); client.setHTTPOptions(HTTPOptions().connectionReuse(true)); waitServer(Test::managementUrl, true); TEST_ASSERT(client.validateConnection()); for (int i = 0; i < 15; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERTM(client.writePoint(*p), String("i=") + i); delete p; } TEST_ASSERT(client.isBufferEmpty()); String query = "select"; FluxQueryResult q = client.query(query); TEST_ASSERT(countLines(q) == 15); TEST_ASSERTM(q.getError()=="", q.getError()); deleteAll(Test::apiUrl); Serial.println("Stop server"); TEST_ASSERT(waitServer(Test::managementUrl, false)); TEST_ASSERT(!client.validateConnection()); client.setHTTPOptions(HTTPOptions().httpReadTimeout(500)); for (int i = 0; i < 14; i++) { Point *p = createPoint("test1"); p->addField("index", i); //will succeed only first batchsize-1 points TEST_ASSERTM(client.writePoint(*p) == (i < 4), String("i=") + i); delete p; } TEST_ASSERT(!client.isBufferEmpty()); Serial.println("Start server"); ; TEST_ASSERT(waitServer(Test::managementUrl, true)); client.setHTTPOptions(HTTPOptions().httpReadTimeout(5000)); Point *p = createPoint("test1"); p->addField("index", 14); TEST_ASSERT(client.writePoint(*p)); TEST_ASSERT(client.isBufferEmpty()); q = client.query(query); TEST_ASSERT(countLines(q) == 15); TEST_ASSERTM(q.getError()=="", q.getError()); deleteAll(Test::apiUrl); Serial.println("Stop server"); waitServer(Test::managementUrl, false); client.setHTTPOptions(HTTPOptions().httpReadTimeout(500)); for (int i = 0; i < 25; i++) { Point *p = createPoint("test1"); p->addField("index", i); //will succeed only first batchsize-1 points TEST_ASSERTM(client.writePoint(*p) == (i < 4), String("i=") + i); delete p; } TEST_ASSERT(client.isBufferFull()); Serial.println("Start server"); ; waitServer(Test::managementUrl, true); client.setHTTPOptions(HTTPOptions().httpReadTimeout(5000)); TEST_ASSERT(client.flushBuffer()); q = client.query(query); std::vector lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(lines.size() == 20); TEST_ASSERT(lines[0].indexOf(",5") > 0); TEST_ASSERT(lines[1].indexOf(",6") > 0); TEST_ASSERT(lines[2].indexOf(",7") > 0); TEST_ASSERT(lines[3].indexOf(",8") > 0); TEST_ASSERT(lines[18].indexOf(",23") > 0); TEST_ASSERT(lines[19].indexOf(",24") > 0); deleteAll(Test::apiUrl); TEST_END(); deleteAll(Test::apiUrl); } void Test::testRetriesOnServerOverload() { TEST_INIT("testRetriesOnServerOverload"); InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); client.setWriteOptions(WriteOptions().batchSize(5).bufferSize(20).flushInterval(60)); waitServer(Test::managementUrl, true); TEST_ASSERT(client.validateConnection()); for (int i = 0; i < 60; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERTM(client.writePoint(*p), String("i=") + i); delete p; } TEST_ASSERT(client.isBufferEmpty()); String query = "select"; FluxQueryResult q = client.query(query); TEST_ASSERT(countLines(q) == 60); TEST_ASSERTM(q.getError()=="", q.getError()); deleteAll(Test::apiUrl); String rec = "a,direction=429-1 a=1"; TEST_ASSERT(client.writeRecord(rec)); TEST_ASSERT(!client.flushBuffer()); client.resetBuffer(); uint32_t start = millis(); uint32_t retryDelay = 10; for (int i = 0; i < 52; i++) { Point *p = createPoint("test1"); p->addField("index", i); uint32_t dur = (millis() - start) / 1000; if (client.writePoint(*p)) { if (i >= 4) { TEST_ASSERTM(dur >= retryDelay, String("Too early write: ") + dur); } } else { TEST_ASSERTM(i >= 4, String("i=") + i); if (dur >= retryDelay) { TEST_ASSERTM(false, String("Write should be ok: ") + dur); } } delete p; delay(333); } TEST_ASSERT(!client.isBufferEmpty()); TEST_ASSERT(client.flushBuffer()); TEST_ASSERT(client.isBufferEmpty()); q = client.query(query); std::vector lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(lines.size() == 37); TEST_ASSERT(lines[0].indexOf(",15") > 0); TEST_ASSERT(lines[36].indexOf(",51") > 0); deleteAll(Test::apiUrl); // default retry rec = "a,direction=429-2 a=1"; TEST_ASSERT(client.writeRecord(rec)); TEST_ASSERT(!client.flushBuffer()); client.resetBuffer(); retryDelay = 5; start = millis(); for (int i = 0; i < 52; i++) { Point *p = createPoint("test1"); p->addField("index", i); uint32_t dur = (millis() - start) / 1000; if (client.writePoint(*p)) { if (i >= 4) { TEST_ASSERTM(dur >= retryDelay, String("Too early write: ") + dur); } } else { TEST_ASSERTM(i >= 4, String("i=") + i); if (dur >= retryDelay) { TEST_ASSERTM(false, String("Write should be ok: ") + dur); } } delete p; delay(162); } TEST_ASSERT(!client.isBufferEmpty()); TEST_ASSERT(client.flushBuffer()); TEST_ASSERT(client.isBufferEmpty()); q = client.query(query); lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(lines.size() == 37); TEST_ASSERT(lines[0].indexOf(",15") > 0); TEST_ASSERT(lines[36].indexOf(",51") > 0); deleteAll(Test::apiUrl); rec = "a,direction=503-1 a=1"; TEST_ASSERT(client.writeRecord(rec)); TEST_ASSERT(!client.flushBuffer()); client.resetBuffer(); retryDelay = 10; start = millis(); for (int i = 0; i < 52; i++) { Point *p = createPoint("test1"); p->addField("index", i); uint32_t dur = (millis() - start) / 1000; if (client.writePoint(*p)) { if (i >= 4) { TEST_ASSERTM(dur >= retryDelay, String("Too early write: ") + dur); } } else { TEST_ASSERTM(i >= 4, String("i=") + i); if (dur >= retryDelay) { TEST_ASSERTM(false, String("Write should be ok: ") + dur); } } delete p; delay(1000); } TEST_ASSERT(!client.isBufferEmpty()); TEST_ASSERT(client.flushBuffer()); TEST_ASSERT(client.isBufferEmpty()); q = client.query(query); lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(lines.size() == 52); TEST_ASSERT(lines[0].indexOf(",0") > 0); TEST_ASSERT(lines[51].indexOf(",51") > 0); deleteAll(Test::apiUrl); // default retry rec = "a,direction=503-2 a=1"; TEST_ASSERT(client.writeRecord(rec)); TEST_ASSERT(!client.flushBuffer()); client.resetBuffer(); retryDelay = 5; start = millis(); for (int i = 0; i < 52; i++) { Point *p = createPoint("test1"); p->addField("index", i); uint32_t dur = (millis() - start) / 1000; if (client.writePoint(*p)) { if (i >= 4) { TEST_ASSERTM(dur >= retryDelay, String("Too early write: ") + dur); } } else { TEST_ASSERTM(i >= 4, String("i=") + i); if (dur >= retryDelay) { TEST_ASSERTM(false, String("Write should be ok: ") + dur); } } delete p; delay(162); } TEST_ASSERT(!client.isBufferEmpty()); TEST_ASSERT(client.flushBuffer()); TEST_ASSERT(client.isBufferEmpty()); q = client.query(query); lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(lines.size() == 37); TEST_ASSERT(lines[0].indexOf(",15") > 0); TEST_ASSERT(lines[36].indexOf(",51") > 0); TEST_END(); deleteAll(Test::apiUrl); } void Test::testFailedWrites() { TEST_INIT("testFailedWrites"); InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); client.setWriteOptions(WriteOptions().batchSize(1).bufferSize(5)); //test with no batching TEST_ASSERT(client.validateConnection()); for (int i = 0; i < 20; i++) { Point *p = createPoint("test1"); if (!(i % 5)) { p->addTag("direction", "status"); p->addTag("x-code", i > 10 ? "404" : "320"); } p->addField("index", i); TEST_ASSERTM(client.writePoint(*p) == (i % 5 != 0), String("i=") + i + client.getLastErrorMessage()); delete p; } String query = ""; FluxQueryResult q = client.query(query); std::vector lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(lines.size() == 16); //12 points+header TEST_ASSERTM(lines[0].indexOf(",1") > 0, lines[0]); TEST_ASSERTM(lines[4].indexOf(",6") > 0, lines[4]); TEST_ASSERTM(lines[9].indexOf(",12") > 0, lines[9]); TEST_ASSERTM(lines[15].indexOf(",19") > 0, lines[15]); deleteAll(Test::apiUrl); //test with batching client.setWriteOptions(WritePrecision::NoTime, 5, 20); for (int i = 0; i < 30; i++) { Point *p = createPoint("test1"); if (!(i % 10)) { p->addTag("direction", "status"); p->addTag("x-code", i > 10 ? "404" : "320"); } p->addField("index", i); //i == 4,14,24 should fail TEST_ASSERTM(client.writePoint(*p) == ((i - 4) % 10 != 0), String("i=") + i); delete p; } q = client.query(query); lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); //3 batches should be skipped TEST_ASSERT(lines.size() == 15); //15 points+header TEST_ASSERTM(lines[0].indexOf(",5") > 0, lines[0]); TEST_ASSERTM(lines[5].indexOf(",15") > 0, lines[5]); TEST_ASSERTM(lines[10].indexOf(",25") > 0, lines[10]); TEST_END(); deleteAll(Test::apiUrl); } void Test::testTimestamp() { TEST_INIT("testTimestamp"); struct timeval tv; tv.tv_usec = 1234; tv.tv_sec = 5678; unsigned long long ts = getTimeStamp(&tv, 0); TEST_ASSERTM( ts == 5678, timeStampToString(ts)); ts = getTimeStamp(&tv, 3); TEST_ASSERTM( ts == 5678001, timeStampToString(ts)); ts = getTimeStamp(&tv, 6); TEST_ASSERTM( ts == 5678001234, timeStampToString(ts)); ts = getTimeStamp(&tv, 9); TEST_ASSERTM( ts == 5678001234000, timeStampToString(ts)); // Test increasing timestamp String prev = ""; for(int i = 0;i<2000;i++) { Point p("test"); p.setTime(WritePrecision::US); String act = p.getTime(); TEST_ASSERTM( i == 0 || prev < act, String(i) + ": " + prev + " vs " + act); prev = act; delayMicroseconds(100); } serverLog(Test::apiUrl, "testTimestamp"); InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); client.setWriteOptions(WritePrecision::S, 1, 5); waitServer(Test::managementUrl, true); //test with no batching TEST_ASSERT(client.validateConnection()); uint32_t timestamp; for (int i = 0; i < 20; i++) { Point *p = createPoint("test1"); timestamp = time(nullptr); switch (i % 4) { case 0: p->setTime(timestamp); break; case 1: { String ts = String(timestamp); p->setTime(ts); } break; case 2: p->setTime(WritePrecision::S); break; //let other be set automatically } p->addField("index", i); TEST_ASSERTM(client.writePoint(*p), String("i=") + i); delete p; } String query = ""; FluxQueryResult q = client.query(query); std::vector lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(lines.size() == 20); for (unsigned int i = 0; i < lines.size(); i++) { int partsCount; String *parts = getParts(lines[i], ',', partsCount); TEST_ASSERTM(partsCount == 11, String(i) + ":" + lines[i]); //1measurement,4tags,5fields, 1timestamp parts[10].trim(); TEST_ASSERTM(parts[10].length() == 10, String(i) + ":" + lines[i]); delete[] parts; } deleteAll(Test::apiUrl); client.setWriteOptions(WritePrecision::NoTime, 2, 5); //test with no batching for (int i = 0; i < 20; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERTM(client.writePoint(*p), String("i=") + i); delete p; } q = client.query(query); lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(lines.size() == 20); //20 points+header for (unsigned int i = 0; i < lines.size(); i++) { int partsCount; String *parts = getParts(lines[i], ',', partsCount); TEST_ASSERTM(partsCount == 10, String(i) + ":" + lines[i]); //1measurement,4tags,5fields delete[] parts; } TEST_END(); deleteAll(Test::apiUrl); serverLog(Test::apiUrl, "testTimestamp end"); } void Test::testTimestampAdjustment() { TEST_INIT("testTimestampAdjustment"); InfluxDBClient client; // test no client precision, but on point Point point("a"); point.setTime(WritePrecision::S); client.checkPrecisions(point); TEST_ASSERTM(point.getTime().endsWith("000000000"),point.getTime() ); point.setTime(WritePrecision::MS); client.checkPrecisions(point); TEST_ASSERTM(point.getTime().endsWith("000"),point.getTime() ); //test not modified ts point.setTime(WritePrecision::NS); String a = point.getTime(); client.checkPrecisions(point); TEST_ASSERTM(a == point.getTime(), point.getTime() ); // test client precision and not point client.setWriteOptions(WriteOptions().writePrecision(WritePrecision::S)); point.setTime(WritePrecision::NoTime); TEST_ASSERTM(!point.hasTime(), point.getTime() ); client.checkPrecisions(point); TEST_ASSERTM(point.getTime().length() == 10, point.getTime() ); // test cut point.setTime(WritePrecision::US); client.checkPrecisions(point); TEST_ASSERTM(point.getTime().length() == 10, point.getTime() ); // test extending client.setWriteOptions(WriteOptions().writePrecision(WritePrecision::US)); point.setTime(WritePrecision::S); client.checkPrecisions(point); TEST_ASSERTM(point.getTime().endsWith("000000"),point.getTime() ); TEST_END(); } void Test::testV1() { TEST_INIT("testV1"); InfluxDBClient client; client.setConnectionParamsV1(Test::apiUrl, Test::dbName, "user","my secret password"); client.setHTTPOptions(HTTPOptions().connectionReuse(true)); waitServer(Test::managementUrl, true); TEST_ASSERTM(client.validateConnection(), client.getLastErrorMessage()); //test with no batching for (int i = 0; i < 20; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERTM(client.writePoint(*p), String("i=") + i + client.getLastErrorMessage()); delete p; } String query = "select"; FluxQueryResult q = client.query(query); std::vector lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERTM(lines.size() == 20, String(lines.size()) + " vs 20"); deleteAll(Test::apiUrl); //test with w/ batching 5 client.setWriteOptions(WritePrecision::NoTime, 5); for (int i = 0; i < 15; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERTM(client.writePoint(*p), String("i=") + i + client.getLastErrorMessage()); delete p; } q = client.query(query); lines = getLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERTM(lines.size() == 15, String(lines.size())); // test precision for (int i = (int)WritePrecision::NoTime; i <= (int)WritePrecision::NS; i++) { client.setWriteOptions((WritePrecision)i, 1); Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERTM(client.writePoint(*p), String("i=") + i); delete p; } TEST_END(); deleteAll(Test::apiUrl); } void Test::testFluxTypes() { TEST_INIT("testFluxTypes"); FluxValue val1; TEST_ASSERTM(val1.isNull(),"val1.isNull"); TEST_ASSERTM(val1.getRawValue() == "","val1.getRawValue()"); TEST_ASSERTM(val1.getString() == "","val1.getString()"); FluxValue val2(new FluxLong("111", 111)); TEST_ASSERTM(!val2.isNull(),"!val2.isNull"); TEST_ASSERTM(val2.getLong() == 111,"val2.getLong"); TEST_ASSERTM(val2.getRawValue() == "111","val2.getRawValue"); TEST_ASSERTM(val2.getUnsignedLong() == 0,"val2.getUnsignedLong"); TEST_ASSERTM(val2.getString() == "","val2.getString()"); val1 = val2; TEST_ASSERTM(!val1.isNull(),"!val1.isNull"); TEST_ASSERTM(val1.getLong() == 111,"val1.getLong"); TEST_ASSERTM(val1.getRawValue() == "111","val1.getRawValue"); TEST_ASSERTM(val1.getString() == "","val1.getString()"); val2 = nullptr; TEST_ASSERTM(val2.isNull(),"val2.isNull"); TEST_ASSERTM(!val1.isNull(),"!val1.isNull"); TEST_ASSERTM(val1.getLong() == 111,"val1.getLong"); TEST_ASSERTM(val1.getRawValue() == "111","val1.getRawValue"); TEST_ASSERTM(val1.getString() == "","val1.getString()"); FluxValue val3(new FluxUnsignedLong("123456", 123456)); TEST_ASSERTM(!val3.isNull(),"!val3.isNull"); TEST_ASSERTM(val3.getUnsignedLong() == 123456,"val3.getUnsignedLong"); TEST_ASSERTM(val3.getRawValue() == "123456","val3.getRawValue"); TEST_ASSERTM(val3.getLong() == 0,"val3.getLong"); TEST_ASSERTM(val3.getString() == "","val3.getString()"); val2 = val3; TEST_ASSERTM(!val2.isNull(),"!val2.isNull"); TEST_ASSERTM(val2.getUnsignedLong() == 123456,"val2.getUnsignedLong"); TEST_ASSERTM(val2.getRawValue() == "123456","val2.getRawValue"); TEST_ASSERTM(val2.getLong() == 0,"val2.getLong"); FluxValue val4(new FluxDouble("12.14", 12.14)); TEST_ASSERTM(!val4.isNull(),"!val4.isNull"); TEST_ASSERTM(val4.getDouble() == 12.14,"val4.getDouble"); TEST_ASSERTM(val4.getLong() == 0,"val4.getLong"); TEST_ASSERTM(val4.getRawValue() == "12.14","val4.getRawValue"); TEST_ASSERTM(val4.getString() == "","val4.getString()"); FluxValue val5(new FluxBool("true", true)); TEST_ASSERTM(!val5.isNull(),"!val5.isNull"); TEST_ASSERTM(val5.getBool(),"val5.getBool"); TEST_ASSERTM(val5.getDouble() == 0.0,"val5.getDouble"); TEST_ASSERTM(val5.getLong() == 0,"val45getLong"); TEST_ASSERTM(val5.getRawValue() == "true","val5.getRawValue"); TEST_ASSERTM(val5.getString() == "","val5.getString()"); FluxValue val6(new FluxDateTime("2020-05-21T09:34:15.1234Z", FluxDatatypeDatetimeRFC3339, {15,34,9,21,4,120,0,0,0}, 123400)); TEST_ASSERTM(!val6.isNull(),"!val6.isNull"); TEST_ASSERTM(!val6.getBool(),"val6.getBool"); TEST_ASSERTM(val6.getLong() == 0,"val6.getLong"); TEST_ASSERTM(val6.getRawValue() == "2020-05-21T09:34:15.1234Z","val6.getRawValue"); TEST_ASSERTM(val6.getString() == "","val6.getString()"); struct tm t1 = {15,34,9,21,4,120,0,0,0}; struct tm tx = val6.getDateTime().value; TEST_ASSERTM(compareTm(tx,t1), "val6.getDateTime().value"); TEST_ASSERTM(val6.getDateTime().microseconds == 123400,"val6.getDateTime().microseconds"); String dtStr = val6.getDateTime().format("%F %T"); TEST_ASSERTM(dtStr == "2020-05-21 09:34:15",dtStr); FluxValue val7(new FluxDateTime("2020-05-22T09:34:15.123456Z", FluxDatatypeDatetimeRFC3339Nano, {15,34,9,22,4,120,0,0,0}, 123456)); TEST_ASSERTM(!val7.isNull(),"!val7.isNull"); TEST_ASSERTM(!val7.getBool(),"val7.getBool"); TEST_ASSERTM(val7.getLong() == 0,"val7.getLong"); TEST_ASSERTM(val7.getRawValue() == "2020-05-22T09:34:15.123456Z","val7.getRawValue"); TEST_ASSERTM(val7.getString() == "","val7.getString()"); struct tm t2 = {15,34,9,22,4,120,0,0,0}; tx = val7.getDateTime().value; TEST_ASSERTM(compareTm(tx,t2), "val7.getDateTime().value"); TEST_ASSERTM(val7.getDateTime().microseconds == 123456,"val7.getDateTime().microseconds"); FluxValue val8(new FluxString("test string", FluxDatatypeString)); TEST_ASSERTM(!val8.isNull(),"!val8.isNull"); TEST_ASSERTM(!val8.getBool(),"val8.getBool"); TEST_ASSERTM(val8.getLong() == 0,"val8.getLong"); TEST_ASSERTM(val8.getRawValue() == "test string","val8.getRawValue"); TEST_ASSERTM(val8.getString() == "test string","val8.getString()"); FluxValue val9(new FluxString("1h4m5s", FluxDatatypeDuration)); TEST_ASSERTM(!val9.isNull(),"!val9.isNull"); TEST_ASSERTM(!val9.getBool(),"val9.getBool"); TEST_ASSERTM(val9.getLong() == 0,"val9.getLong"); TEST_ASSERTM(val9.getRawValue() == "1h4m5s","val9.getRawValue"); TEST_ASSERTM(val9.getString() == "1h4m5s","val9.getString()"); FluxValue val10(new FluxString("ZGF0YWluYmFzZTY0", FluxBinaryDataTypeBase64)); TEST_ASSERTM(!val10.isNull(),"!val10.isNull"); TEST_ASSERTM(!val10.getBool(),"val10.getBool"); TEST_ASSERTM(val10.getLong() == 0,"val10.getLong"); TEST_ASSERTM(val10.getRawValue() == "ZGF0YWluYmFzZTY0","val10.getRawValue"); TEST_ASSERTM(val10.getString() == "ZGF0YWluYmFzZTY0","val10.getString()"); TEST_END(); } void Test::testFluxTypesSerialization() { TEST_INIT("testFluxTypesSerialization"); struct strTest { FluxBase *fb; const char *json; }; strTest tests[] = { { new FluxLong("long", -2020123456), "\"long\":-2020123456" }, { new FluxUnsignedLong("ulong", 2020123456), "\"ulong\":2020123456" }, { new FluxBool("bool", false), "\"bool\":false"}, { new FluxDouble("double", 28.3, 1), "\"double\":28.3"}, { new FluxDateTime("dateTime", FluxDatatypeDatetimeRFC3339Nano, {15,34,9,22,4,120,0,0,0}, 123456), "\"dateTime\":\"2020-05-22T09:34:15.123456Z\""}, { new FluxString("string", "my text", FluxDatatypeString), "\"string\":\"my text\""}, { new FluxDouble("double", 21328.3132213,5), "\"double\":21328.31322"} }; for(int i=0;i<7;i++) { char *buff = tests[i].fb->jsonString(); delete tests[i].fb; String json = buff; delete [] buff; TEST_ASSERTM(json == tests[i].json , json); } TEST_END(); } void Test::testQueryParams() { TEST_INIT("testQueryParams"); QueryParams params; TEST_ASSERT(params.size() == 0); params .add("long", -2020123456l) .add("ulong", 2020123456) .add("bool", false) .add("double", 28.3, 1) .add("dateTime", {15,34,9,22,4,120,0,0,0}, 123456) .add("string", "my text"); TEST_ASSERT(params.size() == 6); const char *jsons[] = { "\"long\":-2020123456", "\"ulong\":2020123456", "\"bool\":false", "\"double\":28.3", "\"dateTime\":\"2020-05-22T09:34:15.123456Z\"", "\"string\":\"my text\"" }; for(int i=0;igetRawValue() == "dateTime"); QueryParams params2; params2.add("char", '1'); params2.add("uchar", (unsigned char)1); params2.add(String("int"), -1); params2.add(F("uint"), 1u); params2.add("long", -1l); params2.add("ulong", 1lu); params2.add("longlong", -1ll); params2.add("ulonglong", 1llu); params2.add("float", 1.1f); params2.add("double", 1.1); params2.add("bool", true); params2.add("cstring", "text"); params2.add(F("fstring"), F("text")); params2.add("dateTime", {15,34,9,22,4,120,0,0,0}); String s = "string"; params2.add("string", s); TEST_ASSERT(params2.size() == 15); const char *types[] = { FluxDatatypeString, FluxDatatypeUnsignedLong, FluxDatatypeLong, FluxDatatypeUnsignedLong, FluxDatatypeLong, FluxDatatypeUnsignedLong, FluxDatatypeLong, FluxDatatypeUnsignedLong, FluxDatatypeDouble, FluxDatatypeDouble, FluxDatatypeBool, FluxDatatypeString, FluxDatatypeString, FluxDatatypeDatetimeRFC3339Nano, FluxDatatypeString }; for(int i=0;igetType() == types[i], String(i) + " " + params2.get(i)->getType()); } TEST_END(); } void Test::testFluxParserEmpty() { TEST_INIT("testFluxParserEmpty"); FluxQueryResult flux("Error sss"); TEST_ASSERTM(!flux.next(),"!flux.next()"); TEST_ASSERTM(flux.getError() == "Error sss","flux.getError"); TEST_ASSERTM(flux.getValues().size() == 0,"flux.getValues().size()"); TEST_ASSERTM(flux.getColumnsDatatype().size() == 0,"flux.getColumnsDatatype().size()"); TEST_ASSERTM(flux.getColumnsName().size() == 0,"flux.getColumnsName().size()"); TEST_ASSERTM(flux.getValueByIndex(0).isNull(),"flux.getValueByIndex(0).isNull()"); TEST_ASSERTM(!flux.hasTableChanged(),"hasTableChanged"); TEST_ASSERTM(flux.getTablePosition()==-1,"getTablePosition"); TEST_ASSERTM(flux.getValueByName("xxx").isNull(),"flux.getValueByName(\"xxx\").isNull()"); flux.close(); // test unitialized InfluxDBClient client; flux = client.query("s"); TEST_ASSERTM(!flux.next(),"!flux.next()"); TEST_ASSERTM(flux.getError() == "Invalid parameters",flux.getError()); flux.close(); //test empty results set InfluxDBClient client2(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); TEST_ASSERT(waitServer(Test::managementUrl,true)); flux = client2.query("testquery-empty"); TEST_ASSERTM(!flux.next(),"flux.next()"); TEST_ASSERTM(flux.getError() == "",flux.getError()); flux.close(); TEST_END(); } bool testFluxDateTimeValue(FluxQueryResult flux, int columnIndex, const char *columnName, const char *rawValue, tm time, unsigned long us) { do { TEST_ASSERTM(flux.getValueByIndex(columnIndex).getRawValue() == rawValue, flux.getValueByName(columnName).getRawValue()); FluxDateTime dt = flux.getValueByIndex(columnIndex).getDateTime(); TEST_ASSERTM(compareTm(time, dt.value), flux.getValueByIndex(columnIndex).getRawValue()); TEST_ASSERTM(dt.microseconds == us, String(dt.microseconds) + " vs " + String(us)); dt = flux.getValueByName(columnName).getDateTime(); TEST_ASSERTM(compareTm(time, dt.value), flux.getValueByName(columnName).getRawValue()); TEST_ASSERTM(dt.microseconds == us, String(dt.microseconds) + " vs " + String(us)); return true; } while(0); end: return false; } bool testStringValue(FluxQueryResult flux, int columnIndex, const char *columnName, const char *rawValue) { do { TEST_ASSERTM(flux.getValueByIndex(columnIndex).getString() == rawValue, flux.getValueByIndex(columnIndex).getString()); TEST_ASSERTM(flux.getValueByName(columnName).getString() == rawValue, flux.getValueByName(columnName).getString()); TEST_ASSERTM(flux.getValueByName(columnName).getRawValue() == rawValue, flux.getValueByName(columnName).getRawValue()); return true; } while(0); end: return false; } bool testStringVector(std::vector vect, const char *values[], unsigned int size) { do { TEST_ASSERTM(vect.size() == size, String(vect.size())); for(unsigned int i=0;iretryCount == 1, String(client._writeBuffer[0]->retryCount)); delay(2000); rec = "test1,direction=permanent-unset,SSID=bonitoo.io,device_name=ESP32,device_id=4272205360 temperature=28.60,humidity=86i,code=69i,door=false,status=\"failed\",index=2"; TEST_ASSERT(!client.writeRecord(rec)); TEST_ASSERT(!client.canSendRequest()); TEST_ASSERTM(client._retryTime == 4, String(client._retryTime)); TEST_ASSERTM(client._writeBuffer[0]->retryCount == 2, String(client._writeBuffer[0]->retryCount)); delay(4000); rec = "test1,SSID=bonitoo.io,device_name=ESP32,device_id=4272205360 temperature=28.60,humidity=86i,code=69i,door=false,status=\"failed\",index=3"; TEST_ASSERT(!client.writeRecord(rec)); TEST_ASSERT(!client.canSendRequest()); TEST_ASSERTM(client._retryTime == 8, String(client._retryTime)); TEST_ASSERTM(client._writeBuffer[0]->retryCount == 3, String(client._writeBuffer[0]->retryCount)); delay(8000); rec = "test1,SSID=bonitoo.io,device_name=ESP32,device_id=4272205360 temperature=28.60,humidity=86i,code=69i,door=false,status=\"failed\",index=4"; TEST_ASSERT(!client.writeRecord(rec)); TEST_ASSERT(!client.canSendRequest()); TEST_ASSERTM(client._retryTime == 2, String(client._retryTime)); TEST_ASSERT(!client._writeBuffer[0]); TEST_ASSERTM(client._writeBuffer[1]->retryCount == 0, String(client._writeBuffer[1]->retryCount)); delay(2000); rec = "test1,SSID=bonitoo.io,device_name=ESP32,device_id=4272205360 temperature=28.60,humidity=86i,code=69i,door=false,status=\"failed\",index=5"; TEST_ASSERT(!client.writeRecord(rec)); TEST_ASSERT(!client.canSendRequest()); TEST_ASSERTM(client._retryTime == 2, String(client._retryTime)); TEST_ASSERT(!client._writeBuffer[0]); TEST_ASSERTM(client._writeBuffer[1]->retryCount == 1, String(client._writeBuffer[1]->retryCount)); delay(2000); TEST_ASSERT(client.canSendRequest()); TEST_ASSERTM(client.flushBuffer(), client.getLastErrorMessage()); TEST_ASSERT(client.isBufferEmpty()); TEST_ASSERT(!client.isBufferFull()); String query = "select"; FluxQueryResult q = client.query(query); TEST_ASSERT(countLines(q) == 3); //point with the direction tag is skipped TEST_ASSERTM(q.getError()=="", q.getError()); TEST_END(); deleteAll(Test::apiUrl); } void Test::testDefaultTags() { TEST_INIT("testDefaultTags"); InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); Point pt("test"); pt.addTag("tag1", "tagvalue"); pt.addField("fieldInt", -23); String testLine = "test,tag1=tagvalue fieldInt=-23i"; String line = client.pointToLineProtocol(pt); TEST_ASSERTM(line == testLine, line); TEST_ASSERT(waitServer(Test::managementUrl, true)); for (int i = 0; i < 5; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERT(client.writePoint(*p)); delete p; } String query = "select"; FluxQueryResult q = client.query(query); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(q.next()); TEST_ASSERTM(q.getColumnsName().size()==10,String(q.getColumnsName().size())); TEST_ASSERT(q.next()); TEST_ASSERT(q.next()); TEST_ASSERT(q.next()); TEST_ASSERTM(q.getColumnsName().size()==10,String(q.getColumnsName().size())) ; TEST_ASSERT(q.next()); TEST_ASSERT(!q.next()); q.close(); deleteAll(Test::apiUrl); client.setWriteOptions(WriteOptions().addDefaultTag("dtag1","dval1").addDefaultTag("dtag2","dval2")); testLine = "test,dtag1=dval1,dtag2=dval2,tag1=tagvalue fieldInt=-23i"; line = client.pointToLineProtocol(pt); TEST_ASSERTM(line == testLine, line); for (int i = 0; i < 5; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERT(client.writePoint(*p)); delete p; } q = client.query(query); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERT(q.next()); TEST_ASSERTM(q.getColumnsName().size()==12,String(q.getColumnsName().size())); TEST_ASSERTM(q.getValueByName("dtag1").getString() == "dval1", q.getValueByName("dtag1").getString()); TEST_ASSERTM(q.getValueByName("dtag2").getString() == "dval2", q.getValueByName("dtag2").getString()); TEST_ASSERT(q.next()); TEST_ASSERTM(q.getValueByName("dtag1").getString() == "dval1",q.getValueByName("dtag1").getString()); TEST_ASSERTM(q.getValueByName("dtag2").getString() == "dval2", q.getValueByName("dtag2").getString()); TEST_ASSERT(q.next()); TEST_ASSERTM(q.getValueByName("dtag1").getString() == "dval1",q.getValueByName("dtag1").getString()); TEST_ASSERTM(q.getValueByName("dtag2").getString() == "dval2", q.getValueByName("dtag2").getString()); TEST_ASSERT(q.next()); TEST_ASSERTM(q.getColumnsName().size()==12,String(q.getColumnsName().size())) ; TEST_ASSERTM(q.getValueByName("dtag1").getString() == "dval1",q.getValueByName("dtag1").getString()); TEST_ASSERTM(q.getValueByName("dtag2").getString() == "dval2", q.getValueByName("dtag2").getString()); TEST_ASSERT(q.next()); TEST_ASSERTM(q.getValueByName("dtag1").getString() == "dval1",q.getValueByName("dtag1").getString()); TEST_ASSERTM(q.getValueByName("dtag2").getString() == "dval2", q.getValueByName("dtag2").getString()); TEST_ASSERT(!q.next()); q.close(); TEST_END(); deleteAll(Test::apiUrl); } void Test::testUrlEncode() { TEST_INIT("testUrlEncode"); String res = "my%20%5Bsecret%5D%20pass%3A%2F%5Cw%60o%5Er%25d"; String urlEnc = urlEncode("my [secret] pass:/\\w`o^r%d"); TEST_ASSERTM(res == urlEnc, urlEnc); TEST_END(); } void Test::testIsValidID() { TEST_INIT("testIsValidID"); TEST_ASSERT(isValidID("0123456789abcdef")); TEST_ASSERT(isValidID("0000000000000000")); TEST_ASSERT(isValidID("9999999999999999")); TEST_ASSERT(isValidID("aaaaaaaaaaaaaaaa")); TEST_ASSERT(isValidID("ffffffffffffffff")); TEST_ASSERT(!isValidID("w123456789abcdef")); TEST_ASSERT(!isValidID("ffffffffffffffffa")); TEST_ASSERT(!isValidID("ffffffffffffffa")); TEST_ASSERT(!isValidID("ffffffff-fffffff")); TEST_END(); } void Test::testBuckets() { TEST_INIT("testBuckets"); Bucket emptyb; TEST_ASSERT(emptyb.isNull()); TEST_ASSERT(!emptyb); TEST_ASSERT(emptyb.getID() == nullptr); TEST_ASSERT(emptyb.getName() == nullptr); TEST_ASSERT(emptyb.getExpire() == 0); BucketsClient emptybs; TEST_ASSERT(emptybs.isNull()); TEST_ASSERT(!emptybs); TEST_ASSERT(emptybs.getOrgID("o") == ""); TEST_ASSERT(emptybs.createBucket("a").isNull()); TEST_ASSERT(emptybs.findBucket("a").isNull()); TEST_ASSERT(!emptybs.checkBucketExists("a")); TEST_ASSERT(!emptybs.deleteBucket("a")); InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); BucketsClient buckets = client.getBucketsClient(); TEST_ASSERT(!buckets.isNull()); emptybs = buckets; TEST_ASSERT(!emptybs.isNull()); TEST_ASSERT(emptybs); TEST_ASSERT(waitServer(Test::managementUrl, true)); String id = buckets.getOrgID("my-org"); TEST_ASSERTM( id == "e2e2d84ffb3c4f85", id.length()?id:buckets.getLastErrorMessage()); id = buckets.getOrgID("org"); TEST_ASSERT( id == ""); TEST_ASSERT(!buckets.checkBucketExists("bucket-1")); Bucket b = buckets.createBucket("bucket-1"); TEST_ASSERTM(!b.isNull(), buckets.getLastErrorMessage()); TEST_ASSERTM(isValidID(b.getID()), b.getID()); TEST_ASSERTM(!strcmp(b.getName(), "bucket-1"), b.getName()); TEST_ASSERTM(b.getExpire() == 0, String(b.getExpire())); emptyb = b; TEST_ASSERT(!emptyb.isNull()); TEST_ASSERT(emptyb); TEST_ASSERTM(isValidID(emptyb.getID()), emptyb.getID()); TEST_ASSERTM(!strcmp(emptyb.getName(), "bucket-1"), emptyb.getName()); TEST_ASSERTM(emptyb.getExpire() == 0, String(emptyb.getExpire())); TEST_ASSERT(buckets.checkBucketExists("bucket-1")); TEST_ASSERT(buckets.deleteBucket(b.getID())); TEST_ASSERT(!buckets.checkBucketExists("bucket-1")); TEST_ASSERT(!buckets.deleteBucket("bucket-1")); uint32_t monthSec = 3600*24*30; b = buckets.createBucket("bucket-2", monthSec); TEST_ASSERTM(!b.isNull(), buckets.getLastErrorMessage()); TEST_ASSERT(buckets.checkBucketExists("bucket-2")); TEST_ASSERTM(b.getExpire() == monthSec, String(b.getExpire())); int len = 34 + strlen(b.getID()) + strlen(b.getName()) + 10 + 1; //10 is maximum length of string representation of expire char *line = new char[len]; sprintf(line, "Bucket: ID %s, Name %s, expire %u", b.getID(),b.getName(), b.getExpire()); TEST_ASSERTM(b.toString() == line, b.toString()); uint32_t yearSec = 12*monthSec; Bucket b2 = buckets.createBucket("bucket-3", yearSec); TEST_ASSERTM(!b2.isNull(), buckets.getLastErrorMessage()); TEST_ASSERT(buckets.checkBucketExists("bucket-3")); TEST_ASSERTM(b2.getExpire() == yearSec, String(b2.getExpire())); TEST_ASSERT(buckets.checkBucketExists("bucket-2")); TEST_ASSERT(buckets.deleteBucket(b.getID())); TEST_ASSERT(buckets.checkBucketExists("bucket-3")); TEST_ASSERT(buckets.deleteBucket(b2.getID())); TEST_ASSERT(!buckets.checkBucketExists("bucket-3")); TEST_ASSERT(!buckets.checkBucketExists("bucket-2")); TEST_END(); } void Test::testFlushing() { TEST_INIT("testFlushing"); InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); TEST_ASSERT(waitServer(Test::managementUrl, true)); TEST_ASSERT(client.validateConnection()); TEST_ASSERT(!client.isBufferFull()); TEST_ASSERT(client.isBufferEmpty()); client.setWriteOptions(WriteOptions().batchSize(10).bufferSize(30).flushInterval(2)); for (int i = 0; i < 5; i++) { Point *p = createPoint("test1"); p->addField("index", i); TEST_ASSERT(client.writePoint(*p)); delete p; } TEST_ASSERT(!client.isBufferFull()); TEST_ASSERT(!client.isBufferEmpty()); client.checkBuffer(); TEST_ASSERT(!client.isBufferFull()); TEST_ASSERT(!client.isBufferEmpty()); String query = "select"; FluxQueryResult q = client.query(query); int count = countLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERTM( count == 0, String(count) + " vs 0"); //5 points delay(2100); client.checkBuffer(); TEST_ASSERT(!client.isBufferFull()); TEST_ASSERT(client.isBufferEmpty()); q = client.query(query); count = countLines(q); TEST_ASSERTM(q.getError()=="", q.getError()); TEST_ASSERTM( count == 5, String(count) + " vs 0"); //5 points TEST_END(); deleteAll(Test::apiUrl); } #if defined(ESP8266) #define WS_DEBUG_RAM(text) { Serial.printf_P(PSTR(text ": free_heap %d, max_alloc_heap %d, heap_fragmentation %d\n"), ESP.getFreeHeap(), ESP.getMaxFreeBlockSize(), ESP.getHeapFragmentation()); } #elif defined(ESP32) #define WS_DEBUG_RAM(text) { Serial.printf_P(PSTR(text ": free_heap %d, max_alloc_heap %d\n"), ESP.getFreeHeap(), ESP.getMaxAllocHeap()); } #endif void Test::testNonRetry() { TEST_INIT("testNonRetry"); const char *lines[] = { "device_status,clientId=WS-E09806011111,Device=WS-ESP8266,Version=0.58-rc3,Location=Prague\\,CZ,WiFi=Bonitoo-ng free_heap=16568i,max_alloc_heap=11336i,heap_fragmentation=29i,uptime=28821.23,wifi_disconnects=0i", "service_status,clientId=WS-E09806011111,Device=WS-ESP8266,Version=0.58-rc3,Location=Prague\\,CZ,WiFi=Bonitoo-ng,service=location state=3i,before_mem_free=36232i,before_mem_max_free_block=17544i,before_mem_framentation=49i,after_mem_free=35792i,after_mem_max_free_block=17544i,after_mem_framentation=48i", "service_status,clientId=WS-E09806011111,Device=WS-ESP8266,Version=0.58-rc3,Location=Prague\\,CZ,WiFi=Bonitoo-ng,service=clock state=2i,before_mem_free=16704i,before_mem_max_free_block=11336i,before_mem_framentation=30i,after_mem_free=16704i,after_mem_max_free_block=11336i,after_mem_framentation=30i", "service_status,clientId=WS-E09806011111,Device=WS-ESP8266,Version=0.58-rc3,Location=Prague\\,CZ,WiFi=Bonitoo-ng,service=update state=0i", "service_status,clientId=WS-E09806011111,Device=WS-ESP8266,Version=0.58-rc3,Location=Prague\\,CZ,WiFi=Bonitoo-ng,service=astronomy state=2i,before_mem_free=16376i,before_mem_max_free_block=11336i,before_mem_framentation=28i,after_mem_free=16376i,after_mem_max_free_block=11336i,after_mem_framentation=28i", "service_status,clientId=WS-E09806011111,Device=WS-ESP8266,Version=0.58-rc3,Location=Prague\\,CZ,WiFi=Bonitoo-ng,service=current_weather state=2i,before_mem_free=16728i,before_mem_max_free_block=11336i,before_mem_framentation=30i,after_mem_free=16376i,after_mem_max_free_block=11336i,after_mem_framentation=28i", "service_status,clientId=WS-E09806011111,Device=WS-ESP8266,Version=0.58-rc3,Location=Prague\\,CZ,WiFi=Bonitoo-ng,service=forecast state=2i,before_mem_free=16704i,before_mem_max_free_block=11336i,before_mem_framentation=30i,after_mem_free=16376i,after_mem_max_free_block=11336i,after_mem_framentation=28i", "service_status,clientId=WS-E09806011111,Device=WS-ESP8266,Version=0.58-rc3,Location=Prague\\,CZ,WiFi=Bonitoo-ng,service=iot_center state=0i", }; WriteOptions wo; WS_DEBUG_RAM("Before inst"); InfluxDBClient *client = new InfluxDBClient(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); WS_DEBUG_RAM("after inst"); //TEST not keeping batch for retry Serial.println("Stop server"); TEST_ASSERT(waitServer(Test::managementUrl, false)); client->setHTTPOptions(HTTPOptions().httpReadTimeout(500)); TEST_ASSERT(!client->validateConnection()); // Disable retry wo.maxRetryAttempts(0); client->setWriteOptions(wo); client->setHTTPOptions(HTTPOptions().connectionReuse(true)); TEST_ASSERT(!client->writeRecord(lines[0])); TEST_ASSERT(!client->_writeBuffer[0]); TEST_ASSERT(waitServer(Test::managementUrl, true)); TEST_ASSERT(client->validateConnection()); uint8_t size = sizeof(lines)/sizeof(lines[0]); uint16_t batchSize = size +1; wo.batchSize(batchSize).bufferSize(batchSize); client->setWriteOptions(wo); WS_DEBUG_RAM("Before"); for(int i=0;iwriteRecord(lines[i]), client->getLastErrorMessage()); WS_DEBUG_RAM("After write Line"); } TEST_ASSERTM(client->flushBuffer(), client->getLastErrorMessage()); WS_DEBUG_RAM("After flush"); delete client; WS_DEBUG_RAM("After delete"); TEST_END(); deleteAll(Test::apiUrl); } void Test::testLargeBatch() { TEST_INIT("testLargeBatch"); TEST_ASSERT(waitServer(Test::managementUrl, true)); WS_DEBUG_RAM("Before"); InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token); client.setStreamWrite(true); WS_DEBUG_RAM("After init"); const char *line = "test1,SSID=Bonitoo-ng,deviceId=4288982576 temperature=17,humidity=28i"; uint32_t free = ESP.getFreeHeap(); #if defined(ESP8266) int batchSize = 330; #elif defined(ESP32) int batchSize = 2047; #endif int len =strlen(line); int points = free/len; Serial.printf("Free ram: %u, line len: %d, max points: %d\n", free, len, points); client.setWriteOptions(WriteOptions().batchSize(batchSize)); WS_DEBUG_RAM("After options"); TEST_ASSERT(client.validateConnection()); WS_DEBUG_RAM("After validate"); if(points < client._writeOptions._batchSize) { Serial.printf("warning, cannot create full batchsize %d\n",client._writeOptions._batchSize); client.setWriteOptions(WriteOptions().batchSize(points)); } for(int i=0;i_apiURL = serverUrl + "/api/v2/"; client.setUrls(); }