version 1.5

This commit is contained in:
Johannes Holzwarth | SE-Inno GmbH
2024-01-11 14:04:25 +01:00
parent 0ee8291846
commit 4492763b78
756 changed files with 209957 additions and 2 deletions
@@ -0,0 +1,75 @@
<?php
namespace InfluxDB2Test;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use InfluxDB2\Client;
use InfluxDB2\Model\WritePrecision;
use InfluxDB2\QueryApi;
use InfluxDB2\WriteApi;
use PHPUnit\Framework\TestCase;
/**
* Parent class for all units tests that uses mocked InfluxDB server
* @package InfluxDB2Test
*/
abstract class BasicTest extends TestCase
{
/** @var Client */
protected $client;
/** @var WriteApi */
protected $writeApi;
/** @var QueryApi */
protected $queryApi;
/** @var MockHandler */
protected $mockHandler;
/** @var array */
protected $requests;
/**
* @before
* @param string $url
* @param string $logFile default log file
*/
public function setUp($url = "http://localhost:8086", $logFile = "php://output"): void
{
$this->client = new Client([
"url" => $url,
"token" => "my-token",
"bucket" => "my-bucket",
"precision" => WritePrecision::NS,
"org" => "my-org",
"logFile" => $logFile
]);
$this->writeApi = $this->client->createWriteApi($this->getWriteOptions());
$this->queryApi = $this->client->createQueryApi();
$this->mockHandler = new MockHandler();
$this->requests = [];
$handlerStack = HandlerStack::create($this->mockHandler);
$handlerStack->push(Middleware::history($this->requests));
$this->writeApi->http = $this->writeApi->configuredClient(new \GuzzleHttp\Client([
'handler' => $handlerStack,
]));
$this->queryApi->http = $this->writeApi->configuredClient(new \GuzzleHttp\Client([
'handler' => $handlerStack,
]));
}
public function tearDown(): void
{
$this->client->close();
}
protected function getWriteOptions(): ?array
{
return null;
}
}
@@ -0,0 +1,79 @@
<?php
namespace InfluxDB2Test;
use Exception;
use InfluxDB2\Client;
use IntegrationBaseTestCase;
require_once('IntegrationBaseTestCase.php');
/**
* @group integration
*/
class ClientTest extends IntegrationBaseTestCase
{
public function test_health()
{
$health = $this->client->health();
$this->assertEquals('ready for queries and writes', $health->getMessage());
$this->assertEquals('influxdb', $health->getName());
$this->assertEquals('pass', $health->getStatus());
}
public function test_health_not_running()
{
$this->client->close();
$this->client = new Client([
"url" => "http://localhost:8099",
"token" => "my-token",
]);
$health = $this->client->health();
$this->assertStringContainsString('Failed to connect to localhost port 8099', $health->getMessage());
$this->assertEquals('influxdb', $health->getName());
$this->assertEquals('fail', $health->getStatus());
}
public function test_ping()
{
$ping = $this->client->ping();
$this->assertArrayHasKey('X-Influxdb-Build', $ping);
$this->assertArrayHasKey('X-Influxdb-Version', $ping);
}
public function test_ping_not_running()
{
$this->client->close();
$this->client = new Client([
"url" => "http://localhost:8099",
"token" => "my-token",
]);
$this->expectException(Exception::class);
$this->expectExceptionMessage("Failed to connect to localhost");
$this->client->ping();
}
public function test_debug()
{
$logFilePath = stream_get_meta_data(tmpfile())['uri'];
$this->client->close();
$this->client = new Client([
"url" => "http://localhost:8086",
"token" => "my-token",
"debug" => true,
"logFile" => $logFilePath
]);
$tables = $this->client->createQueryApi()->query("buckets()", "my-org");
$this->assertCount(1, $tables);
$this->assertStringContainsString('Authorization: ***', file_get_contents($logFilePath));
unlink($logFilePath);
}
}
@@ -0,0 +1,142 @@
<?php
namespace InfluxDB2Test;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use InfluxDB2\ApiException;
use InfluxDB2\Client;
use InfluxDB2\Model\WritePrecision;
use InvalidArgumentException;
use ReflectionObject;
require_once('BasicTest.php');
class DefaultApiTest extends BasicTest
{
public function testUserAgent()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->write('h2o,location=west value=33i 15');
$request = $this->mockHandler->getLastRequest();
$this->assertStringStartsWith(
'influxdb-client-php/',
strval($request->getHeader("User-Agent")[0])
);
}
public function testTrailingSlashInUrl()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->write('h2o,location=west value=33i 15');
$request = $this->mockHandler->getLastRequest();
$this->assertEquals('http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns', strval($request->getUri()));
$this->tearDown();
$this->setUp("http://localhost:8086/");
$this->mockHandler->append(new Response(204));
$this->writeApi->write('h2o,location=west value=33i 15');
$request = $this->mockHandler->getLastRequest();
$this->assertEquals('http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns', strval($request->getUri()));
}
public function testContentType()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->write('h2o,location=west value=33i 15');
$request = $this->mockHandler->getLastRequest();
$this->assertNotEmpty($request->getHeader("Content-Type"));
}
public function testApiException()
{
$this->mockHandler->append(new Response(400));
$this->expectException(ApiException::class);
$this->writeApi->write('h2o,location=west value=33i 15');
}
public function testInvalidArgument()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->options["org"] = '';
$this->expectException(InvalidArgumentException::class);
$this->writeApi->write('h2o,location=west value=33i 15');
}
public function testDefaultVerifySSL()
{
$guzzle = $this->property_value($this->property_value($this->writeApi->http, 'client'), 'httpClient');
$this->assertEquals(true, $guzzle->getConfig()['verify']);
}
public function testConfigureVerifySSL()
{
$client = new Client([
"url" => "http://localhost:8086",
"token" => "my-token",
"bucket" => "my-bucket",
"precision" => WritePrecision::NS,
"org" => "my-org",
"logFile" => "php://output",
"verifySSL" => false
]);
$guzzle = $this->property_value($this->property_value($client->createQueryApi()->http, 'client'), 'httpClient');
$this->assertEquals(false, $guzzle->getConfig()['verify']);
$client->close();
}
public function testFollowRedirect()
{
$this->mockHandler->append(
new Response(
307,
['location' => 'http://localhost:8086']
),
new Response(204, [], "{\"status\": \"pass\"}")
);
$this->writeApi->write('h2o,location=west value=33i 15');
$this->assertCount(2, $this->requests);
$this->assertEquals('Token my-token', $this->getHeader($this->requests[0]['request']));
$this->assertEquals('Token my-token', $this->getHeader($this->requests[1]['request']));
}
/**
* @param Request $request with headers
* @return string Authorization headers
*/
private function getHeader(Request $request): string
{
return implode(' ', $request->getHeaders()['Authorization']);
}
/**
* @throws \ReflectionException fail to access property
*/
private function property_value(object $object, string $property_name): object
{
$reflection = new ReflectionObject($object);
$property = $reflection->getProperty($property_name);
$property->setAccessible(true);
return $property->getValue($object);
}
}
@@ -0,0 +1,534 @@
<?php
namespace InfluxDB2Test;
use Exception;
use InfluxDB2\FluxCsvParser;
use InfluxDB2\FluxCsvParserException;
use InfluxDB2\FluxQueryError;
use InfluxDB2\FluxRecord;
use PHPUnit\Framework\TestCase;
class FluxCsvParserTest extends TestCase
{
public function testMultipleValues()
{
$data = "#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,string,string,string,string,long,long,string\n" .
"#group,false,false,true,true,true,true,true,true,false,false,false\n" .
"#default,_result,,,,,,,,,,\n" .
",result,table,_start,_stop,_field,_measurement,host,region,_value2,value1,value_str\n" .
",,0,1677-09-21T00:12:43.145224192Z,2018-07-16T11:21:02.547596934Z,free,mem,A,west,121,11,test\n" .
",,1,1677-09-21T00:12:43.145224192Z,2018-07-16T11:21:02.547596934Z,free,mem,B,west,484,22,test\n" .
",,2,1677-09-21T00:12:43.145224192Z,2018-07-16T11:21:02.547596934Z,usage_system,cpu,A,west,1444,38,test\n" .
',,3,1677-09-21T00:12:43.145224192Z,2018-07-16T11:21:02.547596934Z,user_usage,cpu,A,west,2401,49,test';
$fluxCsvParser = new FluxCsvParser($data);
$tables = $fluxCsvParser->parse()->tables;
$columnHeaders = $tables[0]->columns;
$this->assertEquals(11, sizeof($columnHeaders));
$values = [false, false, true, true, true, true, true, true, false, false, false];
$this->assertColumns($columnHeaders, $values);
$this->assertEquals(4, sizeof($tables));
$this->assertMultipleRecords($tables);
}
public function testParseShortCut()
{
$data = '#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,' .
"dateTime:RFC3339,long,string,string,string,boolean\n" .
"#group,false,false,false,false,false,false,false,false,false,true\n" .
"#default,_result,,,,,,,,,true\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,true\n";
$fluxCsvParser = new FluxCsvParser($data);
$tables = $fluxCsvParser->parse()->tables;
$this->assertEquals(1, sizeof($tables));
$this->assertEquals(1, sizeof($tables[0]->records));
$record = $tables[0]->records[0];
$this->assertEquals($this->parseTime('1970-01-01T00:00:10Z'), $record->getStart());
$this->assertEquals($this->parseTime('1970-01-01T00:00:20Z'), $record->getStop());
$this->assertEquals($this->parseTime('1970-01-01T00:00:10Z'), $record->getTime());
$this->assertEquals(10, sizeof($record->values));
$this->assertEquals("free", $record->getField());
$this->assertEquals("mem", $record->getMeasurement());
}
public function testMappingBoolean()
{
$data = '#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,' .
"dateTime:RFC3339,long,string,string,string,boolean\n" .
"#group,false,false,false,false,false,false,false,false,false,true\n" .
"#default,_result,,,,,,,,,true\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,true\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,false\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,x\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,\n";
$fluxCsvParser = new FluxCsvParser($data);
$tables = $fluxCsvParser->parse()->tables;
$this->assertEquals(1, sizeof($tables));
$this->assertEquals(4, sizeof($tables[0]->records));
$records = $tables[0]->records;
$this->assertEquals(true, $records[0]->values['value']);
$this->assertEquals(false, $records[1]->values['value']);
$this->assertEquals(false, $records[2]->values['value']);
$this->assertEquals(true, $records[3]->values['value']);
}
/**
* TODO - PHP supports only signed 64bit integers
*/
public function testMappingUnsignedLong()
{
$data = '#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,' .
"dateTime:RFC3339,long,string,string,string,unsignedLong\n" .
"#group,false,false,false,false,false,false,false,false,false,true\n" .
"#default,_result,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,17916881237904312345\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,\n";
//TODO this does not work due "overflow"
$expected = intval("17916881237904312345");
$fluxCsvParser = new FluxCsvParser($data);
$tables = $fluxCsvParser->parse()->tables;
$records = $tables[0]->records;
$this->assertEquals($expected, $records[0]->values['value']);
$this->assertNull($records[1]->values['value']);
}
public function testMappingDouble()
{
$data = '#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,' .
"dateTime:RFC3339,long,string,string,string,double\n" .
"#group,false,false,false,false,false,false,false,false,false,true\n" .
"#default,_result,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,12.25\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,\n";
$fluxCsvParser = new FluxCsvParser($data);
$tables = $fluxCsvParser->parse()->tables;
$records = $tables[0]->records;
$this->assertEquals(12.25, $records[0]->values['value']);
$this->assertNull($records[1]->values['value']);
}
public function testMappingBase64Binary()
{
$binaryData = 'test value';
$encodedData = base64_encode($binaryData);
$data = '#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,' .
"dateTime:RFC3339,long,string,string,string,base64Binary\n" .
"#group,false,false,false,false,false,false,false,false,false,true\n" .
"#default,_result,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n" .
',,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,' . $encodedData . "\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,\n";
$fluxCsvParser = new FluxCsvParser($data);
$tables = $fluxCsvParser->parse()->tables;
$records = $tables[0]->records;
$this->assertEquals($binaryData, $records[0]->values['value']);
$this->assertNull($records[1]->values['value']);
}
public function testMappingDuration()
{
$data = '#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339' .
",dateTime:RFC3339,long,string,string,string,duration\n" .
"#group,false,false,false,false,false,false,false,false,false,true\n" .
"#default,_result,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,125\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,\n";
$fluxCsvParser = new FluxCsvParser($data);
$tables = $fluxCsvParser->parse()->tables;
$records = $tables[0]->records;
$this->assertEquals(125, $records[0]->values['value']);
$this->assertNull($records[1]->values['value']);
}
public function testGroupKey()
{
$data = '#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,' .
"dateTime:RFC3339,long,string,string,string,duration\n" .
"#group,false,false,false,false,true,false,false,false,false,true\n" .
"#default,_result,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,125\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,\n";
$fluxCsvParser = new FluxCsvParser($data);
$tables = $fluxCsvParser->parse()->tables;
$this->assertEquals(10, count($tables[0]->columns));
$this->assertEquals(2, count($tables[0]->getGroupKey()));
}
public function testUnknownTypeAsString()
{
$data = '#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,' .
"dateTime:RFC3339,long,string,string,string,unknown\n" .
"#group,false,false,false,false,false,false,false,false,false,true\n" .
"#default,_result,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,12.25\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,\n";
$fluxCsvParser = new FluxCsvParser($data);
$tables = $fluxCsvParser->parse()->tables;
$records = $tables[0]->records;
$this->assertEquals('12.25', $records[0]->values['value']);
$this->assertNull($records[1]->values['value']);
}
public function testError()
{
$data = "#datatype,string,string\n" .
"#group,true,true\n" .
"#default,,\n" .
",error,reference\n" .
',failed to create physical plan: invalid time bounds from procedure from: bounds contain zero time,897';
$fluxCsvParser = new FluxCsvParser($data);
try {
$fluxCsvParser->parse();
$this->fail();
} catch (FluxQueryError $e) {
$this->assertEquals(
'failed to create physical plan: invalid time bounds from procedure from: bounds contain zero time',
$e->getMessage()
);
$this->assertEquals(897, $e->getCode());
} catch (Exception $e) {
$this->fail();
}
}
public function testErrorWithoutReference()
{
$data = "#datatype,string,string\n" .
"#group,true,true\n" .
"#default,,\n" .
",error,reference\n" .
',failed to create physical plan: invalid time bounds from procedure from: bounds contain zero time,';
$fluxCsvParser = new FluxCsvParser($data);
try {
$fluxCsvParser->parse();
$this->fail();
} catch (FluxQueryError $e) {
$this->assertEquals(
'failed to create physical plan: invalid time bounds from procedure from: bounds contain zero time',
$e->getMessage()
);
$this->assertEquals(0, $e->getCode());
} catch (Exception $e) {
$this->fail();
}
}
public function testWithoutTableReference()
{
$data = ",result,table,_start,_stop,_time,_value,_field,_measurement,host,value\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,12.25\n" .
",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,\n";
$fluxCsvParser = new FluxCsvParser($data);
try {
$fluxCsvParser->parse();
$this->fail();
} catch (FluxCsvParserException $e) {
$this->assertEquals(
'Unable to parse CSV response. FluxTable definition was not found.',
$e->getMessage()
);
} catch (Exception $e) {
$this->fail();
}
}
public function testParserErrorUndefinedOffset()
{
$data = "#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string,string\n" .
"#group,false,false,true,true,false,false,true,true,true,true,true\n" .
"#default,_result,,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,channel,device_eui,sensor_eui\n" .
",,0,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:17:43.775791768Z,23.4,value,4097,1,2CF7F1201470029C,vs\n" .
",,0,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:27:45.894980937Z,22.5,value,4097,1,2CF7F1201470029C,vs\n" .
",,0,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:37:50.278735828Z,21.4,value,4097,1,2CF7F1201470029C,vs\n" .
",,0,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:47:51.766261407Z,20.3,value,4097,1,2CF7F1201470029C,vs\n" .
",,0,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:57:57.475875729Z,18.9,value,4097,1,2CF7F1201470029C,vs\n" .
",,0,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T16:07:59.413550698Z,17.8,value,4097,1,2CF7F1201470029C,vs\n" .
"\n" .
"#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string,string\n" .
"#group,false,false,true,true,false,false,true,true,true,true,true\n" .
"#default,_result,,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,channel,device_eui,sensor_eui\n" .
",,1,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:43:49.398558429Z,12.3,value,4102,1,2CF7F12014700247,vs\n" .
"#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string,string\n" .
"#group,false,false,true,true,false,false,true,true,true,true,true\n" .
"#default,_result,,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,channel,device_eui,sensor_eui\n" .
",,2,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:17:43.772929338Z,43.1,value,4098,1,2CF7F1201470029C,vs\n" .
",,2,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:27:45.897608471Z,49,value,4098,1,2CF7F1201470029C,vs\n" .
",,2,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:37:50.27543528Z,48.2,value,4098,1,2CF7F1201470029C,vs\n" .
",,2,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:47:51.769665096Z,44.7,value,4098,1,2CF7F1201470029C,vs\n" .
",,2,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:57:57.47339818Z,48.5,value,4098,1,2CF7F1201470029C,vs\n" .
",,2,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T16:07:59.40946618Z,52.3,value,4098,1,2CF7F1201470029C,vs\n" .
"\n" .
"#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string,string\n" .
"#group,false,false,true,true,false,false,true,true,true,true,true\n" .
"#default,_result,,,,,,,,,,\n" .
",result,table,_start,_stop,_time,_value,_field,_measurement,channel,device_eui,sensor_eui\n" .
",,3,2020-03-27T15:17:00.64917903Z,2020-03-27T16:17:00.64917903Z,2020-03-27T15:43:49.39609423Z,30.7,value,4103,1,2CF7F12014700247,vs\n";
$parser = new FluxCsvParser($data);
$tables = $parser->parse()->tables;
$this->assertEquals(4, sizeof($tables));
$this->assertEquals(6, sizeof($tables[0]->records));
$this->assertEquals(1, sizeof($tables[1]->records));
$this->assertEquals(6, sizeof($tables[2]->records));
$this->assertEquals(1, sizeof($tables[3]->records));
}
public function testResponseWithError()
{
$data = "#datatype,string,long,string,string,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string\n" .
"#group,false,false,true,true,true,true,false,false,true\n" .
"#default,t1,,,,,,,,\n" .
",result,table,_field,_measurement,_start,_stop,_time,_value,tag\n" .
",,0,value,python_client_test,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:20:00Z,2,test1\n" .
",,0,value,python_client_test,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:21:40Z,2,test1\n" .
",,0,value,python_client_test,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:23:20Z,2,test1\n" .
",,0,value,python_client_test,2010-02-27T04:48:32.752600083Z,2020-02-27T16:48:32.752600083Z,2020-02-27T16:25:00Z,2,test1\n" .
"\n" .
"#datatype,string,string\n" .
"#group,true,true\n" .
"#default,,\n" .
",error,reference\n" .
",\"engine: unknown field type for value: xyz\",";
$fluxCsvParser = new FluxCsvParser($data);
try {
$fluxCsvParser->parse();
$this->fail();
} catch (FluxQueryError $e) {
$this->assertEquals(
'engine: unknown field type for value: xyz',
$e->getMessage()
);
$this->assertEquals(0, $e->getCode());
} catch (Exception $e) {
$this->fail();
}
}
public function testParseExportFromUserInterface()
{
$data = "#group,false,false,true,true,true,true,true,true,false,false\n" .
"#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,string,string,string,string,double,dateTime:RFC3339\n" .
"#default,mean,,,,,,,,,\n" .
",result,table,_start,_stop,_field,_measurement,city,location,_value,_time\n" .
",,0,1754-06-26T11:30:27.613654848Z,2040-10-27T12:13:46.485Z,temperatureC,weather,London,us-midwest,30,1975-09-01T16:59:54.5Z\n" .
",,1,1754-06-26T11:30:27.613654848Z,2040-10-27T12:13:46.485Z,temperatureF,weather,London,us-midwest,86,1975-09-01T16:59:54.5Z\n";
$parser = new FluxCsvParser($data);
$tables = $parser->parse()->tables;
$this->assertEquals(2, sizeof($tables));
$this->assertEquals(1, sizeof($tables[0]->records));
$this->assertFalse($tables[0]->columns[0]->group);
$this->assertFalse($tables[0]->columns[1]->group);
$this->assertTrue($tables[0]->columns[2]->group);
$this->assertEquals(1, sizeof($tables[1]->records));
}
public function testParseWithoutDatatype()
{
$data = ",result,table,_start,_stop,_field,_measurement,host,region,_value2,value1,value_str\n" .
",,0,1677-09-21T00:12:43.145224192Z,2018-07-16T11:21:02.547596934Z,free,mem,A,west,121,11,test\n" .
",,1,1677-09-21T00:12:43.145224192Z,2018-07-16T11:21:02.547596934Z,free,mem,A,west,121,11,test\n";
$parser = new FluxCsvParser($data, false, "only_names");
$tables = $parser->parse()->tables;
$this->assertEquals(2, sizeof($tables));
$this->assertEquals(11, sizeof($tables[0]->columns));
$this->assertEquals(1, sizeof($tables[0]->records));
$this->assertEquals(11, sizeof($tables[0]->records[0]->values));
$this->assertEquals("0", $tables[0]->records[0]->values['table']);
$this->assertEquals("11", $tables[0]->records[0]->values['value1']);
$this->assertEquals("west", $tables[0]->records[0]->values['region']);
}
public function testRecordDoesntContainsKey()
{
$data = "#group,false,false,true,true,true,true,true,true,false,false\n" .
"#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,string,string,string,string,double,dateTime:RFC3339\n" .
"#default,mean,,,,,,,,,\n" .
",result,table,_start,_stop,_field,_measurement,city,location,value,_time\n" .
",,0,1754-06-26T11:30:27.613654848Z,2040-10-27T12:13:46.485Z,temperatureC,weather,London,us-midwest,30,1975-09-01T16:59:54.5Z\n";
$parser = new FluxCsvParser($data);
$tables = $parser->parse()->tables;
$record = $tables[0]->records[0];
try {
$record->getValue();
$this->fail("Expected exception");
} catch (Exception $e) {
$this->assertEquals("Record doesn't contain column named '_value'. " .
"Columns: 'result, table, _start, _stop, _field, _measurement, city, location, value, _time'.", $e->getMessage());
}
}
public function testParseInfinity()
{
$data = "#group,false,false,true,true,true,true,true,true,true,true,false,false
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,string,string,string,string,string,string,double,double
#default,_result,,,,,,,,,,,
,result,table,_start,_stop,_field,_measurement,language,license,name,owner,le,_value
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,0,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,10,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,20,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,30,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,40,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,50,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,60,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,70,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,80,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,90,0
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,+Inf,15
,,0,2021-06-23T06:50:11.897825012Z,2021-06-25T06:50:11.897825012Z,stars,github_repository,C#,MIT License,influxdb-client-csharp,influxdata,-Inf,15
";
$parser = new FluxCsvParser($data);
$tables = $parser->parse()->tables;
$this->assertEquals(1, sizeof($tables));
$this->assertEquals(12, sizeof($tables[0]->records));
$this->assertEquals(INF, $tables[0]->records[10]->values['le']);
$this->assertEquals(-INF, $tables[0]->records[11]->values['le']);
}
public function testParseDuplicateColumnNames()
{
$data = "#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,string,string,double
#group,false,false,true,true,false,true,true,false
#default,_result,,,,,,,
,result,table,_start,_stop,_time,_measurement,location,result
,,0,2022-09-13T06:14:40.469404272Z,2022-09-13T06:24:40.469404272Z,2022-09-13T06:24:33.746Z,my_measurement,Prague,25.3
,,0,2022-09-13T06:14:40.469404272Z,2022-09-13T06:24:40.469404272Z,2022-09-13T06:24:39.299Z,my_measurement,Prague,25.3
,,0,2022-09-13T06:14:40.469404272Z,2022-09-13T06:24:40.469404272Z,2022-09-13T06:24:40.454Z,my_measurement,Prague,25.3
";
$parser = new FluxCsvParser($data);
$tables = $parser->parse()->tables;
$this->assertEquals(1, sizeof($tables));
$this->assertEquals(3, sizeof($tables[0]->records));
$this->assertEquals(8, sizeof($tables[0]->columns));
$this->assertEquals(7, sizeof($tables[0]->records[0]->values));
$this->assertEquals(8, sizeof($tables[0]->records[0]->row));
$this->assertEquals(25.3, $tables[0]->records[0]->row[7]);
}
private function assertColumns(array $columnHeaders, array $values)
{
$i = 0;
foreach ($values as $value) {
$this->assertEquals($value, $columnHeaders[$i]->group, "column assert '" . $columnHeaders[$i]->label . "'");
$i++;
}
}
private function assertMultipleRecords(array $tables)
{
#Record 1
$tableRecords = $tables[0]->records;
$this->assertEquals(1, sizeof($tableRecords));
$values = ['table' => 0, 'host' => 'A', 'region' => 'west', 'value1' => 11, '_value2' => 121,
'value_str' => 'test'];
$this->assertRecord($tableRecords[0], $values, 11);
#Record 2
$tableRecords = $tables[1]->records;
$this->assertEquals(1, sizeof($tableRecords));
$values = ['table' => 1, 'host' => 'B', 'region' => 'west', 'value1' => 22, '_value2' => 484,
'value_str' => 'test'];
$this->assertRecord($tableRecords[0], $values, 11);
#Record 3
$tableRecords = $tables[2]->records;
$this->assertEquals(1, sizeof($tableRecords));
$values = ['table' => 2, 'host' => 'A', 'region' => 'west', 'value1' => 38, '_value2' => 1444,
'value_str' => 'test'];
$this->assertRecord($tableRecords[0], $values, 11);
#Record 4
$tableRecords = $tables[3]->records;
$this->assertEquals(1, sizeof($tableRecords));
$values = ['table' => 3, 'host' => 'A', 'region' => 'west', 'value1' => 49, '_value2' => 2401,
'value_str' => 'test'];
$this->assertRecord($tableRecords[0], $values, 11);
}
private function assertRecord(FluxRecord $fluxRecord, array $values, $size = 0, $value = null)
{
foreach ($values as $key => $val) {
$this->assertEquals($values[$key], $fluxRecord->values[$key]);
}
if ($value == null) {
$this->assertNull($value);
} else {
$this->assertEquals($value, $fluxRecord->getValue());
}
$this->assertEquals($size, sizeof($fluxRecord->values));
}
private function parseTime(string $timestamp)
{
//TODO datetime parsing
return $timestamp;
}
}
@@ -0,0 +1,114 @@
<?php
use InfluxDB2\ApiException;
use InfluxDB2\Model\BucketRetentionRules;
use InfluxDB2\Model\PostBucketRequest;
use InfluxDB2\ObjectSerializer;
use InfluxDB2\Service\BucketsService;
use InfluxDB2\Service\HealthService;
require_once('IntegrationBaseTestCase.php');
/**
* @group integration
*/
class ITBucketServiceTest extends IntegrationBaseTestCase
{
public function testHealthService()
{
$healthService = $this->client->createService(HealthService::class);
$healthCheck = $healthService->getHealth();
self::assertEquals("influxdb", $healthCheck->getName());
self::assertEquals("ready for queries and writes", $healthCheck->getMessage());
}
public function testFixNanosTimeSerialization()
{
self::assertEquals(
"2020-09-18T08:03:48.12345Z",
ObjectSerializer::fixDatetimeNanos("2020-09-18T08:03:48.12345Z")
);
self::assertEquals(
"2020-09-18T08:03:48.123456Z",
ObjectSerializer::fixDatetimeNanos("2020-09-18T08:03:48.123456Z")
);
self::assertEquals(
"2020-09-18T08:03:48.1234567Z",
ObjectSerializer::fixDatetimeNanos("2020-09-18T08:03:48.1234567Z")
);
self::assertEquals(
"2020-09-18T08:03:48.12345678Z",
ObjectSerializer::fixDatetimeNanos("2020-09-18T08:03:48.12345678Z")
);
self::assertEquals(
"2020-09-18T08:03:48.12345678Z",
ObjectSerializer::fixDatetimeNanos("2020-09-18T08:03:48.123456789Z")
);
self::assertEquals(
"2020-09-18T08:03:48.12345678Z",
ObjectSerializer::fixDatetimeNanos("2020-09-18T08:03:48.1234567899Z")
);
self::assertEquals(
"2021-09-29T06:32:56Z",
ObjectSerializer::fixDatetimeNanos("2021-09-29T06:32:56Z")
);
}
public function testBucketService()
{
/** @var BucketsService $bucketsService */
$bucketsService = $this->client->createService(BucketsService::class);
$buckets = $bucketsService->getBuckets(null, null, 100, null)->getBuckets();
foreach ($buckets as $bucket) {
self::assertNotEmpty($bucket->getName());
self::assertNotEmpty($bucket->getId());
}
}
public function testBucketServiceCreateBucket()
{
/** @var BucketsService $bucketsService */
$bucketsService = $this->client->createService(BucketsService::class);
$rule = new BucketRetentionRules();
$rule->setEverySeconds(3600);
$bucketName = $this->generateBucketName();
$bucketRequest = new PostBucketRequest();
$bucketRequest->setName($bucketName)
->setRetentionRules([$rule])
->setOrgId($this->findMyOrg()->getId());
//create bucket
$respBucket = $bucketsService->postBuckets($bucketRequest);
print $respBucket;
self::assertEquals($bucketName, $respBucket->getName());
//find bucket
$buckets = $bucketsService->getBuckets(null, null, 100, null)->getBuckets();
$findBucket = null;
foreach ($buckets as $bucket) {
self::assertNotEmpty($bucket->getName());
self::assertNotEmpty($bucket->getId());
if ($bucket->getId() == $respBucket->getId()) {
$findBucket = $bucket;
}
}
self::assertNotNull($findBucket);
//delete bucket
$bucketsService->deleteBucketsID($findBucket->getId());
//verify bucket deleted
$this->expectException(ApiException::class);
$this->expectExceptionCode(404);
$this->expectExceptionMessage("bucket not found");
$bucketsService->getBucketsID($findBucket->getId());
}
}
@@ -0,0 +1,34 @@
<?php
use InfluxDB2\Model\TaskCreateRequest;
use InfluxDB2\Service\TasksService;
require_once('IntegrationBaseTestCase.php');
/**
* @group integration
*/
class ITTaskServiceTest extends IntegrationBaseTestCase
{
public function testCreateTask()
{
/** @var TasksService $taskService */
$taskService = $this->client->createService(TasksService::class);
$flux = "option task = {
name: \"task-name\",
every: 6h
}
from(bucket: \"telegraf\") |> range(start: -1h)
";
$taskCreateRequest = new TaskCreateRequest();
$taskCreateRequest
->setFlux($flux)
->setOrgId($this->findMyOrg()->getId());
$task = $taskService->postTasks($taskCreateRequest);
self::assertEquals("task-name", $task->getName());
}
}
@@ -0,0 +1,23 @@
<?php
use InfluxDB2\Service\UsersService;
require_once('IntegrationBaseTestCase.php');
/**
* @group integration
*/
class ITUsersServiceTest extends IntegrationBaseTestCase
{
public function testUserService()
{
/** @var UsersService $usersService */
$usersService = $this->client->createService(UsersService::class);
$users = $usersService->getUsers()->getUsers();
foreach ($users as $user) {
self::assertNotEmpty($user->getName());
self::assertNotEmpty($user->getId());
self::assertNotEmpty($user->getLinks()->getSelf());
}
}
}
@@ -0,0 +1,45 @@
<?php
use InfluxDB2\Client;
use InfluxDB2\Model\Organization;
use InfluxDB2\Model\WritePrecision;
use InfluxDB2\Service\OrganizationsService;
use PHPUnit\Framework\TestCase;
class IntegrationBaseTestCase extends TestCase
{
public $client;
public $options;
public function setUp(): void
{
$this->options = [
"url" => "http://localhost:8086",
"token" => "my-token",
"bucket" => "my-bucket",
"precision" => WritePrecision::NS,
"org" => "my-org",
"debug" => false
];
$this->client = new Client($this->options);
}
public function findMyOrg(): ?Organization
{
/** @var OrganizationsService $orgService */
$orgService = $this->client->createService(OrganizationsService::class);
$orgs = $orgService->getOrgs()->getOrgs();
foreach ($orgs as $org) {
if ($org->getName() == $this->options["org"]) {
return $org;
}
}
return null;
}
public function generateBucketName()
{
return "IT-php-bucket-" . microtime();
}
}
@@ -0,0 +1,19 @@
<?php
namespace InfluxDB2Test;
require_once('BasicTest.php');
/**
* Class InvokableScriptsApiTest
* @package InfluxDB2Test
*/
class InvokableScriptsApiTest extends BasicTest
{
public function testCreateInstance()
{
$invokableScriptsApi = $this->client->createInvokableScriptsApi();
$this->assertNotNull($invokableScriptsApi);
}
}
@@ -0,0 +1,52 @@
<?php
namespace InfluxDB2Test;
use InfluxDB2\Client;
use InfluxDB2\Model\WritePrecision;
use PHPUnit\Framework\TestCase;
class PointSettingsTest extends TestCase
{
private const ID_TAG = "132-987-655";
private const CUSTOMER_TAG = "California Miner";
/** @var Client */
private $client;
public function setUp(): void
{
$this->client = new Client([
"url" => "http://localhost:8086",
"token" => "my-token",
"bucket" => "my-bucket",
"precision" => WritePrecision::NS,
"org" => "my-org",
"tags" => ['id' => PointSettingsTest::ID_TAG]
]);
}
public function testPointSettings()
{
$writeApi = $this->client->createWriteApi(null, ['customer' => PointSettingsTest::CUSTOMER_TAG]);
$defaultTags = $writeApi->pointSettings->getDefaultTags();
$this->assertEquals(PointSettingsTest::ID_TAG, $defaultTags['id']);
$this->assertEquals(PointSettingsTest::CUSTOMER_TAG, $defaultTags['customer']);
}
public function testPointSettingsWithAdd()
{
putenv("data_center=LA");
$writeApi = $this->client->createWriteApi();
$writeApi->pointSettings->addDefaultTag('customer', PointSettingsTest::CUSTOMER_TAG);
$defaultTags = $writeApi->pointSettings->getDefaultTags();
$this->assertEquals(PointSettingsTest::ID_TAG, $defaultTags['id']);
$this->assertEquals(PointSettingsTest::CUSTOMER_TAG, $defaultTags['customer']);
}
}
@@ -0,0 +1,292 @@
<?php
namespace InfluxDB2Test;
use DateTime;
use DateTimeImmutable;
use InfluxDB2\Model\WritePrecision;
use InfluxDB2\Point;
use PHPUnit\Framework\TestCase;
class PointTest extends TestCase
{
public function testToLineProtocol()
{
$pointArgs = new Point(
'h2o',
array('host' => 'aws', 'region' => 'us'),
array('level' => 5, 'saturation' => '99%'),
123
);
$this->assertEquals(
'h2o,host=aws,region=us level=5i,saturation="99%" 123',
$pointArgs->toLineProtocol()
);
$pointArray = Point::fromArray(array('name' => 'h2o',
'tags' => array('host' => 'aws', 'region' => 'us'),
'fields' => array('level' => 5, 'saturation' => '99%'),
'time' => 123));
$this->assertEquals(
'h2o,host=aws,region=us level=5i,saturation="99%" 123',
$pointArray->toLineProtocol()
);
}
public function testMeasurementEscape()
{
$point = new Point('h2 o 2', array('location' => 'europe'), array('level' => 2));
$this->assertEquals('h2\\ o\\ 2,location=europe level=2i', $point->toLineProtocol());
$point = new Point('h2,o', array('location' => 'europe'), array('level' => 2));
$this->assertEquals('h2\\,o,location=europe level=2i', $point->toLineProtocol());
}
public function testEmptyKey()
{
$point = Point::measurement('h2o')
->addField('level', 2)
->addTag('location', 'europe')
->addTag('', 'warn');
$this->assertEquals('h2o,location=europe level=2i', $point->toLineProtocol());
}
public function testEmptyValue()
{
$point = Point::measurement('h2o')
->addField('level', 2)
->addTag('location', 'europe')
->addTag('log', '');
$this->assertEquals('h2o,location=europe level=2i', $point->toLineProtocol());
}
public function testTagEscapingKeyAndValue()
{
$point = Point::measurement("h\n2\ro\t_data")
->addTag("new\nline", "new\nline")
->addTag("carriage\rreturn", "carriage\nreturn")
->addTag("t\tab", "t\tab")
->addField("level", 2);
$this->assertEquals(
"h\\n2\\ro\\t_data,carriage\\rreturn=carriage\\nreturn,new\\nline=new\\nline,t\\tab=t\\tab level=2i",
$point->toLineProtocol()
);
}
public function testEqualSignEscaping()
{
$point = Point::measurement("h=2o")
->addTag("l=ocation", "e=urope")
->addField("l=evel", 2);
$this->assertEquals("h=2o,l\\=ocation=e\\=urope l\\=evel=2i", $point->toLineProtocol());
}
public function testOverrideTagAndField()
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addTag('location', 'europe2')
->addField('level', 1)
->addField('level', 2)
->addField('level', 3);
$this->assertEquals('h2o,location=europe2 level=3i', $point->toLineProtocol());
}
public function testFieldTypes()
{
$point = Point::measurement('h2o')
->addTag('tag_b', 'b')
->addTag('tag_a', 'a')
->addField('n1', -2)
->addField('n2', 10)
->addField('n3', 9223372036854775807)
->addField('n4', 5.5)
->addField('bool', true)
->addField('string', 'string value');
$expected = 'h2o,tag_a=a,tag_b=b bool=true,n1=-2i,n2=10i,n3=9223372036854775807i,n4=5.5,string="string value"';
$this->assertEquals($expected, $point->toLineProtocol());
}
public function testFieldNullValue()
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->addField('warning', null);
$this->assertEquals('h2o,location=europe level=2i', $point->toLineProtocol());
}
public function testFieldEscape()
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 'string esc"ape value');
$this->assertEquals('h2o,location=europe level="string esc\"ape value"', $point->toLineProtocol());
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 'string esc\\ape value');
$this->assertEquals('h2o,location=europe level="string esc\\\\ape value"', $point->toLineProtocol());
}
public function testTime()
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time(123, WritePrecision::NS);
$this->assertEquals('h2o,location=europe level=2i 123', $point->toLineProtocol());
}
/**
* @dataProvider providerDateTime
*/
public function testTimeFormatting($time)
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time($time, WritePrecision::MS);
$this->assertEquals('h2o,location=europe level=2i 1444897215000', $point->toLineProtocol());
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time($time, WritePrecision::S);
$this->assertEquals('h2o,location=europe level=2i 1444897215', $point->toLineProtocol());
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time($time, WritePrecision::US);
$this->assertEquals('h2o,location=europe level=2i 1444897215000000', $point->toLineProtocol());
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time($time, WritePrecision::NS);
$this->assertEquals('h2o,location=europe level=2i 1444897215000000000', $point->toLineProtocol());
}
public function providerDateTime()
{
return [
[
(new DateTime())
->setDate(2015, 10, 15)
->setTime(8, 20, 15)
],
[
(new DateTimeImmutable())
->setDate(2015, 10, 15)
->setTime(8, 20, 15)
],
];
}
public function testTimeFormattingDefault()
{
$time = new DateTime();
$time->setDate(2015, 10, 15);
$time->setTime(8, 20, 15);
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time($time);
$this->assertEquals('h2o,location=europe level=2i 1444897215000000000', $point->toLineProtocol());
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time($time, null);
$this->assertEquals('h2o,location=europe level=2i 1444897215000000000', $point->toLineProtocol());
}
public function testTimeString()
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time('123');
$this->assertEquals('h2o,location=europe level=2i 123', $point->toLineProtocol());
}
public function testTimeFloat()
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time(102030405060.24);
$this->assertEquals('h2o,location=europe level=2i 102030405060', $point->toLineProtocol());
}
public function testUtf8()
{
$point = Point::measurement('h2o')
->addTag('location', 'Přerov')
->addField('level', 2)
->time(123);
$this->assertEquals('h2o,location=Přerov level=2i 123', $point->toLineProtocol());
}
public function testWithoutTags()
{
$point = Point::measurement('h2o')
->addField('level', 2)
->time(123);
$this->assertEquals('h2o level=2i 123', $point->toLineProtocol());
}
public function testWithoutFields()
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->time(123);
$this->assertNull($point->toLineProtocol());
}
public function testFromArrayWithoutName()
{
$pointArray = Point::fromArray(array(
'tags' => array('host' => 'aws', 'region' => 'us'),
'fields' => array('level' => 5, 'saturation' => '99%'),
'time' => 123));
$this->assertNull($pointArray);
}
public function testTagNotString()
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addTag('tag_not_string', [])
->addTag('tag_not_null', null)
->addField('level', 2);
$this->assertEquals('h2o,location=europe level=2i', $point->toLineProtocol());
}
}
@@ -0,0 +1,115 @@
<?php
namespace InfluxDB2Test;
use DateTime;
use InfluxDB2\Client;
use InfluxDB2\Model\WritePrecision;
use InfluxDB2\Point;
use PHPUnit\Framework\TestCase;
/**
* @group integration
*/
class QueryApiIntegrationTest extends TestCase
{
private $client;
private $writeApi;
private $queryApi;
/**
* @before
*/
public function setUp(): void
{
$this->client = new Client([
"url" => "http://localhost:8086",
"token" => "my-token",
"bucket" => "my-bucket",
"precision" => WritePrecision::NS,
"org" => "my-org",
"debug" => false
]);
$this->writeApi = $this->client->createWriteApi();
$this->queryApi = $this->client->createQueryApi();
}
public function testExistsApi()
{
$this->assertNotNull($this->writeApi);
$this->assertNotNull($this->queryApi);
}
public function testQueryRaw()
{
$now = new DateTime();
$measurement = 'h2o_query_' . $now->getTimestamp();
$query = $this->prepareData($measurement, $now);
print $query;
$result = $this->queryApi->queryRaw($query);
$this->assertStringContainsString(',result,table,_start,_stop,_time,_value,_field,_measurement,location', $result);
$this->assertStringContainsString($measurement, $result);
}
public function testQuery()
{
$now = new DateTime();
$measurement = 'h2o_query_' . $now->getTimestamp();
$query = $this->prepareData($measurement, $now);
print $query;
$result = $this->queryApi->query($query);
$this->assertNotNull($result);
$this->assertEquals(1, sizeof($result));
$records = $result[0]->records;
$this->assertEquals(1, sizeof($records));
$record = $records[0];
$this->assertEquals($measurement, $record->getMeasurement());
$this->assertEquals('europe', $record->values['location']);
$this->assertEquals(2, $record->getValue());
$this->assertEquals(0, $record->table);
$this->assertEquals(0, $record->values['table']);
$this->assertEquals('level', $record->getField());
}
public function testWriteQueryNewLine()
{
$measurement = 'h2o_QueryNewLine_' . (new DateTime())->getTimestamp();
$this->writeApi->write(Point::measurement($measurement)
->addTag('location', 'europe')
->addField('value', "some \n value"));
$result = $this->queryApi->query('from(bucket: "my-bucket") |> range(start: 0)
|> filter(fn: (r) => r._measurement == "' . $measurement . '")');
$this->assertNotNull($result);
$this->assertEquals(1, sizeof($result));
$records = $result[0]->records;
$this->assertEquals(1, sizeof($records));
$record = $records[0];
$this->assertEquals("some \r\n value", $record->getValue());
}
/**
* @param string $measurement
* @param DateTime $now
* @return string
*/
public function prepareData(string $measurement, DateTime $now): string
{
$this->writeApi->write(Point::measurement($measurement)
->addTag('location', 'europe')
->addField('level', 2)
->time($now, WritePrecision::US));
$query = 'from(bucket: "my-bucket") |> range(start: 0)
|> filter(fn: (r) => r._measurement == "' . $measurement . '")';
return $query;
}
}
@@ -0,0 +1,116 @@
<?php
namespace InfluxDB2Test;
use DateTime;
use InfluxDB2\Client;
use InfluxDB2\Model\WritePrecision;
use InfluxDB2\Point;
use PHPUnit\Framework\TestCase;
/**
* @group integration
*/
class QueryApiStreamTest extends TestCase
{
private $client;
private $writeApi;
private $queryApi;
private $now;
/**
* @before
*/
public function setUp(): void
{
$this->client = new Client([
"url" => "http://localhost:8086",
"token" => "my-token",
"bucket" => "my-bucket",
"precision" => WritePrecision::NS,
"org" => "my-org",
"debug" => false
]);
$this->writeApi = $this->client->createWriteApi();
$this->queryApi = $this->client->createQueryApi();
$this->now = new DateTime();
}
public function testQueryStream()
{
$measurement = 'h2o_query_stream' . $this->now->format('Y-m-d-H-i-s');
$this->write(10, $measurement);
$query = 'from(bucket: "my-bucket") |> range(start: -1m, stop: now()) '
. '|> filter(fn: (r) => r._measurement == "' . $measurement . '")';
$count = 0;
$parser = $this->queryApi->queryStream($query);
foreach ($parser->each() as $record) {
$this->assertNotNull($record);
$this->assertEquals($measurement, $record->getMeasurement());
$this->assertEquals('europe', $record->values['location']);
$this->assertEquals($count, $record->getValue());
$this->assertEquals('level', $record->getField());
$count++;
}
$this->assertEquals(10, $count);
}
public function testQueryStreamBreak()
{
$measurement = 'h2o_query_stream_break' . $this->now->format('Y-m-d-H-i-s');
$this->write(20, $measurement);
$query = 'from(bucket: "my-bucket") |> range(start: -1m, stop: now()) '
. '|> filter(fn: (r) => r._measurement == "' . $measurement . '")';
$count = 0;
$parser = $this->queryApi->queryStream($query);
$records = [];
$this->assertFalse($parser->closed);
foreach ($parser->each() as $record) {
if ($count >= 5) {
break;
}
$records[] = $record;
$count++;
}
$this->assertEquals(5, count($records));
$this->assertTrue($parser->closed);
}
public function testQueryEmptyData()
{
$result = $this->queryApi->queryStream(null);
$this->assertNull($result);
}
private function write($values, $measurement)
{
for ($ii = 0; $ii < $values; $ii++) {
$this->writeApi->write(
Point::measurement($measurement)
->addTag('location', 'europe')
->addField('level', $ii)
->time($this->now->getTimestamp() - $values + $ii, WritePrecision::S),
WritePrecision::S
);
}
}
}
@@ -0,0 +1,103 @@
<?php
namespace InfluxDB2Test;
use DateInterval;
use DateTime;
use GuzzleHttp\Psr7\Response;
use InfluxDB2\Model\Query;
require_once('BasicTest.php');
/**
* Class QueryApiTest
* @package InfluxDB2Test
*/
class QueryApiTest extends BasicTest
{
private const SUCCESS_DATA =
"#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,long,string,string,string,string\n"
. "#group,false,false,false,false,false,false,false,false,false,true\n" . "#default,_result,,,,,,,,,\n"
. ",result,table,_start,_stop,_time,_value,_field,_measurement,host,region\n"
. ",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,10,free,mem,A,west\n"
. ",,0,1970-01-01T00:00:10Z,1970-01-01T00:00:20Z,1970-01-01T00:00:10Z,20,free,mem,B,west\n"
. ",,0,1970-01-01T00:00:20Z,1970-01-01T00:00:30Z,1970-01-01T00:00:20Z,11,free,mem,A,west\n"
. ",,0,1970-01-01T00:00:20Z,1970-01-01T00:00:30Z,1970-01-01T00:00:20Z,22,free,mem,B,west";
public function testQueryRaw()
{
$this->mockHandler->append(new Response(204, [], QueryApiTest::SUCCESS_DATA));
$result = $this->queryApi->queryRaw(
'from(bucket:"my-bucket") |> range(start: 1970-01-01T00:00:00.000000001Z) |> last()'
);
$this->assertEquals(QueryApiTest::SUCCESS_DATA, $result);
}
public function testQuery()
{
$this->mockHandler->append(new Response(204, [], QueryApiTest::SUCCESS_DATA));
$bucket = 'my-bucket';
$result = $this->queryApi->query('from(bucket:"' . $bucket
. '") |> range(start: 1970-01-01T00:00:00.000000001Z) |> last()');
$this->assertEquals(1, count($result));
$this->assertEquals(4, count($result[0]->records));
$record = $result[0]->records[0];
$this->assertEquals('1970-01-01T00:00:10Z', $record->getTime());
$this->assertEquals('mem', $record->getMeasurement());
$this->assertEquals(10, $record->getValue());
$this->assertEquals('free', $record->getField());
}
public function testQueryParameterized()
{
$this->mockHandler->append(new Response(204, [], QueryApiTest::SUCCESS_DATA));
$q = new Query();
$q->setQuery('from(bucket: params.bucketParam) |> range(start: time(v: params.startParam)) |> last()');
$today = new DateTime("2021-12-15T11:33:28+00:00");
$yesterday = $today->sub(new DateInterval("P1D"));
$q->setParams([
"bucketParam" => "my-bucket",
"startParam" => $yesterday
]);
$result = $this->queryApi->query($q);
$contents = $this->mockHandler->getLastRequest()->getBody()->getContents();
$json = json_decode($contents, true);
$this->assertEquals("my-bucket", $json["params"]["bucketParam"]);
$this->assertEquals('2021-12-14T11:33:28+00:00', $json["params"]["startParam"]);
$this->assertCount(1, $result);
$this->assertCount(4, $result[0]->records);
$record = $result[0]->records[0];
$this->assertEquals('1970-01-01T00:00:10Z', $record->getTime());
$this->assertEquals('mem', $record->getMeasurement());
$this->assertEquals(10, $record->getValue());
$this->assertEquals('free', $record->getField());
}
public function testQueryRawEmptyData()
{
$result = $this->queryApi->queryRaw('');
$this->assertNull($result);
}
public function testQueryEmptyData()
{
$result = $this->queryApi->query(null);
$this->assertNull($result);
}
}
@@ -0,0 +1,349 @@
<?php
namespace InfluxDB2Test;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use InfluxDB2\ApiException;
use InfluxDB2\Point;
require_once('BasicTest.php');
/**
* Class WriteApiBatchingTest
* @package InfluxDB2Test
*/
class WriteApiBatchingTest extends BasicTest
{
protected function getWriteOptions(): ?array
{
return array('writeType' => 2, 'batchSize' => 2);
}
public function testBatchSize()
{
$this->mockHandler->append(
new Response(204),
new Response(204)
);
$this->writeApi->write('h2o_feet,location=coyote_creek level\\ water_level=1.0 1');
$this->writeApi->write('h2o_feet,location=coyote_creek level\\ water_level=2.0 2');
$this->writeApi->write('h2o_feet,location=coyote_creek level\\ water_level=3.0 3');
$this->writeApi->write('h2o_feet,location=coyote_creek level\\ water_level=4.0 4');
$this->assertCount(2, $this->requests);
$result1 = "h2o_feet,location=coyote_creek level\\ water_level=1.0 1\n"
. "h2o_feet,location=coyote_creek level\\ water_level=2.0 2";
$result2 = "h2o_feet,location=coyote_creek level\\ water_level=3.0 3\n"
. "h2o_feet,location=coyote_creek level\\ water_level=4.0 4";
$this->assertEquals($result1, $this->requests[0]['request']->getBody());
$this->assertEquals($result2, $this->requests[1]['request']->getBody());
}
public function testBatchSizeGroupBy()
{
$this->mockHandler->append(
new Response(204),
new Response(204),
new Response(204),
new Response(204),
new Response(204)
);
$bucket = 'my-bucket';
$bucket2 = 'my-bucket2';
$this->writeApi->write(
'h2o_feet,location=coyote_creek level\\ water_level=1.0 1',
'ns',
$bucket,
'my-org'
);
$this->writeApi->write(
'h2o_feet,location=coyote_creek level\\ water_level=2.0 2',
's',
$bucket,
'my-org'
);
$this->writeApi->write(
'h2o_feet,location=coyote_creek level\\ water_level=3.0 3',
'ns',
$bucket,
'my-org-a'
);
$this->writeApi->write(
'h2o_feet,location=coyote_creek level\\ water_level=4.0 4',
'ns',
$bucket,
'my-org-a'
);
$this->writeApi->write(
'h2o_feet,location=coyote_creek level\\ water_level=5.0 5',
'ns',
$bucket2,
'my-org-a'
);
$this->writeApi->write(
'h2o_feet,location=coyote_creek level\\ water_level=6.0 6',
'ns',
$bucket,
'my-org-a'
);
$this->assertCount(5, $this->requests);
$request = $this->requests[0]['request'];
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals('h2o_feet,location=coyote_creek level\\ water_level=1.0 1', $request->getBody());
$request = $this->requests[1]['request'];
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=s',
strval($request->getUri())
);
$this->assertEquals('h2o_feet,location=coyote_creek level\\ water_level=2.0 2', $request->getBody());
$request = $this->requests[2]['request'];
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org-a&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals("h2o_feet,location=coyote_creek level\\ water_level=3.0 3\n"
. 'h2o_feet,location=coyote_creek level\\ water_level=4.0 4', $request->getBody());
$request = $this->requests[3]['request'];
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org-a&bucket=my-bucket2&precision=ns',
strval($request->getUri())
);
$this->assertEquals('h2o_feet,location=coyote_creek level\\ water_level=5.0 5', $request->getBody());
$request = $this->requests[4]['request'];
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org-a&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals('h2o_feet,location=coyote_creek level\\ water_level=6.0 6', $request->getBody());
}
public function testFlushAllByCloseClient()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->writeOptions->batchSize = 10;
$this->writeApi->write('h2o_feet,location=coyote_creek level\\ water_level=1.0 1');
$this->writeApi->write('h2o_feet,location=coyote_creek level\\ water_level=2.0 2');
$this->writeApi->write('h2o_feet,location=coyote_creek level\\ water_level=3.0 3');
$this->assertNull($this->mockHandler->getLastRequest());
$this->client->close();
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals("h2o_feet,location=coyote_creek level\\ water_level=1.0 1\n"
. "h2o_feet,location=coyote_creek level\\ water_level=2.0 2\n"
. 'h2o_feet,location=coyote_creek level\\ water_level=3.0 3', $request->getBody());
}
public function testRetryIntervalByConfig()
{
$errorBody = '{"code":"temporarily unavailable","message":"Token is temporarily over quota.'
. 'The Retry-After header describes when to try the write again."}';
$this->mockHandler->append(new Response(
429,
['X-Platform-Error-Code' => 'temporarily unavailable'],
$errorBody
), new Response(204));
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=1.0 1');
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=2.0 2');
$this->assertCount(2, $this->requests);
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals("h2o_feet,location=coyote_creek water_level=1.0 1\n"
. "h2o_feet,location=coyote_creek water_level=2.0 2", $request->getBody()->getContents());
}
public function testRetryIntervalByHeader()
{
$errorBody = '{"code":"temporarily unavailable","message":"Token is temporarily over quota.'
. 'The Retry-After header describes when to try the write again."}';
$this->mockHandler->append(new Response(
429,
['X-Platform-Error-Code' => 'temporarily unavailable',
'Retry-After' => '3'],
$errorBody
), new Response(204));
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=1.0 1');
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=2.0 2');
$this->assertCount(2, $this->requests);
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals("h2o_feet,location=coyote_creek water_level=1.0 1\n"
. "h2o_feet,location=coyote_creek water_level=2.0 2", $request->getBody()->getContents());
}
public function testRetryIntervalMaxRetries()
{
$errorBody = '{"code":"temporarily unavailable","message":"Token is temporarily over quota.'
. 'The Retry-After header describes when to try the write again."}';
$this->writeApi->writeOptions->maxRetries = 2;
$this->mockHandler->append(
new Response(429, ['X-Platform-Error-Code' => 'temporarily unavailable'], $errorBody),
new Response(429, ['X-Platform-Error-Code' => 'temporarily unavailable'], $errorBody),
new Response(429, ['X-Platform-Error-Code' => 'temporarily unavailable'], $errorBody)
);
$this->expectException(ApiException::class);
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=1.0 1');
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=2.0 2');
$this->assertCount(3, $this->requests);
}
public function testRetryCount()
{
$this->mockHandler->append(
// regular call
new Response(429),
// retry
new Response(429),
// retry
new Response(429),
// retry
new Response(429),
// not called
new Response(429)
);
$this->writeApi->writeOptions->batchSize = 1;
$this->writeApi->writeOptions->retryInterval = 1000;
$this->writeApi->writeOptions->maxRetries = 3;
$this->writeApi->writeOptions->maxRetryDelay = 15000;
$this->writeApi->writeOptions->exponentialBase = 2;
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2);
try {
$this->writeApi->write($point);
} catch (ApiException $e) {
$this->assertEquals(429, $e->getCode());
}
$this->assertCount(4, $this->requests);
$count = $this->mockHandler->count();
$this->assertEquals(1, $count);
}
public function testRetryConnectionError()
{
$errorMessage = 'Failed to connect to localhost port 8086';
$this->writeApi->writeOptions->maxRetries = 2;
$this->writeApi->writeOptions->retryInterval = 1000;
$this->writeApi->writeOptions->maxRetryDelay = 15000;
$this->writeApi->writeOptions->exponentialBase = 2;
$this->mockHandler->append(
new ConnectException($errorMessage, new Request('POST', '')),
new ConnectException($errorMessage, new Request('POST', '')),
new ConnectException($errorMessage, new Request('POST', ''))
);
$this->expectException(ApiException::class);
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=1.0 1');
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=2.0 2');
$this->assertCount(3, $this->requests);
}
public function testJitterInterval()
{
$this->mockHandler->append(
new Response(204),
new Response(204)
);
$this->writeApi->writeOptions->jitterInterval = 2000;
$start = microtime(true);
$this->writeApi->write('h2o_feet,location=coyote_creek level\\ water_level=1.0 1');
$this->writeApi->write('h2o_feet,location=coyote_creek level\\ water_level=2.0 2');
$time = microtime(true) - $start;
$this->assertTrue($time > 0 && $time <= 2);
$this->assertCount(1, $this->requests);
$result1 = "h2o_feet,location=coyote_creek level\\ water_level=1.0 1\n"
. "h2o_feet,location=coyote_creek level\\ water_level=2.0 2";
$this->assertEquals($result1, $this->requests[0]['request']->getBody());
}
public function testRetryContainsMessage()
{
// create log file
fopen("log_test.txt", "w");
$this->tearDown();
$this->setUp("http://localhost:8086", "log_test.txt");
$this->mockHandler->append(
new Response(
429,
['X-Platform-Error-Code' => 'temporarily unavailable',
'Retry-After' => '3'],
'org 04014de4ed590000 has exceeded limited_write plan limit'
),
new Response(204)
);
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=1.0 1');
$this->writeApi->write('h2o_feet,location=coyote_creek water_level=2.0 2');
$this->assertCount(2, $this->requests);
$message = file_get_contents("log_test.txt");
$this->assertStringContainsString("The retryable error occurred during writing of data. Reason: 'org 04014de4ed590000 has exceeded limited_write plan limit'. Retry in: 3s.", $message);
}
}
@@ -0,0 +1,145 @@
<?php
namespace InfluxDB2Test;
use InfluxDB2\Client;
use InfluxDB2\Model\WritePrecision;
use InfluxDB2\Point;
use InfluxDB2\WriteApi;
use InfluxDB2\WriteType;
use PHPUnit\Framework\TestCase;
/**
* @group integration
*/
class WriteApiIntegrationTest extends TestCase
{
/** @var Client */
private $client;
/** @var WriteApi */
private $writeApi;
/**
* @before
*/
public function setUp(): void
{
$this->client = new Client([
"url" => "http://localhost:8086",
"token" => "my-token",
"bucket" => "my-bucket",
"precision" => WritePrecision::NS,
"org" => "my-org",
"debug" => false
]);
$this->writeApi = $this->client->createWriteApi();
}
public function testExistsWriteApi()
{
$this->assertNotNull($this->writeApi);
}
public function testWriteApiWriteRaw()
{
$payload = 'h2o_feet,location=coyote_creek water_level=2.0 2';
$response = $this->writeApi->writeRaw($payload);
self::assertNull($response);
}
public function testWriteArray()
{
$data = [
'name' => "h2o",
'tags' => [
'host' => 'aws', 'region' => 'us'
],
'fields' => [
'level' => 5, 'saturation' => 99
],
'time' => 123
];
$response = $this->writeApi->write($data, WritePrecision::S, "my-bucket", "my-org");
self::assertNull($response);
}
public function testBatchingWrite()
{
$writeApi = $this->client->createWriteApi(
["writeType"=>WriteType::BATCHING, 'batchSize'=>3]
);
$data = ['name' => 'cpu',
'tags' => ['host' => 'server_nl', 'region' => 'us'],
'fields' => ['internal' => 5, 'external' => 6],
'time' => microtime(true)];
$writeApi->write($data, WritePrecision::MS);
$p1 = ['name' => "h2o", 'tags' => ['host' => 'aws', 'region' => 'us'], 'fields' => ['level' => 1, 'saturation' => 99], 'time' => 1];
$p2 = ['name' => "h2o", 'tags' => ['host' => 'aws', 'region' => 'us'], 'fields' => ['level' => 2, 'saturation' => 98], 'time' => 2];
$p3 = ['name' => "h2o", 'tags' => ['host' => 'aws', 'region' => 'us'], 'fields' => ['level' => 3, 'saturation' => 97], 'time' => 3];
$p4 = ['name' => "h2o", 'tags' => ['host' => 'aws', 'region' => 'us'], 'fields' => ['level' => 4, 'saturation' => 96], 'time' => 4];
$p5 = ['name' => "h2o", 'tags' => ['host' => 'aws', 'region' => 'us'], 'fields' => ['level' => 5, 'saturation' => 95], 'time' => 5];
$p6 = ['name' => "h2o", 'tags' => ['host' => 'aws', 'region' => 'us'], 'fields' => ['level' => 6, 'saturation' => 95], 'time' => 6];
$writeApi->write($p1);
$writeApi->write($p2);
$writeApi->write($p3);
$writeApi->write($p4);
$writeApi->write($p5);
$writeApi->write($p6);
$this->assertNotNull($writeApi);
$this->client->close();
}
public function testWriteArrayOfPoint()
{
$point1 = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2)
->time(123);
$point2 = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 3)
->time(124);
$data = array($point1, $point2);
$response = $this->writeApi->write($data, WritePrecision::S, "my-bucket", "my-org");
self::assertNull($response);
}
public function testWriteArrayOfArray()
{
$data1 = [
'name' => "h2o",
'tags' => [
'host' => 'aws', 'region' => 'us'
],
'fields' => [
'level' => 5, 'saturation' => 99
],
'time' => 123
];
$data2 = [
'name' => "h2o",
'tags' => [
'host' => 'aws', 'region' => 'us'
],
'fields' => [
'level' => 6, 'saturation' => 98
],
'time' => 124
];
$data = array($data1, $data2);
$response = $this->writeApi->write($data, WritePrecision::S, "my-bucket", "my-org");
self::assertNull($response);
}
}
@@ -0,0 +1,384 @@
<?php
namespace InfluxDB2Test;
use Exception;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Psr7\Response;
use InfluxDB2\ApiException;
use InfluxDB2\Client;
use InfluxDB2\Model\WritePrecision;
use InfluxDB2\Point;
use InfluxDB2\WriteRetry;
require_once('BasicTest.php');
/**
* Class WriteApiTest
* @package InfluxDB2Test
*/
class WriteApiTest extends BasicTest
{
private const ID_TAG = "132-987-655";
private const CUSTOMER_TAG = "California Miner";
public function setUp($url = "http://localhost:8086", $logFile = "php://output"): void
{
parent::setUp($url, $logFile);
putenv("data_center=LA");
}
public function testWriteLineProtocol()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->write('h2o,location=west value=33i 15');
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals('h2o,location=west value=33i 15', $request->getBody());
}
public function testWritePoint()
{
$this->mockHandler->append(new Response(204));
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2);
$this->writeApi->write($point);
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals('h2o,location=europe level=2i', $request->getBody());
}
public function testWriteArray()
{
$this->mockHandler->append(new Response(204));
$array = array('name' => 'h2o',
'tags' => array('host' => 'aws', 'region' => 'us'),
'fields' => array('level' => 5, 'saturation' => '99%'),
'time' => 123);
$this->writeApi->write($array);
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals('h2o,host=aws,region=us level=5i,saturation="99%" 123', $request->getBody());
}
public function testWriteCollection()
{
$this->mockHandler->append(new Response(204));
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2);
$array = array('name' => 'h2o',
'tags' => array('host' => 'aws', 'region' => 'us'),
'fields' => array('level' => 5, 'saturation' => '99%'),
'time' => 123);
$this->writeApi->write(array('h2o,location=west value=33i 15', null, $point, $array));
$request = $this->mockHandler->getLastRequest();
$expected = "h2o,location=west value=33i 15\n"
. "h2o,location=europe level=2i\n"
. "h2o,host=aws,region=us level=5i,saturation=\"99%\" 123";
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals($expected, strval($request->getBody()));
}
public function testAuthorizationHeader()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->write('h2o,location=west value=33i 15');
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals('Token my-token', implode(' ', $request->getHeaders()['Authorization']));
}
public function testWithoutData()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->write('');
$request = $this->mockHandler->getLastRequest();
$this->assertNull($request);
}
public function testInfluxException()
{
$errorBody = '{"code":"invalid","message":"unable to parse \'h2o_feet, location=coyote_creek water_level=1.0 1\': missing tag key"}';
$this->mockHandler->append(new Response(400, array('X-Platform-Error-Code' => 'invalid'), $errorBody));
try {
$this->writeApi->write('h2o,location=west value=33i 15');
$this->fail();
} catch (ApiException $e) {
$this->assertEquals(400, $e->getCode());
$this->assertEquals('invalid', implode($e->getResponseHeaders()['X-Platform-Error-Code']));
$this->assertEquals($errorBody, strval($e->getResponseBody()));
} catch (Exception $e) {
$this->fail();
}
}
public function testWritePointWithDefaultTags()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->pointSettings->addDefaultTag('id', WriteApiTest::ID_TAG);
$this->writeApi->pointSettings->addDefaultTag('customer', WriteApiTest::CUSTOMER_TAG);
$this->writeApi->pointSettings->addDefaultTag('data_center', '${env.data_center}');
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2);
$this->writeApi->write($point);
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals(
'h2o,customer=California\ Miner,data_center=LA,id=132-987-655,location=europe level=2i',
strval($request->getBody())
);
}
public function testWriteArrayWithDefaultTags()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->pointSettings->addDefaultTag('id', WriteApiTest::ID_TAG);
$this->writeApi->pointSettings->addDefaultTag('customer', WriteApiTest::CUSTOMER_TAG);
$this->writeApi->pointSettings->addDefaultTag('data_center', '${env.data_center}');
$array = array('name' => 'h2o',
'tags' => array('host' => 'aws', 'region' => 'us'),
'fields' => array('level' => 5, 'saturation' => '99%'),
'time' => 123);
$this->writeApi->write($array);
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals(
'h2o,customer=California\ Miner,data_center=LA,host=aws,id=132-987-655,region=us level=5i,saturation="99%" 123',
strval($request->getBody())
);
}
public function testWriteCollectionWithDefaultTags()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->pointSettings->addDefaultTag('id', WriteApiTest::ID_TAG);
$this->writeApi->pointSettings->addDefaultTag('customer', WriteApiTest::CUSTOMER_TAG);
$this->writeApi->pointSettings->addDefaultTag('data_center', '${env.data_center}');
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2);
$array = array('name' => 'h2o',
'tags' => array('host' => 'aws', 'region' => 'us'),
'fields' => array('level' => 5, 'saturation' => '99%'),
'time' => 123);
$this->writeApi->write(array('h2o,location=west value=33i 15', null, $point, $array));
$request = $this->mockHandler->getLastRequest();
$expected = "h2o,location=west value=33i 15\n"
. "h2o,customer=California\ Miner,data_center=LA,id=132-987-655,location=europe level=2i\n"
. "h2o,customer=California\ Miner,data_center=LA,host=aws,id=132-987-655,region=us level=5i,saturation=\"99%\" 123";
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals($expected, strval($request->getBody()));
}
public function testWriteArrayWithoutTagsWithDefaultTags()
{
$this->mockHandler->append(new Response(204));
$this->writeApi->pointSettings->addDefaultTag('id', WriteApiTest::ID_TAG);
$this->writeApi->pointSettings->addDefaultTag('customer', WriteApiTest::CUSTOMER_TAG);
$this->writeApi->pointSettings->addDefaultTag('data_center', '${env.data_center}');
$array = array('name' => 'h2o',
'fields' => array('level' => 5, 'saturation' => '99%'),
'time' => 123);
$this->writeApi->write($array);
$request = $this->mockHandler->getLastRequest();
$this->assertEquals(
'http://localhost:8086/api/v2/write?org=my-org&bucket=my-bucket&precision=ns',
strval($request->getUri())
);
$this->assertEquals(
'h2o,customer=California\ Miner,data_center=LA,id=132-987-655 level=5i,saturation="99%" 123',
strval($request->getBody())
);
}
public function testRetryCount()
{
$this->mockHandler->append(
// regular call
new Response(429),
// retry
new Response(429),
// retry
new Response(429),
// retry
new Response(429),
// not called
new Response(429)
);
$this->writeApi->writeOptions->retryInterval = 1000;
$this->writeApi->writeOptions->maxRetries = 3;
$this->writeApi->writeOptions->maxRetryDelay = 15000;
$this->writeApi->writeOptions->exponentialBase = 2;
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2);
$this->expectExceptionCode(429);
$this->expectException(ApiException::class);
$this->writeApi->write($point);
$this->assertCount(4, $this->requests);
$this->assertCount(1, $this->mockHandler);
}
public function testRetryMaxTime()
{
$this->mockHandler->append(
// regular call
new Response(429),
// retry
new Response(429),
// retry
new Response(200)
);
$this->writeApi->writeOptions->retryInterval = 1000;
$this->writeApi->writeOptions->maxRetries = 3;
$this->writeApi->writeOptions->maxRetryDelay = 15000;
$this->writeApi->writeOptions->exponentialBase = 2;
$this->writeApi->writeOptions->maxRetryTime = 300;
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2);
$this->expectException(ApiException::class);
$this->expectExceptionCode(429);
$this->writeApi->write($point);
$this->assertCount(2, $this->requests);
$this->assertCount(1, $this->mockHandler);
}
public function testRetryBackoffTime()
{
$retry = new WriteRetry();
$backoff = $retry->getBackoffTime(1);
$this->assertGreaterThanOrEqual(5000, $backoff);
$this->assertLessThanOrEqual(10000, $backoff);
$backoff = $retry->getBackoffTime(2);
$this->assertGreaterThanOrEqual(10000, $backoff);
$this->assertLessThanOrEqual(20000, $backoff);
$backoff = $retry->getBackoffTime(3);
$this->assertGreaterThanOrEqual(20000, $backoff);
$this->assertLessThanOrEqual(40000, $backoff);
$backoff = $retry->getBackoffTime(4);
$this->assertGreaterThanOrEqual(40000, $backoff);
$this->assertLessThanOrEqual(80000, $backoff);
$backoff = $retry->getBackoffTime(5);
$this->assertGreaterThanOrEqual(80000, $backoff);
$this->assertLessThanOrEqual(125000, $backoff);
$backoff = $retry->getBackoffTime(6);
$this->assertGreaterThanOrEqual(80000, $backoff);
$this->assertLessThanOrEqual(125000, $backoff);
}
public function testConnectExceptionRetry()
{
$client = new Client([
"url" => "http://nonexistenthost:8086/",
"token" => "my-token",
"bucket" => "my-bucket",
"precision" => WritePrecision::NS,
"org" => "my-org",
"logFile" => "php://output"
]);
$writeApi = $client->createWriteApi(["retryInterval" => 100]);
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2);
$this->expectException(ApiException::class);
$this->expectExceptionMessage("Could not resolve host: nonexistenthost");
try {
$writeApi->write($point);
} catch (ApiException $e) {
$this->assertEquals(ConnectException::class, get_class($e->getPrevious()));
throw $e;
}
}
}
@@ -0,0 +1,111 @@
<?php
namespace InfluxDB2Test;
use InfluxDB2\Client;
use InfluxDB2\Model\WritePrecision;
use InfluxDB2\Point;
use InfluxDB2\UdpWriter;
use PHPUnit\Framework\TestCase;
/**
* Class WriteUdpTest
* @package InfluxDB2Test
*/
class WriteUdpTest extends TestCase
{
protected $baseConfig = [
"url" => "http://localhost:8086",
"token" => "my-token",
"bucket" => "my-bucket",
"precision" => WritePrecision::NS,
"org" => "my-org",
"logFile" => "php://output",
];
protected function getWriterMock()
{
$method = new \ReflectionMethod(UdpWriter::class, 'writeSocket');
$method->setAccessible(true);
return $this->getMockBuilder(UdpWriter::class)
->setMethods(['writeSocket'])
->setConstructorArgs([$this->baseConfig + ['udpPort' => 1000]])
->getMock();
}
public function testRequireOptions()
{
$client = new Client($this->baseConfig);
$this->expectException(\Exception::class);
$client->createUdpWriter();
}
public function testValidOptions()
{
$this->expectNotToPerformAssertions();
$client = new Client($this->baseConfig + ['udpPort' => 1000]);
$client->createUdpWriter();
}
public function testSocketError()
{
$writer = $this->getWriterMock();
$writer->method('writeSocket')->willReturn(false);
$this->expectException(\Exception::class);
$writer->write('h2o,location=west value=33i 15');
}
public function testLineProtocol()
{
$writer = $this->getWriterMock();
$buffer = '';
$writer->method('writeSocket')->willReturnCallback(function ($data) use (&$buffer) {
$buffer = $data;
});
$writer->write('h2o,location=west value=33i 15');
$this->assertEquals('h2o,location=west value=33i 15', $buffer);
}
public function testWriteArray()
{
$array = [
'name' => 'h2o',
'tags' => ['host' => 'aws', 'region' => 'us'],
'fields' => ['level' => 5, 'saturation' => '99%'],
'time' => 123
];
$writer = $this->getWriterMock();
$buffer = '';
$writer->method('writeSocket')->willReturnCallback(function ($data) use (&$buffer) {
$buffer = $data;
});
$writer->write($array);
$this->assertEquals('h2o,host=aws,region=us level=5i,saturation="99%" 123', $buffer);
}
public function testWriteCollection()
{
$point = Point::measurement('h2o')
->addTag('location', 'europe')
->addField('level', 2);
$array = [
'name' => 'h2o',
'tags' => ['host' => 'aws', 'region' => 'us'],
'fields' => ['level' => 5, 'saturation' => '99%'],
'time' => 123
];
$writer = $this->getWriterMock();
$buffer = '';
$writer->method('writeSocket')->willReturnCallback(function ($data) use (&$buffer) {
$buffer = $data;
});
$writer->write(['h2o,location=west value=33i 15', null, $point, $array]);
$expected = "h2o,location=west value=33i 15\n"
. "h2o,location=europe level=2i\n"
. "h2o,host=aws,region=us level=5i,saturation=\"99%\" 123";
$this->assertEquals($expected, $buffer);
}
}