1<?php 2/* 3 * LocationTest.php 4 * 5 * -Description- 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * 20 * @package LibreNMS 21 * @link http://librenms.org 22 * @copyright 2021 Tony Murray 23 * @author Tony Murray <murraytony@gmail.com> 24 */ 25 26namespace LibreNMS\Tests\Unit; 27 28use App\Models\Device; 29use App\Models\Location; 30use LibreNMS\Config; 31use LibreNMS\Interfaces\Geocoder; 32use LibreNMS\Tests\TestCase; 33use LibreNMS\Util\Dns; 34use Mockery\MockInterface; 35 36class LocationTest extends TestCase 37{ 38 public function testCanSetLocation() 39 { 40 $device = Device::factory()->make(); /** @var Device $device */ 41 $device->setLocation('Where'); 42 43 $this->assertEquals($device->location->location, 'Where'); 44 $this->assertNull($device->location->lat); 45 $this->assertNull($device->location->lng); 46 47 $device->setLocation(null); 48 $this->assertNull($device->location); 49 } 50 51 public function testCanNotSetLocation() 52 { 53 $device = Device::factory()->make(); /** @var Device $device */ 54 $location = Location::factory()->make(); 55 56 $device->override_sysLocation = true; 57 $device->setLocation($location->location); 58 $this->assertNull($device->location); 59 } 60 61 public function testCanSetEncodedLocation() 62 { 63 Config::set('geoloc.dns', false); 64 $device = Device::factory()->make(); /** @var Device $device */ 65 66 // valid coords 67 $location = Location::factory()->withCoordinates()->make(); 68 $device->setLocation("$location->location [$location->lat,$location->lng]", true); 69 $this->assertEquals("$location->location [$location->lat,$location->lng]", $device->location->location); 70 $this->assertEquals($location->location, $device->location->display()); 71 $this->assertEquals($location->lat, $device->location->lat); 72 $this->assertEquals($location->lng, $device->location->lng); 73 74 // with space 75 $location = Location::factory()->withCoordinates()->make(); 76 $device->setLocation("$location->location [$location->lat, $location->lng]", true); 77 $this->assertEquals("$location->location [$location->lat, $location->lng]", $device->location->location); 78 $this->assertEquals($location->location, $device->location->display()); 79 $this->assertEquals("$location->location [$location->lat,$location->lng]", $device->location->display(true)); 80 $this->assertEquals($location->lat, $device->location->lat); 81 $this->assertEquals($location->lng, $device->location->lng); 82 83 // invalid coords 84 $location = Location::factory()->withCoordinates()->make(['lat' => 251.5007138]); 85 $name = "$location->location [$location->lat,$location->lng]"; 86 $device->setLocation($name, true); 87 $this->assertEquals($name, $device->location->location); 88 $this->assertEquals($name, $device->location->display()); 89 $this->assertEquals($name, $device->location->display(true)); 90 $this->assertNull($device->location->lat); 91 $this->assertNull($device->location->lng); 92 } 93 94 public function testCanHandleGivenCoordinates() 95 { 96 Config::set('geoloc.dns', false); 97 $device = Device::factory()->make(); /** @var Device $device */ 98 $location = Location::factory()->withCoordinates()->make(); 99 100 $device->setLocation($location); 101 $this->assertEquals($location->location, $device->location->location); 102 $this->assertEquals($location->location, $device->location->display()); 103 $this->assertEquals("$location->location [$location->lat,$location->lng]", $device->location->display(true)); 104 $this->assertEquals($location->lat, $device->location->lat); 105 $this->assertEquals($location->lng, $device->location->lng); 106 } 107 108 public function testCanNotSetFixedCoordinates() 109 { 110 $device = Device::factory()->make(); /** @var Device $device */ 111 $locationOne = Location::factory()->withCoordinates()->make(); 112 $locationTwo = Location::factory(['location' => $locationOne->location])->withCoordinates()->make(); 113 114 $device->setLocation($locationOne); 115 $this->assertEquals($locationOne->lat, $device->location->lat); 116 $this->assertEquals($locationOne->lng, $device->location->lng); 117 118 $device->location->fixed_coordinates = true; 119 $device->setLocation($locationTwo); 120 $this->assertEquals($locationOne->lat, $device->location->lat); 121 $this->assertEquals($locationOne->lng, $device->location->lng); 122 123 $device->location->fixed_coordinates = false; 124 $device->setLocation($locationTwo); 125 $this->assertEquals($locationTwo->lat, $device->location->lat); 126 $this->assertEquals($locationTwo->lng, $device->location->lng); 127 } 128 129 public function testDnsLookup() 130 { 131 $example = 'SW1A2AA.find.me.uk'; 132 $expected = ['lat' => 51.50354111111111, 'lng' => -0.12766972222222223]; 133 134 $result = (new Dns())->getCoordinates($example); 135 136 $this->assertEquals($expected, $result); 137 } 138 139 public function testCanSetDnsCoordinate() 140 { 141 Config::set('geoloc.dns', true); 142 $device = Device::factory()->make(); /** @var Device $device */ 143 $location = Location::factory()->withCoordinates()->make(); 144 145 $this->mock(Dns::class, function (MockInterface $mock) use ($location) { 146 $mock->shouldReceive('getCoordinates')->once()->andReturn($location->only(['lat', 'lng'])); 147 }); 148 149 $device->setLocation($location->location, true); 150 $this->assertEquals($location->location, $device->location->location); 151 $this->assertEquals($location->lat, $device->location->lat); 152 $this->assertEquals($location->lng, $device->location->lng); 153 154 Config::set('geoloc.dns', false); 155 $device->setLocation('No DNS', true); 156 $this->assertEquals('No DNS', $device->location->location); 157 $this->assertNull($device->location->lat); 158 $this->assertNull($device->location->lng); 159 } 160 161 public function testCanSetByApi() 162 { 163 $device = Device::factory()->make(); /** @var Device $device */ 164 $location = Location::factory()->withCoordinates()->make(); 165 166 $this->mock(Geocoder::class, function (MockInterface $mock) use ($location) { 167 $mock->shouldReceive('getCoordinates')->once()->andReturn($location->only(['lat', 'lng'])); 168 }); 169 170 Config::set('geoloc.latlng', false); 171 $device->setLocation('No API', true); 172 $this->assertEquals('No API', $device->location->location); 173 $this->assertNull($device->location->lat); 174 $this->assertNull($device->location->lng); 175 176 Config::set('geoloc.latlng', true); 177 $device->setLocation('API', true); 178 $this->assertEquals('API', $device->location->location); 179 $this->assertEquals($location->lat, $device->location->lat); 180 $this->assertEquals($location->lng, $device->location->lng); 181 182 // preset coord = skip api 183 $device->setLocation('API', true); 184 $this->assertEquals($location->lat, $device->location->lat); 185 $this->assertEquals($location->lng, $device->location->lng); 186 } 187 188 public function testCorrectPrecedence() 189 { 190 $device = Device::factory()->make(); /** @var Device $device */ 191 $location_encoded = Location::factory()->withCoordinates()->make(); 192 $location_fixed = Location::factory()->withCoordinates()->make(); 193 $location_api = Location::factory()->withCoordinates()->make(); 194 $location_dns = Location::factory()->withCoordinates()->make(); 195 196 Config::set('geoloc.dns', true); 197 $this->mock(Dns::class, function (MockInterface $mock) use ($location_dns) { 198 $mock->shouldReceive('getCoordinates')->times(3)->andReturn( 199 $location_dns->only(['lat', 'lng']), 200 [], 201 [] 202 ); 203 }); 204 205 Config::set('geoloc.latlng', true); 206 $this->mock(Geocoder::class, function (MockInterface $mock) use ($location_api) { 207 $mock->shouldReceive('getCoordinates')->once()->andReturn($location_api->only(['lat', 'lng'])); 208 }); 209 210 // fixed first 211 $location_fixed->location = "$location_fixed [-42, 42]"; // encoded should not be used 212 $device->setLocation($location_fixed, true); 213 $this->assertEquals($location_fixed->lat, $device->location->lat); 214 $this->assertEquals($location_fixed->lng, $device->location->lng); 215 216 // then encoded 217 $device->setLocation($location_encoded->display(true), true); 218 $this->assertEquals($location_encoded->lat, $device->location->lat); 219 $this->assertEquals($location_encoded->lng, $device->location->lng); 220 221 // then dns 222 $device->setLocation($location_encoded->location, true); 223 $this->assertEquals($location_dns->lat, $device->location->lat); 224 $this->assertEquals($location_dns->lng, $device->location->lng); 225 226 // then api 227 $device->setLocation($location_encoded->location, true); 228 $this->assertEquals($location_dns->lat, $device->location->lat); 229 $this->assertEquals($location_dns->lng, $device->location->lng); 230 231 $device->location->lat = null; // won't be used if latitude is set 232 $device->setLocation($location_encoded->location, true); 233 $this->assertEquals($location_api->lat, $device->location->lat); 234 $this->assertEquals($location_api->lng, $device->location->lng); 235 } 236} 237